2 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
10 * Revision 1.3 2002/05/26 23:31:18 relnev
11 * added a few files that needed to be compiled
13 * freespace.cpp: now compiles
15 * Revision 1.2 2002/05/07 03:16:44 theoddone33
16 * The Great Newline Fix
18 * Revision 1.1.1.1 2002/05/03 03:28:09 root
22 * 201 6/16/00 3:15p Jefff
23 * sim of the year dvd version changes, a few german soty localization
26 * 200 11/03/99 11:06a Jefff
29 * 199 10/26/99 5:07p Jamest
30 * fixed jeffs dumb debug code
32 * 198 10/25/99 5:53p Jefff
33 * call control_config_common_init() on startup
35 * 197 10/14/99 10:18a Daveb
36 * Fixed incorrect CD checking problem on standalone server.
38 * 196 10/13/99 9:22a Daveb
39 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
40 * related to movies. Fixed launcher spawning from PXO screen.
42 * 195 10/06/99 11:05a Jefff
43 * new oem upsell 3 hotspot coords
45 * 194 10/06/99 10:31a Jefff
48 * 193 10/01/99 9:10a Daveb
51 * 192 9/15/99 4:57a Dave
52 * Updated ships.tbl checksum
54 * 191 9/15/99 3:58a Dave
55 * Removed framerate warning at all times.
57 * 190 9/15/99 3:16a Dave
58 * Remove mt-011.fs2 from the builtin mission list.
60 * 189 9/15/99 1:45a Dave
61 * Don't init joystick on standalone. Fixed campaign mode on standalone.
62 * Fixed no-score-report problem in TvT
64 * 188 9/14/99 6:08a Dave
65 * Updated (final) single, multi, and campaign list.
67 * 187 9/14/99 3:26a Dave
68 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
69 * respawn-too-early problem. Made a few crash points safe.
71 * 186 9/13/99 4:52p Dave
74 * 185 9/12/99 8:09p Dave
75 * Fixed problem where skip-training button would cause mission messages
76 * not to get paged out for the current mission.
78 * 184 9/10/99 11:53a Dave
79 * Shutdown graphics before sound to eliminate apparent lockups when
80 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
82 * 183 9/09/99 11:40p Dave
83 * Handle an Assert() in beam code. Added supernova sounds. Play the right
84 * 2 end movies properly, based upon what the player did in the mission.
86 * 182 9/08/99 10:29p Dave
87 * Make beam sound pausing and unpausing much safer.
89 * 181 9/08/99 10:01p Dave
90 * Make sure game won't run in a drive's root directory. Make sure
91 * standalone routes suqad war messages properly to the host.
93 * 180 9/08/99 3:22p Dave
94 * Updated builtin mission list.
96 * 179 9/08/99 12:01p Jefff
97 * fixed Game_builtin_mission_list typo on Training-2.fs2
99 * 178 9/08/99 9:48a Andsager
100 * Add force feedback for engine wash.
102 * 177 9/07/99 4:01p Dave
103 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
104 * does everything properly (setting up address when binding). Remove
105 * black rectangle background from UI_INPUTBOX.
107 * 176 9/13/99 2:40a Dave
108 * Comment in full 80 minute CD check for RELEASE_REAL builds.
110 * 175 9/06/99 6:38p Dave
111 * Improved CD detection code.
113 * 174 9/06/99 1:30a Dave
114 * Intermediate checkin. Started on enforcing CD-in-drive to play the
117 * 173 9/06/99 1:16a Dave
118 * Make sure the user sees the intro movie.
120 * 172 9/04/99 8:00p Dave
121 * Fixed up 1024 and 32 bit movie support.
123 * 171 9/03/99 1:32a Dave
124 * CD checking by act. Added support to play 2 cutscenes in a row
125 * seamlessly. Fixed super low level cfile bug related to files in the
126 * root directory of a CD. Added cheat code to set campaign mission # in
129 * 170 9/01/99 10:49p Dave
130 * Added nice SquadWar checkbox to the client join wait screen.
132 * 169 9/01/99 10:14a Dave
135 * 168 8/29/99 4:51p Dave
136 * Fixed damaged checkin.
138 * 167 8/29/99 4:18p Andsager
139 * New "burst" limit for friendly damage. Also credit more damage done
140 * against large friendly ships.
142 * 166 8/27/99 6:38p Alanl
143 * crush the blasted repeating messages bug
145 * 164 8/26/99 9:09p Dave
146 * Force framerate check in everything but a RELEASE_REAL build.
148 * 163 8/26/99 9:45a Dave
149 * First pass at easter eggs and cheats.
151 * 162 8/24/99 8:55p Dave
152 * Make sure nondimming pixels work properly in tech menu.
154 * 161 8/24/99 1:49a Dave
155 * Fixed client-side afterburner stuttering. Added checkbox for no version
156 * checking on PXO join. Made button info passing more friendly between
159 * 160 8/22/99 5:53p Dave
160 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
161 * instead of ship designations for multiplayer players.
163 * 159 8/22/99 1:19p Dave
164 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
165 * which d3d cards are detected.
167 * 158 8/20/99 2:09p Dave
168 * PXO banner cycling.
170 * 157 8/19/99 10:59a Dave
171 * Packet loss detection.
173 * 156 8/19/99 10:12a Alanl
174 * preload mission-specific messages on machines greater than 48MB
176 * 155 8/16/99 4:04p Dave
177 * Big honking checkin.
179 * 154 8/11/99 5:54p Dave
180 * Fixed collision problem. Fixed standalone ghost problem.
182 * 153 8/10/99 7:59p Jefff
185 * 152 8/10/99 6:54p Dave
186 * Mad optimizations. Added paging to the nebula effect.
188 * 151 8/10/99 3:44p Jefff
189 * loads Intelligence information on startup
191 * 150 8/09/99 3:47p Dave
192 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
193 * non-nebula missions.
195 * 149 8/09/99 2:21p Andsager
196 * Fix patching from multiplayer direct to launcher update tab.
198 * 148 8/09/99 10:36a Dave
199 * Version info for game.
201 * 147 8/06/99 9:46p Dave
202 * Hopefully final changes for the demo.
204 * 146 8/06/99 3:34p Andsager
205 * Make title version info "(D)" -> "D" show up nicely
207 * 145 8/06/99 2:59p Adamp
208 * Fixed NT launcher/update problem.
210 * 144 8/06/99 1:52p Dave
211 * Bumped up MAX_BITMAPS for the demo.
213 * 143 8/06/99 12:17p Andsager
214 * Demo: down to just 1 demo dog
216 * 142 8/05/99 9:39p Dave
217 * Yet another new checksum.
219 * 141 8/05/99 6:19p Dave
220 * New demo checksums.
222 * 140 8/05/99 5:31p Andsager
223 * Up demo version 1.01
225 * 139 8/05/99 4:22p Andsager
226 * No time limit on upsell screens. Reverse order of display of upsell
229 * 138 8/05/99 4:17p Dave
230 * Tweaks to client interpolation.
232 * 137 8/05/99 3:52p Danw
234 * 136 8/05/99 3:01p Danw
236 * 135 8/05/99 2:43a Anoop
237 * removed duplicate definition.
239 * 134 8/05/99 2:13a Dave
242 * 133 8/05/99 2:05a Dave
245 * 132 8/05/99 1:22a Andsager
248 * 131 8/04/99 9:51p Andsager
249 * Add title screen to demo
251 * 130 8/04/99 6:47p Jefff
252 * fixed link error resulting from #ifdefs
254 * 129 8/04/99 6:26p Dave
255 * Updated ship tbl checksum.
257 * 128 8/04/99 5:40p Andsager
258 * Add multiple demo dogs
260 * 127 8/04/99 5:36p Andsager
261 * Show upsell screens at end of demo campaign before returning to main
264 * 126 8/04/99 11:42a Danw
265 * tone down EAX reverb
267 * 125 8/04/99 11:23a Dave
268 * Updated demo checksums.
270 * 124 8/03/99 11:02p Dave
271 * Maybe fixed sync problems in multiplayer.
273 * 123 8/03/99 6:21p Jefff
276 * 122 8/03/99 3:44p Andsager
277 * Launch laucher if trying to run FS without first having configured
280 * 121 8/03/99 12:45p Dave
283 * 120 8/02/99 9:13p Dave
286 * 119 7/30/99 10:31p Dave
287 * Added comm menu to the configurable hud files.
289 * 118 7/30/99 5:17p Andsager
290 * first fs2demo checksums
292 * 117 7/29/99 3:09p Anoop
294 * 116 7/29/99 12:05a Dave
295 * Nebula speed optimizations.
297 * 115 7/27/99 8:59a Andsager
298 * Make major, minor version consistent for all builds. Only show major
299 * and minor for launcher update window.
301 * 114 7/26/99 5:50p Dave
302 * Revised ingame join. Better? We'll see....
304 * 113 7/26/99 5:27p Andsager
305 * Add training mission as builtin to demo build
307 * 112 7/24/99 1:54p Dave
308 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
311 * 111 7/22/99 4:00p Dave
312 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
314 * 110 7/21/99 8:10p Dave
315 * First run of supernova effect.
317 * 109 7/20/99 1:49p Dave
318 * Peter Drake build. Fixed some release build warnings.
320 * 108 7/19/99 2:26p Andsager
321 * set demo multiplayer missions
323 * 107 7/18/99 5:19p Dave
324 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
326 * 106 7/16/99 1:50p Dave
327 * 8 bit aabitmaps. yay.
329 * 105 7/15/99 3:07p Dave
330 * 32 bit detection support. Mouse coord commandline.
332 * 104 7/15/99 2:13p Dave
333 * Added 32 bit detection.
335 * 103 7/15/99 9:20a Andsager
336 * FS2_DEMO initial checkin
338 * 102 7/14/99 11:02a Dave
339 * Skill level default back to easy. Blech.
341 * 101 7/09/99 5:54p Dave
342 * Seperated cruiser types into individual types. Added tons of new
343 * briefing icons. Campaign screen.
345 * 100 7/08/99 4:43p Andsager
346 * New check for sparky_hi and print if not found.
348 * 99 7/08/99 10:53a Dave
349 * New multiplayer interpolation scheme. Not 100% done yet, but still
350 * better than the old way.
352 * 98 7/06/99 4:24p Dave
353 * Mid-level checkin. Starting on some potentially cool multiplayer
356 * 97 7/06/99 3:35p Andsager
357 * Allow movie to play before red alert mission.
359 * 96 7/03/99 5:50p Dave
360 * Make rotated bitmaps draw properly in padlock views.
362 * 95 7/02/99 9:55p Dave
363 * Player engine wash sound.
365 * 94 7/02/99 4:30p Dave
366 * Much more sophisticated lightning support.
368 * 93 6/29/99 7:52p Dave
369 * Put in exception handling in FS2.
371 * 92 6/22/99 9:37p Dave
372 * Put in pof spewing.
374 * 91 6/16/99 4:06p Dave
375 * New pilot info popup. Added new draw-bitmap-as-poly function.
377 * 90 6/15/99 1:56p Andsager
378 * For release builds, allow start up in high res only with
381 * 89 6/15/99 9:34a Dave
382 * Fixed key checking in single threaded version of the stamp notification
385 * 88 6/09/99 2:55p Andsager
386 * Allow multiple asteroid subtypes (of large, medium, small) and follow
389 * 87 6/08/99 1:14a Dave
390 * Multi colored hud test.
392 * 86 6/04/99 9:52a Dave
393 * Fixed some rendering problems.
395 * 85 6/03/99 10:15p Dave
396 * Put in temporary main hall screen.
398 * 84 6/02/99 6:18p Dave
399 * Fixed TNT lockup problems! Wheeeee!
401 * 83 6/01/99 3:52p Dave
402 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
403 * dead popup, pxo find player popup, pxo private room popup.
405 * 82 5/26/99 1:28p Jasenw
406 * changed coords for loading ani
408 * 81 5/26/99 11:46a Dave
409 * Added ship-blasting lighting and made the randomization of lighting
410 * much more customizable.
412 * 80 5/24/99 5:45p Dave
413 * Added detail levels to the nebula, with a decent speedup. Split nebula
414 * lightning into its own section.
432 #include "systemvars.h"
437 #include "starfield.h"
438 #include "lighting.h"
443 #include "fireballs.h"
447 #include "floating.h"
448 #include "gamesequence.h"
450 #include "optionsmenu.h"
451 #include "playermenu.h"
452 #include "trainingmenu.h"
453 #include "techmenu.h"
456 #include "hudmessage.h"
458 #include "missiongoals.h"
459 #include "missionparse.h"
464 #include "multiutil.h"
465 #include "multimsgs.h"
469 #include "freespace.h"
470 #include "managepilot.h"
472 #include "contexthelp.h"
475 #include "missionbrief.h"
476 #include "missiondebrief.h"
478 #include "missionshipchoice.h"
480 #include "hudconfig.h"
481 #include "controlsconfig.h"
482 #include "missionmessage.h"
483 #include "missiontraining.h"
485 #include "hudtarget.h"
489 #include "eventmusic.h"
490 #include "animplay.h"
491 #include "missionweaponchoice.h"
492 #include "missionlog.h"
493 #include "audiostr.h"
495 #include "missioncampaign.h"
497 #include "missionhotkey.h"
498 #include "objectsnd.h"
499 #include "cmeasure.h"
501 #include "linklist.h"
502 #include "shockwave.h"
503 #include "afterburner.h"
508 #include "stand_gui.h"
509 #include "pcxutils.h"
510 #include "hudtargetbox.h"
511 #include "multi_xfer.h"
512 #include "hudescort.h"
513 #include "multiutil.h"
516 #include "multiteamselect.h"
519 #include "readyroom.h"
520 #include "mainhallmenu.h"
521 #include "multilag.h"
523 #include "particle.h"
525 #include "multi_ingame.h"
526 #include "snazzyui.h"
527 #include "asteroid.h"
528 #include "popupdead.h"
529 #include "multi_voice.h"
530 #include "missioncmdbrief.h"
531 #include "redalert.h"
532 #include "gameplayhelp.h"
533 #include "multilag.h"
534 #include "staticrand.h"
535 #include "multi_pmsg.h"
536 #include "levelpaging.h"
537 #include "observer.h"
538 #include "multi_pause.h"
539 #include "multi_endgame.h"
540 #include "cutscenes.h"
541 #include "multi_respawn.h"
542 // #include "movie.h"
543 #include "multi_obj.h"
544 #include "multi_log.h"
546 #include "localize.h"
547 #include "osregistry.h"
548 #include "barracks.h"
549 #include "missionpause.h"
551 #include "alphacolors.h"
552 #include "objcollide.h"
555 #include "neblightning.h"
556 #include "shipcontrails.h"
559 #include "multi_dogfight.h"
560 #include "multi_rate.h"
561 #include "muzzleflash.h"
565 #include "mainhalltemp.h"
566 #include "exceptionhandler.h"
570 #include "supernova.h"
571 #include "hudshield.h"
572 // #include "names.h"
574 #include "missionloopbrief.h"
578 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
584 // 1.00.04 5/26/98 MWA -- going final (12 pm)
585 // 1.00.03 5/26/98 MWA -- going final (3 am)
586 // 1.00.02 5/25/98 MWA -- going final
587 // 1.00.01 5/25/98 MWA -- going final
588 // 0.90 5/21/98 MWA -- getting ready for final.
589 // 0.10 4/9/98. Set by MK.
591 // Demo version: (obsolete since DEMO codebase split from tree)
592 // 0.03 4/10/98 AL. Interplay rev
593 // 0.02 4/8/98 MK. Increased when this system was modified.
594 // 0.01 4/7/98? AL. First release to Interplay QA.
597 // 1.00 5/28/98 AL. First release to Interplay QA.
599 void game_level_init(int seed = -1);
600 void game_post_level_init();
601 void game_do_frame();
602 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
603 void game_reset_time();
604 void game_show_framerate(); // draws framerate in lower right corner
606 int Game_no_clear = 0;
608 int Pofview_running = 0;
609 int Nebedit_running = 0;
611 typedef struct big_expl_flash {
612 float max_flash_intensity; // max intensity
613 float cur_flash_intensity; // cur intensity
614 int flash_start; // start time
617 #define FRAME_FILTER 16
619 #define DEFAULT_SKILL_LEVEL 1
620 int Game_skill_level = DEFAULT_SKILL_LEVEL;
622 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
623 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
625 #define EXE_FNAME ("fs2.exe")
626 #define LAUNCHER_FNAME ("freespace2.exe")
628 // JAS: Code for warphole camera.
629 // Needs to be cleaned up.
630 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
631 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
632 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
633 matrix Camera_orient = IDENTITY_MATRIX;
634 float Camera_damping = 1.0f;
635 float Camera_time = 0.0f;
636 float Warpout_time = 0.0f;
637 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
638 int Warpout_sound = -1;
640 int Use_joy_mouse = 0;
641 int Use_palette_flash = 1;
643 int Use_fullscreen_at_startup = 0;
645 int Show_area_effect = 0;
646 object *Last_view_target = NULL;
648 int dogfight_blown = 0;
651 float frametimes[FRAME_FILTER];
652 float frametotal = 0.0f;
656 int Show_framerate = 0;
658 int Show_framerate = 1;
661 int Framerate_cap = 120;
664 int Show_target_debug_info = 0;
665 int Show_target_weapons = 0;
667 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
669 int Debug_octant = -1;
671 fix Game_time_compression = F1_0;
673 // if the ships.tbl the player has is valid
674 int Game_ships_tbl_valid = 0;
676 // if the weapons.tbl the player has is valid
677 int Game_weapons_tbl_valid = 0;
681 extern int Player_attacking_enabled;
685 int Pre_player_entry;
687 int Fred_running = 0;
688 char Game_current_mission_filename[MAX_FILENAME_LEN];
689 int game_single_step = 0;
690 int last_single_step=0;
692 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
693 extern int MSG_WINDOW_Y_START;
694 extern int MSG_WINDOW_HEIGHT;
696 int game_zbuffer = 1;
697 //static int Game_music_paused;
698 static int Game_paused;
702 #define EXPIRE_BAD_CHECKSUM 1
703 #define EXPIRE_BAD_TIME 2
705 extern void ssm_init();
706 extern void ssm_level_init();
707 extern void ssm_process();
709 // static variable to contain the time this version was built
710 // commented out for now until
711 // I figure out how to get the username into the file
712 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
714 // defines and variables used for dumping frame for making trailers.
716 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
717 int Debug_dump_trigger = 0;
718 int Debug_dump_frame_count;
719 int Debug_dump_frame_num = 0;
720 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
723 // amount of time to wait after the player has died before we display the death died popup
724 #define PLAYER_DIED_POPUP_WAIT 2500
725 int Player_died_popup_wait = -1;
726 int Player_multi_died_check = -1;
728 // builtin mission list stuff
730 int Game_builtin_mission_count = 6;
731 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
732 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
733 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
734 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
735 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
736 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
737 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
739 #elif defined(PD_BUILD)
740 int Game_builtin_mission_count = 4;
741 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
742 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
743 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
744 { "sm1-01", (FSB_FROM_VOLITION), "" },
745 { "sm1-05", (FSB_FROM_VOLITION), "" },
747 #elif defined(MULTIPLAYER_BETA)
748 int Game_builtin_mission_count = 17;
749 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
751 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
752 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
753 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
754 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
755 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
756 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
757 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
758 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
759 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
760 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
761 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
762 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
763 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
764 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
765 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
766 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
767 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
769 #elif defined(OEM_BUILD)
770 int Game_builtin_mission_count = 17;
771 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
772 // oem version - act 1 only
773 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
776 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
777 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
778 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
779 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
780 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
781 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
782 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
783 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
784 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
785 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
786 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
787 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
788 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
789 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
790 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
791 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
794 int Game_builtin_mission_count = 92;
795 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
796 // single player campaign
797 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
800 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
801 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
802 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
803 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
804 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
805 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
806 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
807 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
808 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
809 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
810 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
811 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
812 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
813 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
814 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
815 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
816 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
817 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
818 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
821 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
822 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
823 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
824 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
825 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
826 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
827 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
828 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
829 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
830 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
833 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
834 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
835 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
836 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
837 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
838 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
839 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
840 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
841 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
842 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
843 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
844 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
846 // multiplayer missions
849 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
850 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
851 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
854 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
855 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
856 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
857 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
860 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
861 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
862 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
863 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
864 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
865 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
866 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
867 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
868 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
869 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
870 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
871 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
872 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
873 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
874 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
875 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
876 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
877 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
878 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
879 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
880 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
881 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
882 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
883 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
884 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
885 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
886 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
887 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
890 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
891 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
892 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
893 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
894 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
895 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
896 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
897 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
898 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
899 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
902 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
903 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
904 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
905 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
906 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
911 // Internal function prototypes
912 void game_maybe_draw_mouse(float frametime);
913 void init_animating_pointer();
914 void load_animating_pointer(char *filename, int dx, int dy);
915 void unload_animating_pointer();
916 void game_do_training_checks();
917 void game_shutdown(void);
918 void game_show_event_debug(float frametime);
919 void game_event_debug_init();
921 void demo_upsell_show_screens();
922 void game_start_subspace_ambient_sound();
923 void game_stop_subspace_ambient_sound();
924 void verify_ships_tbl();
925 void verify_weapons_tbl();
926 void display_title_screen();
928 // loading background filenames
929 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
930 "LoadingBG", // GR_640
931 "2_LoadingBG" // GR_1024
935 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
936 "Loading.ani", // GR_640
937 "2_Loading.ani" // GR_1024
940 #if defined(FS2_DEMO)
941 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
945 #elif defined(OEM_BUILD)
946 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
953 char Game_CDROM_dir[MAX_PATH_LEN];
956 // How much RAM is on this machine. Set in WinMain
957 uint Freespace_total_ram = 0;
960 float Game_flash_red = 0.0f;
961 float Game_flash_green = 0.0f;
962 float Game_flash_blue = 0.0f;
963 float Sun_spot = 0.0f;
964 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
966 // game shudder stuff (in ms)
967 int Game_shudder_time = -1;
968 int Game_shudder_total = 0;
969 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
972 sound_env Game_sound_env;
973 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
974 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
976 int Game_sound_env_update_timestamp;
978 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
981 // WARPIN CRAP END --------------------------------------------------------------------------------------------
983 fs_builtin_mission *game_find_builtin_mission(char *filename)
987 // look through all existing builtin missions
988 for(idx=0; idx<Game_builtin_mission_count; idx++){
989 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
990 return &Game_builtin_mission_list[idx];
998 int game_get_default_skill_level()
1000 return DEFAULT_SKILL_LEVEL;
1004 void game_flash_reset()
1006 Game_flash_red = 0.0f;
1007 Game_flash_green = 0.0f;
1008 Game_flash_blue = 0.0f;
1010 Big_expl_flash.max_flash_intensity = 0.0f;
1011 Big_expl_flash.cur_flash_intensity = 0.0f;
1012 Big_expl_flash.flash_start = 0;
1015 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1016 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1018 void game_framerate_check_init()
1020 // zero critical time
1021 Gf_critical_time = 0.0f;
1024 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1025 // if this is a glide card
1026 if(gr_screen.mode == GR_GLIDE){
1028 extern GrHwConfiguration hwconfig;
1031 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1032 Gf_critical = 15.0f;
1036 Gf_critical = 10.0f;
1041 Gf_critical = 15.0f;
1044 // d3d. only care about good cards here I guess (TNT)
1046 Gf_critical = 15.0f;
1049 // if this is a glide card
1050 if(gr_screen.mode == GR_GLIDE){
1052 extern GrHwConfiguration hwconfig;
1055 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1056 Gf_critical = 25.0f;
1060 Gf_critical = 20.0f;
1065 Gf_critical = 25.0f;
1068 // d3d. only care about good cards here I guess (TNT)
1070 Gf_critical = 25.0f;
1075 extern float Framerate;
1076 void game_framerate_check()
1080 // if the current framerate is above the critical level, add frametime
1081 if(Framerate >= Gf_critical){
1082 Gf_critical_time += flFrametime;
1085 if(!Show_framerate){
1089 // display if we're above the critical framerate
1090 if(Framerate < Gf_critical){
1091 gr_set_color_fast(&Color_bright_red);
1092 gr_string(200, y_start, "Framerate warning");
1097 // display our current pct of good frametime
1098 if(f2fl(Missiontime) >= 0.0f){
1099 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1102 gr_set_color_fast(&Color_bright_green);
1104 gr_set_color_fast(&Color_bright_red);
1107 gr_printf(200, y_start, "%d%%", (int)pct);
1114 // Adds a flash effect. These can be positive or negative.
1115 // The range will get capped at around -1 to 1, so stick
1116 // with a range like that.
1117 void game_flash( float r, float g, float b )
1119 Game_flash_red += r;
1120 Game_flash_green += g;
1121 Game_flash_blue += b;
1123 if ( Game_flash_red < -1.0f ) {
1124 Game_flash_red = -1.0f;
1125 } else if ( Game_flash_red > 1.0f ) {
1126 Game_flash_red = 1.0f;
1129 if ( Game_flash_green < -1.0f ) {
1130 Game_flash_green = -1.0f;
1131 } else if ( Game_flash_green > 1.0f ) {
1132 Game_flash_green = 1.0f;
1135 if ( Game_flash_blue < -1.0f ) {
1136 Game_flash_blue = -1.0f;
1137 } else if ( Game_flash_blue > 1.0f ) {
1138 Game_flash_blue = 1.0f;
1143 // Adds a flash for Big Ship explosions
1144 // cap range from 0 to 1
1145 void big_explosion_flash(float flash)
1147 Big_expl_flash.flash_start = timestamp(1);
1151 } else if (flash < 0.0f) {
1155 Big_expl_flash.max_flash_intensity = flash;
1156 Big_expl_flash.cur_flash_intensity = 0.0f;
1159 // Amount to diminish palette towards normal, per second.
1160 #define DIMINISH_RATE 0.75f
1161 #define SUN_DIMINISH_RATE 6.00f
1165 float sn_glare_scale = 1.7f;
1168 dc_get_arg(ARG_FLOAT);
1169 sn_glare_scale = Dc_arg_float;
1172 float Supernova_last_glare = 0.0f;
1173 void game_sunspot_process(float frametime)
1177 float Sun_spot_goal = 0.0f;
1180 sn_stage = supernova_active();
1182 // sunspot differently based on supernova stage
1184 // approaching. player still in control
1187 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1190 light_get_global_dir(&light_dir, 0);
1192 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1195 // scale it some more
1196 dot = dot * (0.5f + (pct * 0.5f));
1199 Sun_spot_goal += (dot * sn_glare_scale);
1202 // draw the sun glow
1203 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1204 // draw the glow for this sun
1205 stars_draw_sun_glow(0);
1208 Supernova_last_glare = Sun_spot_goal;
1211 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1214 Sun_spot_goal = 0.9f;
1215 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1217 if(Sun_spot_goal > 1.0f){
1218 Sun_spot_goal = 1.0f;
1221 Sun_spot_goal *= sn_glare_scale;
1222 Supernova_last_glare = Sun_spot_goal;
1225 // fade to white. display dead popup
1228 Supernova_last_glare += (2.0f * flFrametime);
1229 if(Supernova_last_glare > 2.0f){
1230 Supernova_last_glare = 2.0f;
1233 Sun_spot_goal = Supernova_last_glare;
1240 // check sunspots for all suns
1241 n_lights = light_get_global_count();
1244 for(idx=0; idx<n_lights; idx++){
1245 //(vector *eye_pos, matrix *eye_orient)
1246 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1249 light_get_global_dir(&light_dir, idx);
1251 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1253 Sun_spot_goal += (float)pow(dot,85.0f);
1255 // draw the glow for this sun
1256 stars_draw_sun_glow(idx);
1258 Sun_spot_goal = 0.0f;
1264 Sun_spot_goal = 0.0f;
1268 float dec_amount = frametime*SUN_DIMINISH_RATE;
1270 if ( Sun_spot < Sun_spot_goal ) {
1271 Sun_spot += dec_amount;
1272 if ( Sun_spot > Sun_spot_goal ) {
1273 Sun_spot = Sun_spot_goal;
1275 } else if ( Sun_spot > Sun_spot_goal ) {
1276 Sun_spot -= dec_amount;
1277 if ( Sun_spot < Sun_spot_goal ) {
1278 Sun_spot = Sun_spot_goal;
1284 // Call once a frame to diminish the
1285 // flash effect to 0.
1286 void game_flash_diminish(float frametime)
1288 float dec_amount = frametime*DIMINISH_RATE;
1290 if ( Game_flash_red > 0.0f ) {
1291 Game_flash_red -= dec_amount;
1292 if ( Game_flash_red < 0.0f )
1293 Game_flash_red = 0.0f;
1295 Game_flash_red += dec_amount;
1296 if ( Game_flash_red > 0.0f )
1297 Game_flash_red = 0.0f;
1300 if ( Game_flash_green > 0.0f ) {
1301 Game_flash_green -= dec_amount;
1302 if ( Game_flash_green < 0.0f )
1303 Game_flash_green = 0.0f;
1305 Game_flash_green += dec_amount;
1306 if ( Game_flash_green > 0.0f )
1307 Game_flash_green = 0.0f;
1310 if ( Game_flash_blue > 0.0f ) {
1311 Game_flash_blue -= dec_amount;
1312 if ( Game_flash_blue < 0.0f )
1313 Game_flash_blue = 0.0f;
1315 Game_flash_blue += dec_amount;
1316 if ( Game_flash_blue > 0.0f )
1317 Game_flash_blue = 0.0f;
1320 // update big_explosion_cur_flash
1321 #define TIME_UP 1500
1322 #define TIME_DOWN 2500
1323 int duration = TIME_UP + TIME_DOWN;
1324 int time = timestamp_until(Big_expl_flash.flash_start);
1325 if (time > -duration) {
1327 if (time < TIME_UP) {
1328 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1331 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1335 if ( Use_palette_flash ) {
1337 // static int or=0, og=0, ob=0;
1339 // Change the 200 to change the color range of colors.
1340 r = fl2i( Game_flash_red*128.0f );
1341 g = fl2i( Game_flash_green*128.0f );
1342 b = fl2i( Game_flash_blue*128.0f );
1344 if ( Sun_spot > 0.0f ) {
1345 r += fl2i(Sun_spot*128.0f);
1346 g += fl2i(Sun_spot*128.0f);
1347 b += fl2i(Sun_spot*128.0f);
1350 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1351 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1352 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1353 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1356 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1357 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1358 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1360 if ( (r!=0) || (g!=0) || (b!=0) ) {
1361 gr_flash( r, g, b );
1363 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1374 void game_level_close()
1376 // De-Initialize the game subsystems
1377 message_mission_shutdown();
1378 event_music_level_close();
1379 game_stop_looped_sounds();
1381 obj_snd_level_close(); // uninit object-linked persistant sounds
1382 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1383 anim_level_close(); // stop and clean up any anim instances
1384 shockwave_level_close();
1385 fireball_level_close();
1387 mission_event_shutdown();
1388 asteroid_level_close();
1389 model_cache_reset(); // Reset/free all the model caching stuff
1390 flak_level_close(); // unload flak stuff
1391 neb2_level_close(); // shutdown gaseous nebula stuff
1394 mflash_level_close();
1396 audiostream_unpause_all();
1401 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1402 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1403 void game_level_init(int seed)
1405 // seed the random number generator
1407 // if no seed was passed, seed the generator either from the time value, or from the
1408 // netgame security flags -- ensures that all players in multiplayer game will have the
1409 // same randon number sequence (with static rand functions)
1410 if ( Game_mode & GM_NORMAL ) {
1411 Game_level_seed = time(NULL);
1413 Game_level_seed = Netgame.security;
1416 // mwa 9/17/98 -- maybe this assert isn't needed????
1417 Assert( !(Game_mode & GM_MULTIPLAYER) );
1418 Game_level_seed = seed;
1420 srand( Game_level_seed );
1422 // semirand function needs to get re-initted every time in multiplayer
1423 if ( Game_mode & GM_MULTIPLAYER ){
1429 Key_normal_game = (Game_mode & GM_NORMAL);
1432 Game_shudder_time = -1;
1434 // Initialize the game subsystems
1435 // timestamp_reset(); // Must be inited before everything else
1437 game_reset_time(); // resets time, and resets saved time too
1439 obj_init(); // Must be inited before the other systems
1440 model_free_all(); // Free all existing models
1441 mission_brief_common_init(); // Free all existing briefing/debriefing text
1442 weapon_level_init();
1443 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1445 player_level_init();
1446 shipfx_flash_init(); // Init the ship gun flash system.
1447 game_flash_reset(); // Reset the flash effect
1448 particle_init(); // Reset the particle system
1452 shield_hit_init(); // Initialize system for showing shield hits
1453 radar_mission_init();
1454 mission_init_goals();
1457 obj_snd_level_init(); // init object-linked persistant sounds
1459 shockwave_level_init();
1460 afterburner_level_init();
1461 scoring_level_init( &Player->stats );
1463 asteroid_level_init();
1464 control_config_clear_used_status();
1465 collide_ship_ship_sounds_init();
1467 Pre_player_entry = 1; // Means the player has not yet entered.
1468 Entry_delay_time = 0; // Could get overwritten in mission read.
1469 fireball_preload(); // page in warphole bitmaps
1471 flak_level_init(); // initialize flak - bitmaps, etc
1472 ct_level_init(); // initialize ships contrails, etc
1473 awacs_level_init(); // initialize AWACS
1474 beam_level_init(); // initialize beam weapons
1475 mflash_level_init();
1477 supernova_level_init();
1479 // multiplayer dogfight hack
1482 shipfx_engine_wash_level_init();
1486 Last_view_target = NULL;
1491 // campaign wasn't ended
1492 Campaign_ended_in_mission = 0;
1495 // called when a mission is over -- does server specific stuff.
1496 void freespace_stop_mission()
1499 Game_mode &= ~GM_IN_MISSION;
1502 // called at frame interval to process networking stuff
1503 void game_do_networking()
1505 Assert( Net_player != NULL );
1506 if (!(Game_mode & GM_MULTIPLAYER)){
1510 // see if this player should be reading/writing data. Bit is set when at join
1511 // screen onward until quits back to main menu.
1512 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1516 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1519 multi_pause_do_frame();
1524 // Loads the best palette for this level, based
1525 // on nebula color and hud color. You could just call palette_load_table with
1526 // the appropriate filename, but who wants to do that.
1527 void game_load_palette()
1529 char palette_filename[1024];
1531 // We only use 3 hud colors right now
1532 // Assert( HUD_config.color >= 0 );
1533 // Assert( HUD_config.color <= 2 );
1535 Assert( Mission_palette >= 0 );
1536 Assert( Mission_palette <= 98 );
1538 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1539 strcpy( palette_filename, NOX("gamepalette-subspace") );
1541 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1544 mprintf(( "Loading palette %s\n", palette_filename ));
1546 // palette_load_table(palette_filename);
1549 void game_post_level_init()
1551 // Stuff which gets called after mission is loaded. Because player isn't created until
1552 // after mission loads, some things must get initted after the level loads
1554 model_level_post_init();
1557 hud_setup_escort_list();
1558 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1564 game_event_debug_init();
1567 training_mission_init();
1568 asteroid_create_all();
1570 game_framerate_check_init();
1574 // An estimate as to how high the count passed to game_loading_callback will go.
1575 // This is just a guess, it seems to always be about the same. The count is
1576 // proportional to the code being executed, not the time, so this works good
1577 // for a bar, assuming the code does about the same thing each time you
1578 // load a level. You can find this value by looking at the return value
1579 // of game_busy_callback(NULL), which I conveniently print out to the
1580 // debug output window with the '=== ENDING LOAD ==' stuff.
1581 //#define COUNT_ESTIMATE 3706
1582 #define COUNT_ESTIMATE 1111
1584 int Game_loading_callback_inited = 0;
1586 int Game_loading_background = -1;
1587 anim * Game_loading_ani = NULL;
1588 anim_instance *Game_loading_ani_instance;
1589 int Game_loading_frame=-1;
1591 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1600 // This gets called 10x per second and count is the number of times
1601 // game_busy() has been called since the current callback function
1603 void game_loading_callback(int count)
1605 game_do_networking();
1607 Assert( Game_loading_callback_inited==1 );
1608 Assert( Game_loading_ani != NULL );
1610 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1611 if ( framenum > Game_loading_ani->total_frames-1 ) {
1612 framenum = Game_loading_ani->total_frames-1;
1613 } else if ( framenum < 0 ) {
1618 while ( Game_loading_frame < framenum ) {
1619 Game_loading_frame++;
1620 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1624 if ( cbitmap > -1 ) {
1625 if ( Game_loading_background > -1 ) {
1626 gr_set_bitmap( Game_loading_background );
1630 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1631 gr_set_bitmap( cbitmap );
1632 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1634 bm_release(cbitmap);
1640 void game_loading_callback_init()
1642 Assert( Game_loading_callback_inited==0 );
1644 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1645 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1648 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1649 Assert( Game_loading_ani != NULL );
1650 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1651 Assert( Game_loading_ani_instance != NULL );
1652 Game_loading_frame = -1;
1654 Game_loading_callback_inited = 1;
1656 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1661 void game_loading_callback_close()
1663 Assert( Game_loading_callback_inited==1 );
1665 // Make sure bar shows all the way over.
1666 game_loading_callback(COUNT_ESTIMATE);
1668 int real_count = game_busy_callback( NULL );
1671 Game_loading_callback_inited = 0;
1674 mprintf(( "=================== ENDING LOAD ================\n" ));
1675 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1676 mprintf(( "================================================\n" ));
1678 // to remove warnings in release build
1682 free_anim_instance(Game_loading_ani_instance);
1683 Game_loading_ani_instance = NULL;
1684 anim_free(Game_loading_ani);
1685 Game_loading_ani = NULL;
1687 bm_release( Game_loading_background );
1688 common_free_interface_palette(); // restore game palette
1689 Game_loading_background = -1;
1691 gr_set_font( FONT1 );
1694 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1696 void game_maybe_update_sound_environment()
1698 // do nothing for now
1701 // Assign the sound environment for the game, based on the current mission
1703 void game_assign_sound_environment()
1706 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1707 Game_sound_env.id = SND_ENV_DRUGGED;
1708 Game_sound_env.volume = 0.800f;
1709 Game_sound_env.damping = 1.188f;
1710 Game_sound_env.decay = 6.392f;
1712 } else if (Num_asteroids > 30) {
1713 Game_sound_env.id = SND_ENV_AUDITORIUM;
1714 Game_sound_env.volume = 0.603f;
1715 Game_sound_env.damping = 0.5f;
1716 Game_sound_env.decay = 4.279f;
1719 Game_sound_env = Game_default_sound_env;
1723 Game_sound_env = Game_default_sound_env;
1724 Game_sound_env_update_timestamp = timestamp(1);
1727 // function which gets called before actually entering the mission. It is broken down into a funciton
1728 // since it will get called in one place from a single player game and from another place for
1729 // a multiplayer game
1730 void freespace_mission_load_stuff()
1732 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1733 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1734 if(!(Game_mode & GM_STANDALONE_SERVER)){
1736 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1738 game_loading_callback_init();
1740 event_music_level_init(); // preloads the first 2 seconds for each event music track
1743 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1746 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1749 ship_assign_sound_all(); // assign engine sounds to ships
1750 game_assign_sound_environment(); // assign the sound environment for this mission
1753 // call function in missionparse.cpp to fixup player/ai stuff.
1754 mission_parse_fixup_players();
1757 // Load in all the bitmaps for this level
1762 game_loading_callback_close();
1764 // the only thing we need to call on the standalone for now.
1766 // call function in missionparse.cpp to fixup player/ai stuff.
1767 mission_parse_fixup_players();
1769 // Load in all the bitmaps for this level
1775 uint load_mission_load;
1776 uint load_post_level_init;
1777 uint load_mission_stuff;
1779 // tells the server to load the mission and initialize structures
1780 int game_start_mission()
1782 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1784 load_gl_init = time(NULL);
1786 load_gl_init = time(NULL) - load_gl_init;
1788 if (Game_mode & GM_MULTIPLAYER) {
1789 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1791 // clear multiplayer stats
1792 init_multiplayer_stats();
1795 load_mission_load = time(NULL);
1796 if (mission_load()) {
1797 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1798 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1799 gameseq_post_event(GS_EVENT_MAIN_MENU);
1801 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1806 load_mission_load = time(NULL) - load_mission_load;
1808 // If this is a red alert mission in campaign mode, bash wingman status
1809 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1810 red_alert_bash_wingman_status();
1813 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1814 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1815 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1816 // game_load_palette();
1819 load_post_level_init = time(NULL);
1820 game_post_level_init();
1821 load_post_level_init = time(NULL) - load_post_level_init;
1825 void Do_model_timings_test();
1826 Do_model_timings_test();
1830 load_mission_stuff = time(NULL);
1831 freespace_mission_load_stuff();
1832 load_mission_stuff = time(NULL) - load_mission_stuff;
1837 int Interface_framerate = 0;
1840 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1841 DCF_BOOL( show_framerate, Show_framerate )
1842 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1843 DCF_BOOL( show_target_weapons, Show_target_weapons )
1844 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1845 DCF_BOOL( sound, Sound_enabled )
1846 DCF_BOOL( zbuffer, game_zbuffer )
1847 DCF_BOOL( shield_system, New_shield_system )
1848 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1849 DCF_BOOL( player_attacking, Player_attacking_enabled )
1850 DCF_BOOL( show_waypoints, Show_waypoints )
1851 DCF_BOOL( show_area_effect, Show_area_effect )
1852 DCF_BOOL( show_net_stats, Show_net_stats )
1853 DCF_BOOL( log, Log_debug_output_to_file )
1854 DCF_BOOL( training_msg_method, Training_msg_method )
1855 DCF_BOOL( show_player_pos, Show_player_pos )
1856 DCF_BOOL(i_framerate, Interface_framerate )
1858 DCF(show_mem,"Toggles showing mem usage")
1861 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1862 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1863 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1864 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1870 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1872 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1873 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1877 DCF(show_cpu,"Toggles showing cpu usage")
1880 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1881 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1882 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1883 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1889 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1891 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1892 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1899 // AL 4-8-98: always allow players to display their framerate
1902 DCF_BOOL( show_framerate, Show_framerate )
1909 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1912 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1913 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1914 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1915 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1917 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" );
1918 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1920 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1923 DCF(palette_flash,"Toggles palette flash effect on/off")
1926 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1927 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
1928 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
1929 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
1931 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
1932 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
1935 int Use_low_mem = 0;
1937 DCF(low_mem,"Uses low memory settings regardless of RAM")
1940 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1941 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
1942 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
1943 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
1945 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
1946 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
1948 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1954 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1957 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1958 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
1959 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
1960 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
1962 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
1963 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
1964 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1968 int Framerate_delay = 0;
1970 float Freespace_gamma = 1.0f;
1972 DCF(gamma,"Sets Gamma factor")
1975 dc_get_arg(ARG_FLOAT|ARG_NONE);
1976 if ( Dc_arg_type & ARG_FLOAT ) {
1977 Freespace_gamma = Dc_arg_float;
1979 dc_printf( "Gamma reset to 1.0f\n" );
1980 Freespace_gamma = 1.0f;
1982 if ( Freespace_gamma < 0.1f ) {
1983 Freespace_gamma = 0.1f;
1984 } else if ( Freespace_gamma > 5.0f ) {
1985 Freespace_gamma = 5.0f;
1987 gr_set_gamma(Freespace_gamma);
1989 char tmp_gamma_string[32];
1990 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1991 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1995 dc_printf( "Usage: gamma <float>\n" );
1996 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
1997 Dc_status = 0; // don't print status if help is printed. Too messy.
2001 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2010 Game_current_mission_filename[0] = 0;
2012 // seed the random number generator
2013 Game_init_seed = time(NULL);
2014 srand( Game_init_seed );
2016 Framerate_delay = 0;
2022 extern void bm_init();
2028 // Initialize the timer before the os
2036 GetCurrentDirectory(1024, whee);
2042 strcat(whee, EXE_FNAME);
2044 //Initialize the libraries
2045 s1 = timer_get_milliseconds();
2046 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2049 e1 = timer_get_milliseconds();
2051 // time a bunch of cfopens
2053 s2 = timer_get_milliseconds();
2055 for(int idx=0; idx<10000; idx++){
2056 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2061 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2063 e2 = timer_get_milliseconds();
2066 if (Is_standalone) {
2067 std_init_standalone();
2069 os_init( Osreg_class_name, Osreg_app_name );
2070 os_set_title(Osreg_title);
2073 // initialize localization module. Make sure this is down AFTER initialzing OS.
2074 // int t1 = timer_get_milliseconds();
2077 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2079 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2082 // verify that he has a valid weapons.tbl
2083 verify_weapons_tbl();
2085 // Output version numbers to registry for auto patching purposes
2086 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2087 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2088 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2090 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2091 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2092 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2095 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2099 Asteroids_enabled = 1;
2102 /////////////////////////////
2104 /////////////////////////////
2109 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2110 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2112 if (!stricmp(ptr, NOX("no sound"))) {
2113 Cmdline_freespace_no_sound = 1;
2115 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2117 } else if (!stricmp(ptr, NOX("EAX"))) {
2122 if (!Is_standalone) {
2123 snd_init(use_a3d, use_eax);
2125 /////////////////////////////
2127 /////////////////////////////
2129 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2132 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);
2134 // fire up the UpdateLauncher executable
2136 PROCESS_INFORMATION pi;
2138 memset( &si, 0, sizeof(STARTUPINFO) );
2141 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2142 NULL, // pointer to command line string
2143 NULL, // pointer to process security attributes
2144 NULL, // pointer to thread security attributes
2145 FALSE, // handle inheritance flag
2146 CREATE_DEFAULT_ERROR_MODE, // creation flags
2147 NULL, // pointer to new environment block
2148 NULL, // pointer to current directory name
2149 &si, // pointer to STARTUPINFO
2150 &pi // pointer to PROCESS_INFORMATION
2153 // If the Launcher could not be started up, let the user know
2155 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2164 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2166 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);
2174 // check for hi res pack file
2175 int has_sparky_hi = 0;
2177 // check if sparky_hi exists -- access mode 0 means does file exist
2180 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2183 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2186 // see if we've got 32 bit in the string
2187 if(strstr(ptr, "32 bit")){
2193 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2195 // always 640 for E3
2196 gr_init(GR_640, GR_GLIDE);
2198 // regular or hi-res ?
2200 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2202 if(strstr(ptr, NOX("(1024x768)"))){
2204 gr_init(GR_1024, GR_GLIDE);
2206 gr_init(GR_640, GR_GLIDE);
2209 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2211 // always 640 for E3
2213 gr_init(GR_640, GR_DIRECT3D, depth);
2215 // regular or hi-res ?
2217 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2219 if(strstr(ptr, NOX("(1024x768)"))){
2223 gr_init(GR_1024, GR_DIRECT3D, depth);
2227 gr_init(GR_640, GR_DIRECT3D, depth);
2233 if ( Use_fullscreen_at_startup && !Is_standalone) {
2234 gr_init(GR_640, GR_DIRECTDRAW);
2236 gr_init(GR_640, GR_SOFTWARE);
2239 if ( !Is_standalone ) {
2240 gr_init(GR_640, GR_DIRECTDRAW);
2242 gr_init(GR_640, GR_SOFTWARE);
2248 extern int Gr_inited;
2249 if(trying_d3d && !Gr_inited){
2250 extern char Device_init_error[512];
2252 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2261 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2262 Freespace_gamma = (float)atof(ptr);
2263 if ( Freespace_gamma < 0.1f ) {
2264 Freespace_gamma = 0.1f;
2265 } else if ( Freespace_gamma > 5.0f ) {
2266 Freespace_gamma = 5.0f;
2268 char tmp_gamma_string[32];
2269 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2270 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2272 gr_set_gamma(Freespace_gamma);
2274 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2277 display_title_screen();
2281 // attempt to load up master tracker registry info (login and password)
2282 Multi_tracker_id = -1;
2284 // pxo login and password
2285 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2287 nprintf(("Network","Error reading in PXO login data\n"));
2288 strcpy(Multi_tracker_login,"");
2290 strcpy(Multi_tracker_login,ptr);
2292 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2294 nprintf(("Network","Error reading PXO password\n"));
2295 strcpy(Multi_tracker_passwd,"");
2297 strcpy(Multi_tracker_passwd,ptr);
2300 // pxo squad name and password
2301 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2303 nprintf(("Network","Error reading in PXO squad name\n"));
2304 strcpy(Multi_tracker_squad_name, "");
2306 strcpy(Multi_tracker_squad_name, ptr);
2309 // If less than 48MB of RAM, use low memory model.
2310 if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem ) {
2311 mprintf(( "Using normal memory settings...\n" ));
2312 bm_set_low_mem(1); // Use every other frame of bitmaps
2314 mprintf(( "Using high memory settings...\n" ));
2315 bm_set_low_mem(0); // Use all frames of bitmaps
2318 // load non-darkening pixel defs
2319 palman_load_pixels();
2321 // hud shield icon stuff
2322 hud_shield_game_init();
2324 control_config_common_init(); // sets up localization stuff in the control config
2330 gamesnd_parse_soundstbl();
2335 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2340 player_controls_init();
2343 //if(!Is_standalone){
2351 ship_init(); // read in ships.tbl
2353 mission_campaign_init(); // load in the default campaign
2355 // navmap_init(); // init the navigation map system
2356 context_help_init();
2357 techroom_intel_init(); // parse species.tbl, load intel info
2359 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2360 init_animating_pointer();
2362 mission_brief_common_init(); // Mark all the briefing structures as empty.
2363 gr_font_init(); // loads up all fonts
2365 neb2_init(); // fullneb stuff
2369 player_tips_init(); // helpful tips
2372 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2373 pilot_load_pic_list();
2374 pilot_load_squad_pic_list();
2376 load_animating_pointer(NOX("cursor"), 0, 0);
2378 // initialize alpha colors
2379 alpha_colors_init();
2382 // Game_music_paused = 0;
2389 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2390 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2392 mprintf(("cfile_init() took %d\n", e1 - s1));
2393 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2396 char transfer_text[128];
2398 float Start_time = 0.0f;
2400 float Framerate = 0.0f;
2402 float Timing_total = 0.0f;
2403 float Timing_render2 = 0.0f;
2404 float Timing_render3 = 0.0f;
2405 float Timing_flip = 0.0f;
2406 float Timing_clear = 0.0f;
2408 MONITOR(NumPolysDrawn);
2414 void game_get_framerate()
2416 char text[128] = "";
2418 if ( frame_int == -1 ) {
2420 for (i=0; i<FRAME_FILTER; i++ ) {
2421 frametimes[i] = 0.0f;
2426 frametotal -= frametimes[frame_int];
2427 frametotal += flFrametime;
2428 frametimes[frame_int] = flFrametime;
2429 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2431 if ( frametotal != 0.0 ) {
2432 if ( Framecount >= FRAME_FILTER )
2433 Framerate = FRAME_FILTER / frametotal;
2435 Framerate = Framecount / frametotal;
2436 sprintf( text, NOX("FPS: %.1f"), Framerate );
2438 sprintf( text, NOX("FPS: ?") );
2442 if (Show_framerate) {
2443 gr_set_color_fast(&HUD_color_debug);
2444 gr_string( 570, 2, text );
2448 void game_show_framerate()
2452 cur_time = f2fl(timer_get_approx_seconds());
2453 if (cur_time - Start_time > 30.0f) {
2454 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2455 Start_time += 1000.0f;
2458 //mprintf(( "%s\n", text ));
2461 if ( Debug_dump_frames )
2465 // possibly show control checking info
2466 control_check_indicate();
2468 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2469 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2470 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2471 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2474 if ( Show_cpu == 1 ) {
2479 dy = gr_get_font_height() + 1;
2481 gr_set_color_fast(&HUD_color_debug);
2484 extern int D3D_textures_in;
2485 extern int D3D_textures_in_frame;
2486 extern int Glide_textures_in;
2487 extern int Glide_textures_in_frame;
2488 extern int Glide_explosion_vram;
2489 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2491 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2493 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2496 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2498 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2500 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2502 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2504 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2509 extern int Num_pairs; // Number of object pairs that were checked.
2510 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2513 extern int Num_pairs_checked; // What percent of object pairs were checked.
2514 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2516 Num_pairs_checked = 0;
2520 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2523 if ( Timing_total > 0.01f ) {
2524 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2526 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2528 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2530 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2532 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2542 dy = gr_get_font_height() + 1;
2544 gr_set_color_fast(&HUD_color_debug);
2547 extern int TotalRam;
2548 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2553 extern int Model_ram;
2554 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2558 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2560 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2562 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2565 extern int D3D_textures_in;
2566 extern int Glide_textures_in;
2567 extern int Glide_textures_in_frame;
2568 extern int Glide_explosion_vram;
2569 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2571 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2573 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2579 if ( Show_player_pos ) {
2583 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));
2586 MONITOR_INC(NumPolys, modelstats_num_polys);
2587 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2588 MONITOR_INC(NumVerts, modelstats_num_verts );
2590 modelstats_num_polys = 0;
2591 modelstats_num_polys_drawn = 0;
2592 modelstats_num_verts = 0;
2593 modelstats_num_sortnorms = 0;
2597 void game_show_standalone_framerate()
2599 float frame_rate=30.0f;
2600 if ( frame_int == -1 ) {
2602 for (i=0; i<FRAME_FILTER; i++ ) {
2603 frametimes[i] = 0.0f;
2608 frametotal -= frametimes[frame_int];
2609 frametotal += flFrametime;
2610 frametimes[frame_int] = flFrametime;
2611 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2613 if ( frametotal != 0.0 ) {
2614 if ( Framecount >= FRAME_FILTER ){
2615 frame_rate = FRAME_FILTER / frametotal;
2617 frame_rate = Framecount / frametotal;
2620 std_set_standalone_fps(frame_rate);
2624 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2625 void game_show_time_left()
2629 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2630 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2631 // checking how much time is left
2633 if ( Mission_end_time == -1 ){
2637 diff = f2i(Mission_end_time - Missiontime);
2638 // be sure to bash to 0. diff could be negative on frame that we quit mission
2643 hud_set_default_color();
2644 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2647 //========================================================================================
2648 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2649 //========================================================================================
2653 DCF(ai_pause,"Pauses ai")
2656 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2657 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2658 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2659 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2662 obj_init_all_ships_physics();
2665 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2666 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2669 DCF(single_step,"Single steps the game")
2672 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2673 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2674 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2675 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2677 last_single_step = 0; // Make so single step waits a frame before stepping
2680 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2681 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2684 DCF_BOOL(physics_pause, physics_paused)
2685 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2686 DCF_BOOL(ai_firing, Ai_firing_enabled )
2688 // Create some simple aliases to these commands...
2689 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2690 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2691 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2692 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2693 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2696 //========================================================================================
2697 //========================================================================================
2700 void game_training_pause_do()
2704 key = game_check_key();
2706 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2713 void game_increase_skill_level()
2716 if (Game_skill_level >= NUM_SKILL_LEVELS){
2717 Game_skill_level = 0;
2721 int Player_died_time;
2723 int View_percent = 100;
2726 DCF(view, "Sets the percent of the 3d view to render.")
2729 dc_get_arg(ARG_INT);
2730 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2731 View_percent = Dc_arg_int;
2733 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2739 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2743 dc_printf("View is set to %d%%\n", View_percent );
2748 // Set the clip region for the 3d rendering window
2749 void game_set_view_clip()
2751 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2752 // Set the clip region for the letterbox "dead view"
2753 int yborder = gr_screen.max_h/4;
2755 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2756 // J.S. I've changed my ways!! See the new "no constants" code!!!
2757 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2759 // Set the clip region for normal view
2760 if ( View_percent >= 100 ) {
2763 int xborder, yborder;
2765 if ( View_percent < 5 ) {
2769 float fp = i2fl(View_percent)/100.0f;
2770 int fi = fl2i(fl_sqrt(fp)*100.0f);
2771 if ( fi > 100 ) fi=100;
2773 xborder = ( gr_screen.max_w*(100-fi) )/200;
2774 yborder = ( gr_screen.max_h*(100-fi) )/200;
2776 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2782 void show_debug_stuff()
2785 int laser_count = 0, missile_count = 0;
2787 for (i=0; i<MAX_OBJECTS; i++) {
2788 if (Objects[i].type == OBJ_WEAPON){
2789 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2791 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2797 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2800 extern int Tool_enabled;
2805 int tst_bitmap = -1;
2807 float tst_offset, tst_offset_total;
2810 void game_tst_frame_pre()
2818 g3_rotate_vertex(&v, &tst_pos);
2819 g3_project_vertex(&v);
2822 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2826 // big ship? always tst
2828 // within 3000 meters
2829 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2833 // within 300 meters
2834 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2841 void game_tst_frame()
2851 tst_time = time(NULL);
2853 // load the tst bitmap
2854 switch((int)frand_range(0.0f, 3.0)){
2856 tst_bitmap = bm_load("ig_jim");
2858 mprintf(("TST 0\n"));
2862 tst_bitmap = bm_load("ig_kan");
2864 mprintf(("TST 1\n"));
2868 tst_bitmap = bm_load("ig_jim");
2870 mprintf(("TST 2\n"));
2874 tst_bitmap = bm_load("ig_kan");
2876 mprintf(("TST 3\n"));
2885 // get the tst bitmap dimensions
2887 bm_get_info(tst_bitmap, &w, &h);
2890 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2892 snd_play(&Snds[SND_VASUDAN_BUP]);
2894 // tst x and direction
2898 tst_offset_total = (float)w;
2899 tst_offset = (float)w;
2901 tst_x = (float)gr_screen.max_w;
2902 tst_offset_total = (float)-w;
2903 tst_offset = (float)w;
2911 float diff = (tst_offset_total / 0.5f) * flFrametime;
2917 tst_offset -= fl_abs(diff);
2918 } else if(tst_mode == 2){
2921 tst_offset -= fl_abs(diff);
2925 gr_set_bitmap(tst_bitmap);
2926 gr_bitmap((int)tst_x, (int)tst_y);
2929 if(timestamp_elapsed_safe(tst_stamp, 1100)){
2933 // if we passed the switch point
2934 if(tst_offset <= 0.0f){
2939 tst_stamp = timestamp(1000);
2940 tst_offset = fl_abs(tst_offset_total);
2951 void game_tst_mark(object *objp, ship *shipp)
2960 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2963 sip = &Ship_info[shipp->ship_info_index];
2970 tst_pos = objp->pos;
2971 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2977 extern void render_shields();
2979 void player_repair_frame(float frametime)
2981 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2983 for(idx=0;idx<MAX_PLAYERS;idx++){
2986 np = &Net_players[idx];
2988 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)){
2990 // don't rearm/repair if the player is dead or dying/departing
2991 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
2992 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
2997 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
2998 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3004 #define NUM_FRAMES_TEST 300
3005 #define NUM_MIXED_SOUNDS 16
3006 void do_timing_test(float flFrametime)
3008 static int framecount = 0;
3009 static int test_running = 0;
3010 static float test_time = 0.0f;
3012 static int snds[NUM_MIXED_SOUNDS];
3015 if ( test_running ) {
3017 test_time += flFrametime;
3018 if ( framecount >= NUM_FRAMES_TEST ) {
3020 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3021 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3026 if ( Test_begin == 1 ) {
3032 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3035 // start looping digital sounds
3036 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3037 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3044 DCF(dcf_fov, "Change the field of view")
3047 dc_get_arg(ARG_FLOAT|ARG_NONE);
3048 if ( Dc_arg_type & ARG_NONE ) {
3049 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3050 dc_printf( "Zoom factor reset\n" );
3052 if ( Dc_arg_type & ARG_FLOAT ) {
3053 if (Dc_arg_float < 0.25f) {
3054 Viewer_zoom = 0.25f;
3055 dc_printf("Zoom factor pinned at 0.25.\n");
3056 } else if (Dc_arg_float > 1.25f) {
3057 Viewer_zoom = 1.25f;
3058 dc_printf("Zoom factor pinned at 1.25.\n");
3060 Viewer_zoom = Dc_arg_float;
3066 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3069 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3073 DCF(framerate_cap, "Sets the framerate cap")
3076 dc_get_arg(ARG_INT);
3077 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3078 Framerate_cap = Dc_arg_int;
3080 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3086 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3087 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3088 dc_printf("[n] must be from 1 to 120.\n");
3092 if ( Framerate_cap )
3093 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3095 dc_printf("There is no framerate cap currently active.\n");
3099 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3100 int Show_viewing_from_self = 0;
3102 void say_view_target()
3104 object *view_target;
3106 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3107 view_target = &Objects[Player_ai->target_objnum];
3109 view_target = Player_obj;
3111 if (Game_mode & GM_DEAD) {
3112 if (Player_ai->target_objnum != -1)
3113 view_target = &Objects[Player_ai->target_objnum];
3116 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3117 if (view_target != Player_obj){
3119 char *view_target_name = NULL;
3120 switch(Objects[Player_ai->target_objnum].type) {
3122 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3125 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3126 Viewer_mode &= ~VM_OTHER_SHIP;
3128 case OBJ_JUMP_NODE: {
3129 char jump_node_name[128];
3130 strcpy(jump_node_name, XSTR( "jump node", 184));
3131 view_target_name = jump_node_name;
3132 Viewer_mode &= ~VM_OTHER_SHIP;
3141 if ( view_target_name ) {
3142 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3143 Show_viewing_from_self = 1;
3146 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3147 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3148 Show_viewing_from_self = 1;
3150 if (Show_viewing_from_self)
3151 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3156 Last_view_target = view_target;
3160 float Game_hit_x = 0.0f;
3161 float Game_hit_y = 0.0f;
3163 // Reset at the beginning of each frame
3164 void game_whack_reset()
3170 // Apply a 2d whack to the player
3171 void game_whack_apply( float x, float y )
3173 // Do some force feedback
3174 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3180 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3183 // call to apply a "shudder"
3184 void game_shudder_apply(int time, float intensity)
3186 Game_shudder_time = timestamp(time);
3187 Game_shudder_total = time;
3188 Game_shudder_intensity = intensity;
3191 #define FF_SCALE 10000
3192 void apply_hud_shake(matrix *eye_orient)
3194 if (Viewer_obj == Player_obj) {
3195 physics_info *pi = &Player_obj->phys_info;
3203 // Make eye shake due to afterburner
3204 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3207 dtime = timestamp_until(pi->afterburner_decay);
3211 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3212 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3215 // Make eye shake due to engine wash
3217 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3220 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3221 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3223 // get the intensity
3224 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3228 vm_vec_rand_vec_quick(&rand_vec);
3231 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3235 // make hud shake due to shuddering
3236 if(Game_shudder_time != -1){
3237 // if the timestamp has elapsed
3238 if(timestamp_elapsed(Game_shudder_time)){
3239 Game_shudder_time = -1;
3241 // otherwise apply some shudder
3245 dtime = timestamp_until(Game_shudder_time);
3249 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));
3250 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));
3255 vm_angles_2_matrix(&tm, &tangles);
3256 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3257 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3258 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3259 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3264 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3266 // Player's velocity just before he blew up. Used to keep camera target moving.
3267 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3269 // Set eye_pos and eye_orient based on view mode.
3270 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3274 static int last_Viewer_mode = 0;
3275 static int last_Game_mode = 0;
3276 static int last_Viewer_objnum = -1;
3278 // This code is supposed to detect camera "cuts"... like going between
3281 // determine if we need to regenerate the nebula
3282 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3283 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3284 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3285 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3286 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3287 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3288 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3289 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3290 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3293 // regenerate the nebula
3297 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3298 //mprintf(( "************** Camera cut! ************\n" ));
3299 last_Viewer_mode = Viewer_mode;
3300 last_Game_mode = Game_mode;
3302 // Camera moved. Tell stars & debris to not do blurring.
3308 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3309 player_display_packlock_view();
3312 game_set_view_clip();
3314 if (Game_mode & GM_DEAD) {
3315 vector vec_to_deader, view_pos;
3318 Viewer_mode |= VM_DEAD_VIEW;
3320 if (Player_ai->target_objnum != -1) {
3321 int view_from_player = 1;
3323 if (Viewer_mode & VM_OTHER_SHIP) {
3324 // View from target.
3325 Viewer_obj = &Objects[Player_ai->target_objnum];
3327 last_Viewer_objnum = Player_ai->target_objnum;
3329 if ( Viewer_obj->type == OBJ_SHIP ) {
3330 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3331 view_from_player = 0;
3334 last_Viewer_objnum = -1;
3337 if ( view_from_player ) {
3338 // View target from player ship.
3340 *eye_pos = Player_obj->pos;
3341 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3342 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3345 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3347 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3348 dist += flFrametime * 16.0f;
3350 vm_vec_scale(&vec_to_deader, -dist);
3351 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3353 view_pos = Player_obj->pos;
3355 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3356 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3357 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3358 Dead_player_last_vel = Player_obj->phys_info.vel;
3359 //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));
3360 } else if (Player_ai->target_objnum != -1) {
3361 view_pos = Objects[Player_ai->target_objnum].pos;
3363 // Make camera follow explosion, but gradually slow down.
3364 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3365 view_pos = Player_obj->pos;
3366 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3367 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3370 *eye_pos = Dead_camera_pos;
3372 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3374 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3379 // if supernova shockwave
3380 if(supernova_camera_cut()){
3384 // call it dead view
3385 Viewer_mode |= VM_DEAD_VIEW;
3387 // set eye pos and orient
3388 supernova_set_view(eye_pos, eye_orient);
3390 // If already blown up, these other modes can override.
3391 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3392 Viewer_mode &= ~VM_DEAD_VIEW;
3394 Viewer_obj = Player_obj;
3396 if (Viewer_mode & VM_OTHER_SHIP) {
3397 if (Player_ai->target_objnum != -1){
3398 Viewer_obj = &Objects[Player_ai->target_objnum];
3399 last_Viewer_objnum = Player_ai->target_objnum;
3401 Viewer_mode &= ~VM_OTHER_SHIP;
3402 last_Viewer_objnum = -1;
3405 last_Viewer_objnum = -1;
3408 if (Viewer_mode & VM_EXTERNAL) {
3411 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3412 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3414 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3416 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3417 vm_vec_normalize(&eye_dir);
3418 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3421 // Modify the orientation based on head orientation.
3422 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3424 } else if ( Viewer_mode & VM_CHASE ) {
3427 if ( Viewer_obj->phys_info.speed < 0.1 )
3428 move_dir = Viewer_obj->orient.fvec;
3430 move_dir = Viewer_obj->phys_info.vel;
3431 vm_vec_normalize(&move_dir);
3434 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3435 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3436 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3437 vm_vec_normalize(&eye_dir);
3439 // JAS: I added the following code because if you slew up using
3440 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3441 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3442 // call because the up and the forward vector are the same. I fixed
3443 // it by adding in a fraction of the right vector all the time to the
3445 vector tmp_up = Viewer_obj->orient.uvec;
3446 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3448 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3451 // Modify the orientation based on head orientation.
3452 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3453 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3454 *eye_pos = Camera_pos;
3456 ship * shipp = &Ships[Player_obj->instance];
3458 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3459 vm_vec_normalize(&eye_dir);
3460 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3463 // get an eye position based upon the correct type of object
3464 switch(Viewer_obj->type){
3466 // make a call to get the eye point for the player object
3467 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3470 // make a call to get the eye point for the player object
3471 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3477 #ifdef JOHNS_DEBUG_CODE
3478 john_debug_stuff(&eye_pos, &eye_orient);
3484 apply_hud_shake(eye_orient);
3486 // setup neb2 rendering
3487 neb2_render_setup(eye_pos, eye_orient);
3491 extern void ai_debug_render_stuff();
3494 int Game_subspace_effect = 0;
3495 DCF_BOOL( subspace, Game_subspace_effect );
3497 // Does everything needed to render a frame
3498 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3502 g3_start_frame(game_zbuffer);
3503 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3505 // maybe offset the HUD (jitter stuff)
3506 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3507 HUD_set_offsets(Viewer_obj, !dont_offset);
3509 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3510 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3511 // must be done before ships are rendered
3512 if ( MULTIPLAYER_CLIENT ) {
3513 shield_point_multi_setup();
3516 if ( Game_subspace_effect ) {
3517 stars_draw(0,0,0,1);
3519 stars_draw(1,1,1,0);
3522 obj_render_all(obj_render);
3523 beam_render_all(); // render all beam weapons
3524 particle_render_all(); // render particles after everything else.
3525 trail_render_all(); // render missilie trails after everything else.
3526 mflash_render_all(); // render all muzzle flashes
3528 // Why do we not show the shield effect in these modes? Seems ok.
3529 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3533 // render nebula lightning
3536 // render local player nebula
3537 neb2_render_player();
3540 ai_debug_render_stuff();
3543 #ifndef RELEASE_REAL
3544 // game_framerate_check();
3548 extern void snd_spew_debug_info();
3549 snd_spew_debug_info();
3552 //================ END OF 3D RENDERING STUFF ====================
3556 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3557 hud_maybe_clear_head_area();
3558 anim_render_all(0, flFrametime);
3561 extern int Multi_display_netinfo;
3562 if(Multi_display_netinfo){
3563 extern void multi_display_netinfo();
3564 multi_display_netinfo();
3567 game_tst_frame_pre();
3570 do_timing_test(flFrametime);
3574 extern int OO_update_index;
3575 multi_rate_display(OO_update_index, 375, 0);
3580 extern void oo_display();
3587 //#define JOHNS_DEBUG_CODE 1
3589 #ifdef JOHNS_DEBUG_CODE
3590 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3592 //if ( keyd_pressed[KEY_LSHIFT] )
3594 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3596 model_subsystem *turret = tsys->system_info;
3598 if (turret->type == SUBSYSTEM_TURRET ) {
3600 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3602 ship_model_start(tobj);
3604 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3605 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3606 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3608 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3610 ship_model_stop(tobj);
3620 // following function for dumping frames for purposes of building trailers.
3623 // function to toggle state of dumping every frame into PCX when playing the game
3624 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3628 if ( Debug_dump_frames == 0 ) {
3630 Debug_dump_frames = 15;
3631 Debug_dump_trigger = 0;
3632 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3633 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3636 Debug_dump_frames = 0;
3637 Debug_dump_trigger = 0;
3638 gr_dump_frame_stop();
3639 dc_printf( "Frame dumping is now OFF\n" );
3645 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3649 if ( Debug_dump_frames == 0 ) {
3651 Debug_dump_frames = 15;
3652 Debug_dump_trigger = 1;
3653 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3654 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3657 Debug_dump_frames = 0;
3658 Debug_dump_trigger = 0;
3659 gr_dump_frame_stop();
3660 dc_printf( "Frame dumping is now OFF\n" );
3666 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3670 if ( Debug_dump_frames == 0 ) {
3672 Debug_dump_frames = 30;
3673 Debug_dump_trigger = 0;
3674 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3675 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3678 Debug_dump_frames = 0;
3679 Debug_dump_trigger = 0;
3680 gr_dump_frame_stop();
3681 dc_printf( "Frame dumping is now OFF\n" );
3687 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3691 if ( Debug_dump_frames == 0 ) {
3693 Debug_dump_frames = 30;
3694 Debug_dump_trigger = 1;
3695 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3696 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3699 Debug_dump_frames = 0;
3700 Debug_dump_trigger = 0;
3701 gr_dump_frame_stop();
3702 dc_printf( "Triggered frame dumping is now OFF\n" );
3708 void game_maybe_dump_frame()
3710 if ( !Debug_dump_frames ){
3714 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3721 Debug_dump_frame_num++;
3727 extern int Player_dead_state;
3729 // Flip the page and time how long it took.
3730 void game_flip_page_and_time_it()
3734 t1 = timer_get_fixed_seconds();
3736 t2 = timer_get_fixed_seconds();
3738 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3739 sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3742 void game_simulation_frame()
3744 // blow ships up in multiplayer dogfight
3745 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){
3746 // blow up all non-player ships
3747 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3750 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3752 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)){
3753 moveup = GET_NEXT(moveup);
3756 shipp = &Ships[Objects[moveup->objnum].instance];
3757 sip = &Ship_info[shipp->ship_info_index];
3759 // only blow up small ships
3760 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3761 // function to simply explode a ship where it is currently at
3762 ship_self_destruct( &Objects[moveup->objnum] );
3765 moveup = GET_NEXT(moveup);
3771 // process AWACS stuff - do this first thing
3774 // single player, set Player hits_this_frame to 0
3775 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3776 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3777 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3781 supernova_process();
3782 if(supernova_active() >= 5){
3786 // fire targeting lasers now so that
3787 // 1 - created this frame
3788 // 2 - collide this frame
3789 // 3 - render this frame
3790 // 4 - ignored and deleted next frame
3791 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3793 ship_process_targeting_lasers();
3795 // do this here so that it works for multiplayer
3797 // get viewer direction
3798 int viewer_direction = PHYSICS_VIEWER_REAR;
3800 if(Viewer_mode == 0){
3801 viewer_direction = PHYSICS_VIEWER_FRONT;
3803 if(Viewer_mode & VM_PADLOCK_UP){
3804 viewer_direction = PHYSICS_VIEWER_UP;
3806 else if(Viewer_mode & VM_PADLOCK_REAR){
3807 viewer_direction = PHYSICS_VIEWER_REAR;
3809 else if(Viewer_mode & VM_PADLOCK_LEFT){
3810 viewer_direction = PHYSICS_VIEWER_LEFT;
3812 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3813 viewer_direction = PHYSICS_VIEWER_RIGHT;
3816 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3818 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3821 #define VM_PADLOCK_UP (1 << 7)
3822 #define VM_PADLOCK_REAR (1 << 8)
3823 #define VM_PADLOCK_LEFT (1 << 9)
3824 #define VM_PADLOCK_RIGHT (1 << 10)
3826 // evaluate mission departures and arrivals before we process all objects.
3827 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3829 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3830 // ships/wing packets.
3831 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3832 mission_parse_eval_stuff();
3835 // if we're an observer, move ourselves seperately from the standard physics
3836 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3837 obj_observer_move(flFrametime);
3840 // move all the objects now
3841 obj_move_all(flFrametime);
3843 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3844 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3845 // ship_check_cargo_all();
3846 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3847 mission_eval_goals();
3851 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3852 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3853 training_check_objectives();
3856 // do all interpolation now
3857 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3858 // client side processing of warping in effect stages
3859 multi_do_client_warp(flFrametime);
3861 // client side movement of an observer
3862 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3863 obj_observer_move(flFrametime);
3866 // move all objects - does interpolation now as well
3867 obj_move_all(flFrametime);
3870 // only process the message queue when the player is "in" the game
3871 if ( !Pre_player_entry ){
3872 message_queue_process(); // process any messages send to the player
3875 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3876 message_maybe_distort(); // maybe distort incoming message if comms damaged
3877 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3878 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3879 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3882 if(!(Game_mode & GM_STANDALONE_SERVER)){
3883 // process some stuff every frame (before frame is rendered)
3884 emp_process_local();
3886 hud_update_frame(); // update hud systems
3888 if (!physics_paused) {
3889 // Move particle system
3890 particle_move_all(flFrametime);
3892 // Move missile trails
3893 trail_move_all(flFrametime);
3895 // process muzzle flashes
3896 mflash_process_all();
3898 // Flash the gun flashes
3899 shipfx_flash_do_frame(flFrametime);
3901 shockwave_move_all(flFrametime); // update all the shockwaves
3904 // subspace missile strikes
3907 obj_snd_do_frame(); // update the object-linked persistant sounds
3908 game_maybe_update_sound_environment();
3909 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3911 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3913 if ( Game_subspace_effect ) {
3914 game_start_subspace_ambient_sound();
3920 // Maybe render and process the dead-popup
3921 void game_maybe_do_dead_popup(float frametime)
3923 if ( popupdead_is_active() ) {
3925 int choice = popupdead_do_frame(frametime);
3927 if ( Game_mode & GM_NORMAL ) {
3931 if(game_do_cd_mission_check(Game_current_mission_filename)){
3932 gameseq_post_event(GS_EVENT_ENTER_GAME);
3934 gameseq_post_event(GS_EVENT_MAIN_MENU);
3939 gameseq_post_event(GS_EVENT_END_GAME);
3944 if(game_do_cd_mission_check(Game_current_mission_filename)){
3945 gameseq_post_event(GS_EVENT_START_GAME);
3947 gameseq_post_event(GS_EVENT_MAIN_MENU);
3951 // this should only happen during a red alert mission
3954 Assert(The_mission.red_alert);
3955 if(!The_mission.red_alert){
3957 if(game_do_cd_mission_check(Game_current_mission_filename)){
3958 gameseq_post_event(GS_EVENT_START_GAME);
3960 gameseq_post_event(GS_EVENT_MAIN_MENU);
3965 // choose the previous mission
3966 mission_campaign_previous_mission();
3968 if(game_do_cd_mission_check(Game_current_mission_filename)){
3969 gameseq_post_event(GS_EVENT_START_GAME);
3971 gameseq_post_event(GS_EVENT_MAIN_MENU);
3982 case POPUPDEAD_DO_MAIN_HALL:
3983 multi_quit_game(PROMPT_NONE,-1);
3986 case POPUPDEAD_DO_RESPAWN:
3987 multi_respawn_normal();
3988 event_music_player_respawn();
3991 case POPUPDEAD_DO_OBSERVER:
3992 multi_respawn_observer();
3993 event_music_player_respawn_as_observer();
4002 if ( leave_popup ) {
4008 // returns true if player is actually in a game_play stats
4009 int game_actually_playing()
4013 state = gameseq_get_state();
4014 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4020 // Draw the 2D HUD gauges
4021 void game_render_hud_2d()
4023 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4027 HUD_render_2d(flFrametime);
4031 // Draw the 3D-dependant HUD gauges
4032 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4034 g3_start_frame(0); // 0 = turn zbuffering off
4035 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4037 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4038 HUD_render_3d(flFrametime);
4042 game_sunspot_process(flFrametime);
4044 // Diminish the palette effect
4045 game_flash_diminish(flFrametime);
4053 int actually_playing;
4054 fix total_time1, total_time2;
4055 fix render2_time1=0, render2_time2=0;
4056 fix render3_time1=0, render3_time2=0;
4057 fix flip_time1=0, flip_time2=0;
4058 fix clear_time1=0, clear_time2=0;
4064 if (Framerate_delay) {
4065 int start_time = timer_get_milliseconds();
4066 while (timer_get_milliseconds() < start_time + Framerate_delay)
4072 demo_do_frame_start();
4074 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4079 // start timing frame
4080 timing_frame_start();
4082 total_time1 = timer_get_fixed_seconds();
4084 // var to hold which state we are in
4085 actually_playing = game_actually_playing();
4087 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4088 if (!(Game_mode & GM_STANDALONE_SERVER)){
4089 Assert( OBJ_INDEX(Player_obj) >= 0 );
4093 if (Missiontime > Entry_delay_time){
4094 Pre_player_entry = 0;
4096 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4099 // Note: These are done even before the player enters, else buffers can overflow.
4100 if (! (Game_mode & GM_STANDALONE_SERVER)){
4104 shield_frame_init();
4106 if ( Player->control_mode != PCM_NORMAL )
4109 if ( !Pre_player_entry && actually_playing ) {
4110 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4112 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4113 game_process_keys();
4115 // don't read flying controls if we're playing a demo back
4116 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4117 read_player_controls( Player_obj, flFrametime);
4121 // if we're not the master, we may have to send the server-critical ship status button_info bits
4122 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4123 multi_maybe_send_ship_status();
4128 // Reset the whack stuff
4131 // These two lines must be outside of Pre_player_entry code,
4132 // otherwise too many lights are added.
4135 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4139 game_simulation_frame();
4141 // if not actually in a game play state, then return. This condition could only be true in
4142 // a multiplayer game.
4143 if ( !actually_playing ) {
4144 Assert( Game_mode & GM_MULTIPLAYER );
4148 if (!Pre_player_entry) {
4149 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4150 clear_time1 = timer_get_fixed_seconds();
4151 // clear the screen to black
4153 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4157 clear_time2 = timer_get_fixed_seconds();
4158 render3_time1 = timer_get_fixed_seconds();
4159 game_render_frame_setup(&eye_pos, &eye_orient);
4160 game_render_frame( &eye_pos, &eye_orient );
4162 // save the eye position and orientation
4163 if ( Game_mode & GM_MULTIPLAYER ) {
4164 Net_player->s_info.eye_pos = eye_pos;
4165 Net_player->s_info.eye_orient = eye_orient;
4168 hud_show_target_model();
4170 // check to see if we should display the death died popup
4171 if(Game_mode & GM_DEAD_BLEW_UP){
4172 if(Game_mode & GM_MULTIPLAYER){
4173 // catch the situation where we're supposed to be warping out on this transition
4174 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4175 gameseq_post_event(GS_EVENT_DEBRIEF);
4176 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4177 Player_died_popup_wait = -1;
4181 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4182 Player_died_popup_wait = -1;
4188 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4189 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4190 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4191 if(!popupdead_is_active()){
4195 Player_multi_died_check = -1;
4199 render3_time2 = timer_get_fixed_seconds();
4200 render2_time1 = timer_get_fixed_seconds();
4203 game_get_framerate();
4204 game_show_framerate();
4206 game_show_time_left();
4208 // Draw the 2D HUD gauges
4209 if(supernova_active() < 3){
4210 game_render_hud_2d();
4213 game_set_view_clip();
4215 // Draw 3D HUD gauges
4216 game_render_hud_3d(&eye_pos, &eye_orient);
4220 render2_time2 = timer_get_fixed_seconds();
4222 // maybe render and process the dead popup
4223 game_maybe_do_dead_popup(flFrametime);
4225 // start timing frame
4226 timing_frame_stop();
4227 // timing_display(30, 10);
4229 // If a regular popup is active, don't flip (popup code flips)
4230 if( !popup_running_state() ){
4231 flip_time1 = timer_get_fixed_seconds();
4232 game_flip_page_and_time_it();
4233 flip_time2 = timer_get_fixed_seconds();
4237 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4240 game_show_standalone_framerate();
4244 game_do_training_checks();
4247 // process lightning (nebula only)
4250 total_time2 = timer_get_fixed_seconds();
4252 // Got some timing numbers
4253 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4254 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4255 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4256 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4257 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4260 demo_do_frame_end();
4262 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4268 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4269 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4270 // died. This resulted in screwed up death sequences.
4272 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4273 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4274 static int timer_paused=0;
4275 static int stop_count,start_count;
4276 static int time_stopped,time_started;
4277 int saved_timestamp_ticker = -1;
4279 void game_reset_time()
4281 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4285 // Last_time = timer_get_fixed_seconds();
4291 void game_stop_time()
4293 if (timer_paused==0) {
4295 time = timer_get_fixed_seconds();
4296 // Save how much time progressed so far in the frame so we can
4297 // use it when we unpause.
4298 Last_delta_time = time - Last_time;
4300 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4301 if (Last_delta_time < 0) {
4302 #if defined(TIMER_TEST) && !defined(NDEBUG)
4303 Int3(); //get Matt!!!!
4305 Last_delta_time = 0;
4307 #if defined(TIMER_TEST) && !defined(NDEBUG)
4308 time_stopped = time;
4311 // Stop the timer_tick stuff...
4312 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4313 saved_timestamp_ticker = timestamp_ticker;
4317 #if defined(TIMER_TEST) && !defined(NDEBUG)
4322 void game_start_time()
4325 Assert(timer_paused >= 0);
4326 if (timer_paused==0) {
4328 time = timer_get_fixed_seconds();
4329 #if defined(TIMER_TEST) && !defined(NDEBUG)
4331 Int3(); //get Matt!!!!
4334 // Take current time, and set it backwards to account for time
4335 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4336 // will be correct when it goes to calculate the frametime next
4338 Last_time = time - Last_delta_time;
4339 #if defined(TIMER_TEST) && !defined(NDEBUG)
4340 time_started = time;
4343 // Restore the timer_tick stuff...
4344 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4345 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4346 timestamp_ticker = saved_timestamp_ticker;
4347 saved_timestamp_ticker = -1;
4350 #if defined(TIMER_TEST) && !defined(NDEBUG)
4356 void game_set_frametime(int state)
4359 float frame_cap_diff;
4361 thistime = timer_get_fixed_seconds();
4363 if ( Last_time == 0 )
4364 Frametime = F1_0 / 30;
4366 Frametime = thistime - Last_time;
4368 // Frametime = F1_0 / 30;
4370 fix debug_frametime = Frametime; // Just used to display frametime.
4372 // If player hasn't entered mission yet, make frame take 1/4 second.
4373 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4376 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4378 fix frame_speed = F1_0 / Debug_dump_frames;
4380 if (Frametime > frame_speed ){
4381 nprintf(("warning","slow frame: %x\n",Frametime));
4384 thistime = timer_get_fixed_seconds();
4385 Frametime = thistime - Last_time;
4386 } while (Frametime < frame_speed );
4388 Frametime = frame_speed;
4392 Assert( Framerate_cap > 0 );
4394 // Cap the framerate so it doesn't get too high.
4398 cap = F1_0/Framerate_cap;
4399 if (Frametime < cap) {
4400 thistime = cap - Frametime;
4401 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4402 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4404 thistime = timer_get_fixed_seconds();
4408 if((Game_mode & GM_STANDALONE_SERVER) &&
4409 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4411 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4412 Sleep((DWORD)(frame_cap_diff*1000));
4414 thistime += fl2f((frame_cap_diff));
4416 Frametime = thistime - Last_time;
4419 // If framerate is too low, cap it.
4420 if (Frametime > MAX_FRAMETIME) {
4422 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4424 // to remove warnings in release build
4425 debug_frametime = fl2f(flFrametime);
4427 Frametime = MAX_FRAMETIME;
4430 Frametime = fixmul(Frametime, Game_time_compression);
4432 Last_time = thistime;
4433 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4435 flFrametime = f2fl(Frametime);
4436 //if(!(Game_mode & GM_PLAYING_DEMO)){
4437 timestamp_inc(flFrametime);
4439 /* if ((Framecount > 0) && (Framecount < 10)) {
4440 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4445 // This is called from game_do_frame(), and from navmap_do_frame()
4446 void game_update_missiontime()
4448 // TODO JAS: Put in if and move this into game_set_frametime,
4449 // fix navmap to call game_stop/start_time
4450 //if ( !timer_paused )
4451 Missiontime += Frametime;
4454 void game_do_frame()
4456 game_set_frametime(GS_STATE_GAME_PLAY);
4457 game_update_missiontime();
4459 if (Game_mode & GM_STANDALONE_SERVER) {
4460 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4463 if ( game_single_step && (last_single_step == game_single_step) ) {
4464 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4465 while( key_checkch() == 0 )
4467 os_set_title( XSTR( "FreeSpace", 171) );
4468 Last_time = timer_get_fixed_seconds();
4471 last_single_step = game_single_step;
4473 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4474 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4478 Keep_mouse_centered = 0;
4479 monitor_update(); // Update monitor variables
4482 void multi_maybe_do_frame()
4484 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4489 int Joymouse_button_status = 0;
4491 // Flush all input devices
4499 Joymouse_button_status = 0;
4501 //mprintf(("Game flush!\n" ));
4504 // function for multiplayer only which calls game_do_state_common() when running the
4506 void game_do_dc_networking()
4508 Assert( Game_mode & GM_MULTIPLAYER );
4510 game_do_state_common( gameseq_get_state() );
4513 // Call this whenever in a loop, or when you need to check for a keystroke.
4514 int game_check_key()
4520 // convert keypad enter to normal enter
4521 if ((k & KEY_MASK) == KEY_PADENTER)
4522 k = (k & ~KEY_MASK) | KEY_ENTER;
4529 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4530 static int Demo_show_trailer_timestamp = 0;
4532 void demo_reset_trailer_timer()
4534 Demo_show_trailer_timestamp = timer_get_milliseconds();
4537 void demo_maybe_show_trailer(int k)
4540 // if key pressed, reset demo trailer timer
4542 demo_reset_trailer_timer();
4546 // if mouse moved, reset demo trailer timer
4549 mouse_get_delta(&dx, &dy);
4550 if ( (dx > 0) || (dy > 0) ) {
4551 demo_reset_trailer_timer();
4555 // if joystick has moved, reset demo trailer timer
4558 joy_get_delta(&dx, &dy);
4559 if ( (dx > 0) || (dy > 0) ) {
4560 demo_reset_trailer_timer();
4564 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4565 // the low-level code. Ugly, I know... but was the simplest and most
4568 // if 30 seconds since last demo trailer time reset, launch movie
4569 if ( os_foreground() ) {
4570 int now = timer_get_milliseconds();
4571 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4572 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4574 movie_play( NOX("fstrailer2.mve") );
4575 demo_reset_trailer_timer();
4583 // same as game_check_key(), except this is used while actually in the game. Since there
4584 // generally are differences between game control keys and general UI keys, makes sense to
4585 // have seperate functions for each case. If you are not checking a game control while in a
4586 // mission, you should probably be using game_check_key() instead.
4591 if (!os_foreground()) {
4596 // If we're in a single player game, pause it.
4597 if (!(Game_mode & GM_MULTIPLAYER)){
4598 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4599 game_process_pause_key();
4607 demo_maybe_show_trailer(k);
4610 // Move the mouse cursor with the joystick.
4611 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4612 // Move the mouse cursor with the joystick
4616 joy_get_pos( &jx, &jy, &jz, &jr );
4618 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4619 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4622 mouse_get_real_pos( &mx, &my );
4623 mouse_set_pos( mx+dx, my+dy );
4628 m = mouse_down(MOUSE_LEFT_BUTTON);
4630 if ( j != Joymouse_button_status ) {
4631 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4632 Joymouse_button_status = j;
4634 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4635 } else if ( (!j) && (m) ) {
4636 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4641 // if we should be ignoring keys because of some multiplayer situations
4642 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4646 // If a popup is running, don't process all the Fn keys
4647 if( popup_active() ) {
4651 state = gameseq_get_state();
4653 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4656 case KEY_DEBUGGED + KEY_BACKSP:
4661 launch_context_help();
4666 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4668 // don't allow f2 while warping out in multiplayer
4669 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4674 case GS_STATE_INITIAL_PLAYER_SELECT:
4675 case GS_STATE_OPTIONS_MENU:
4676 case GS_STATE_HUD_CONFIG:
4677 case GS_STATE_CONTROL_CONFIG:
4678 case GS_STATE_DEATH_DIED:
4679 case GS_STATE_DEATH_BLEW_UP:
4680 case GS_STATE_VIEW_MEDALS:
4684 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4691 // hotkey selection screen -- only valid from briefing and beyond.
4694 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) ) {
4695 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4701 case KEY_DEBUGGED + KEY_F3:
4702 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4705 case KEY_DEBUGGED + KEY_F4:
4706 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4710 if(Game_mode & GM_MULTIPLAYER){
4711 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4712 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4716 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4717 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4723 case KEY_ESC | KEY_SHIFTED:
4724 // make sure to quit properly out of multiplayer
4725 if(Game_mode & GM_MULTIPLAYER){
4726 multi_quit_game(PROMPT_NONE);
4729 gameseq_post_event( GS_EVENT_QUIT_GAME );
4734 case KEY_DEBUGGED + KEY_P:
4737 case KEY_PRINT_SCRN:
4739 static int counter = 0;
4744 sprintf( tmp_name, NOX("screen%02d"), counter );
4746 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4747 gr_print_screen(tmp_name);
4755 case KEY_SHIFTED | KEY_ENTER: {
4757 #if !defined(NDEBUG)
4759 if ( Game_mode & GM_NORMAL ){
4763 // if we're in multiplayer mode, do some special networking
4764 if(Game_mode & GM_MULTIPLAYER){
4765 debug_console(game_do_dc_networking);
4772 if ( Game_mode & GM_NORMAL )
4786 gameseq_post_event(GS_EVENT_QUIT_GAME);
4789 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4792 void camera_set_position( vector *pos )
4797 void camera_set_orient( matrix *orient )
4799 Camera_orient = *orient;
4802 void camera_set_velocity( vector *vel, int instantaneous )
4804 Camera_desired_velocity.x = 0.0f;
4805 Camera_desired_velocity.y = 0.0f;
4806 Camera_desired_velocity.z = 0.0f;
4808 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4809 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4810 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4812 if ( instantaneous ) {
4813 Camera_velocity = Camera_desired_velocity;
4821 vector new_vel, delta_pos;
4823 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4824 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4825 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4827 Camera_velocity = new_vel;
4829 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4831 vm_vec_add2( &Camera_pos, &delta_pos );
4833 float ot = Camera_time+0.0f;
4835 Camera_time += flFrametime;
4837 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4840 tmp.z = 4.739f; // always go this fast forward.
4842 // pick x and y velocities so they are always on a
4843 // circle with a 25 m radius.
4845 float tmp_angle = frand()*PI2;
4847 tmp.x = 22.0f * (float)sin(tmp_angle);
4848 tmp.y = -22.0f * (float)cos(tmp_angle);
4850 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4852 //mprintf(( "Changing velocity!\n" ));
4853 camera_set_velocity( &tmp, 0 );
4856 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4857 vector tmp = { 0.0f, 0.0f, 0.0f };
4858 camera_set_velocity( &tmp, 0 );
4863 void end_demo_campaign_do()
4865 #if defined(FS2_DEMO)
4866 // show upsell screens
4867 demo_upsell_show_screens();
4868 #elif defined(OEM_BUILD)
4869 // show oem upsell screens
4870 oem_upsell_show_screens();
4873 // drop into main hall
4874 gameseq_post_event( GS_EVENT_MAIN_MENU );
4877 // All code to process events. This is the only place
4878 // that you should change the state of the game.
4879 void game_process_event( int current_state, int event )
4881 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4884 case GS_EVENT_SIMULATOR_ROOM:
4885 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4888 case GS_EVENT_MAIN_MENU:
4889 gameseq_set_state(GS_STATE_MAIN_MENU);
4892 case GS_EVENT_OPTIONS_MENU:
4893 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4896 case GS_EVENT_BARRACKS_MENU:
4897 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4900 case GS_EVENT_TECH_MENU:
4901 gameseq_set_state(GS_STATE_TECH_MENU);
4904 case GS_EVENT_TRAINING_MENU:
4905 gameseq_set_state(GS_STATE_TRAINING_MENU);
4908 case GS_EVENT_START_GAME:
4909 Select_default_ship = 0;
4910 Player_multi_died_check = -1;
4911 gameseq_set_state(GS_STATE_CMD_BRIEF);
4914 case GS_EVENT_START_BRIEFING:
4915 gameseq_set_state(GS_STATE_BRIEFING);
4918 case GS_EVENT_DEBRIEF:
4919 // did we end the campaign in the main freespace 2 single player campaign?
4920 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4921 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4923 gameseq_set_state(GS_STATE_DEBRIEF);
4926 Player_multi_died_check = -1;
4929 case GS_EVENT_SHIP_SELECTION:
4930 gameseq_set_state( GS_STATE_SHIP_SELECT );
4933 case GS_EVENT_WEAPON_SELECTION:
4934 gameseq_set_state( GS_STATE_WEAPON_SELECT );
4937 case GS_EVENT_ENTER_GAME:
4939 // maybe start recording a demo
4941 demo_start_record("test.fsd");
4945 if (Game_mode & GM_MULTIPLAYER) {
4946 // if we're respawning, make sure we change the view mode so that the hud shows up
4947 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4951 gameseq_set_state(GS_STATE_GAME_PLAY);
4953 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4956 Player_multi_died_check = -1;
4958 // clear multiplayer button info
4959 extern button_info Multi_ship_status_bi;
4960 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4962 Start_time = f2fl(timer_get_approx_seconds());
4964 mprintf(("Entering game at time = %7.3f\n", Start_time));
4968 case GS_EVENT_START_GAME_QUICK:
4969 Select_default_ship = 1;
4970 gameseq_post_event(GS_EVENT_ENTER_GAME);
4974 case GS_EVENT_END_GAME:
4975 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4976 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4977 gameseq_set_state(GS_STATE_MAIN_MENU);
4982 Player_multi_died_check = -1;
4985 case GS_EVENT_QUIT_GAME:
4986 main_hall_stop_music();
4987 main_hall_stop_ambient();
4988 gameseq_set_state(GS_STATE_QUIT_GAME);
4990 Player_multi_died_check = -1;
4993 case GS_EVENT_GAMEPLAY_HELP:
4994 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
4997 case GS_EVENT_PAUSE_GAME:
4998 gameseq_push_state(GS_STATE_GAME_PAUSED);
5001 case GS_EVENT_DEBUG_PAUSE_GAME:
5002 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5005 case GS_EVENT_TRAINING_PAUSE:
5006 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5009 case GS_EVENT_PREVIOUS_STATE:
5010 gameseq_pop_state();
5013 case GS_EVENT_TOGGLE_FULLSCREEN:
5014 #ifndef HARDWARE_ONLY
5016 if ( gr_screen.mode == GR_SOFTWARE ) {
5017 gr_init( GR_640, GR_DIRECTDRAW );
5018 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5019 gr_init( GR_640, GR_SOFTWARE );
5025 case GS_EVENT_TOGGLE_GLIDE:
5027 if ( gr_screen.mode != GR_GLIDE ) {
5028 gr_init( GR_640, GR_GLIDE );
5030 gr_init( GR_640, GR_SOFTWARE );
5035 case GS_EVENT_LOAD_MISSION_MENU:
5036 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5039 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5040 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5043 case GS_EVENT_HUD_CONFIG:
5044 gameseq_push_state( GS_STATE_HUD_CONFIG );
5047 case GS_EVENT_CONTROL_CONFIG:
5048 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5051 case GS_EVENT_DEATH_DIED:
5052 gameseq_set_state( GS_STATE_DEATH_DIED );
5055 case GS_EVENT_DEATH_BLEW_UP:
5056 if ( current_state == GS_STATE_DEATH_DIED ) {
5057 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5058 event_music_player_death();
5060 // multiplayer clients set their extra check here
5061 if(Game_mode & GM_MULTIPLAYER){
5062 // set the multi died absolute last chance check
5063 Player_multi_died_check = time(NULL);
5066 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5070 case GS_EVENT_NEW_CAMPAIGN:
5071 if (!mission_load_up_campaign()){
5072 readyroom_continue_campaign();
5075 Player_multi_died_check = -1;
5078 case GS_EVENT_CAMPAIGN_CHEAT:
5079 if (!mission_load_up_campaign()){
5081 // bash campaign value
5082 extern char Main_hall_campaign_cheat[512];
5085 // look for the mission
5086 for(idx=0; idx<Campaign.num_missions; idx++){
5087 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5088 Campaign.next_mission = idx;
5089 Campaign.prev_mission = idx - 1;
5096 readyroom_continue_campaign();
5099 Player_multi_died_check = -1;
5102 case GS_EVENT_CAMPAIGN_ROOM:
5103 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5106 case GS_EVENT_CMD_BRIEF:
5107 gameseq_set_state(GS_STATE_CMD_BRIEF);
5110 case GS_EVENT_RED_ALERT:
5111 gameseq_set_state(GS_STATE_RED_ALERT);
5114 case GS_EVENT_CREDITS:
5115 gameseq_set_state( GS_STATE_CREDITS );
5118 case GS_EVENT_VIEW_MEDALS:
5119 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5122 case GS_EVENT_SHOW_GOALS:
5123 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5126 case GS_EVENT_HOTKEY_SCREEN:
5127 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5130 // multiplayer stuff follow these comments
5132 case GS_EVENT_MULTI_JOIN_GAME:
5133 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5136 case GS_EVENT_MULTI_HOST_SETUP:
5137 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5140 case GS_EVENT_MULTI_CLIENT_SETUP:
5141 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5144 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5145 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5148 case GS_EVENT_MULTI_STD_WAIT:
5149 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5152 case GS_EVENT_STANDALONE_MAIN:
5153 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5156 case GS_EVENT_MULTI_PAUSE:
5157 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5160 case GS_EVENT_INGAME_PRE_JOIN:
5161 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5164 case GS_EVENT_EVENT_DEBUG:
5165 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5168 // Start a warpout where player automatically goes 70 no matter what
5169 // and can't cancel out of it.
5170 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5171 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5173 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5174 Player->saved_viewer_mode = Viewer_mode;
5175 Player->control_mode = PCM_WARPOUT_STAGE1;
5176 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5177 Warpout_time = 0.0f; // Start timer!
5180 case GS_EVENT_PLAYER_WARPOUT_START:
5181 if ( Player->control_mode != PCM_NORMAL ) {
5182 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5184 Player->saved_viewer_mode = Viewer_mode;
5185 Player->control_mode = PCM_WARPOUT_STAGE1;
5186 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5187 Warpout_time = 0.0f; // Start timer!
5188 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5192 case GS_EVENT_PLAYER_WARPOUT_STOP:
5193 if ( Player->control_mode != PCM_NORMAL ) {
5194 if ( !Warpout_forced ) { // cannot cancel forced warpout
5195 Player->control_mode = PCM_NORMAL;
5196 Viewer_mode = Player->saved_viewer_mode;
5197 hud_subspace_notify_abort();
5198 mprintf(( "Player put back to normal mode.\n" ));
5199 if ( Warpout_sound > -1 ) {
5200 snd_stop( Warpout_sound );
5207 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5208 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5209 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5210 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5212 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5213 shipfx_warpout_start( Player_obj );
5214 Player->control_mode = PCM_WARPOUT_STAGE2;
5215 Player->saved_viewer_mode = Viewer_mode;
5216 Viewer_mode |= VM_WARP_CHASE;
5218 vector tmp = Player_obj->pos;
5220 ship_get_eye( &tmp, &tmp_m, Player_obj );
5221 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5222 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5223 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5225 camera_set_position( &tmp );
5226 camera_set_orient( &Player_obj->orient );
5227 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5229 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5230 camera_set_velocity( &tmp_vel, 1);
5234 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5235 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5236 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5237 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5239 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5240 Player->control_mode = PCM_WARPOUT_STAGE3;
5244 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5245 mprintf(( "Player warped out. Going to debriefing!\n" ));
5246 Player->control_mode = PCM_NORMAL;
5247 Viewer_mode = Player->saved_viewer_mode;
5250 // we have a special debriefing screen for multiplayer furballs
5251 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5252 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5254 // do the normal debriefing for all other situations
5256 gameseq_post_event(GS_EVENT_DEBRIEF);
5260 case GS_EVENT_STANDALONE_POSTGAME:
5261 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5264 case GS_EVENT_INITIAL_PLAYER_SELECT:
5265 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5268 case GS_EVENT_GAME_INIT:
5269 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5270 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5272 // see if the command line option has been set to use the last pilot, and act acoordingly
5273 if( player_select_get_last_pilot() ) {
5274 // always enter the main menu -- do the automatic network startup stuff elsewhere
5275 // so that we still have valid checks for networking modes, etc.
5276 gameseq_set_state(GS_STATE_MAIN_MENU);
5278 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5283 case GS_EVENT_MULTI_MISSION_SYNC:
5284 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5287 case GS_EVENT_MULTI_START_GAME:
5288 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5291 case GS_EVENT_MULTI_HOST_OPTIONS:
5292 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5295 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5296 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5299 case GS_EVENT_TEAM_SELECT:
5300 gameseq_set_state(GS_STATE_TEAM_SELECT);
5303 case GS_EVENT_END_CAMPAIGN:
5304 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5307 case GS_EVENT_END_DEMO:
5308 gameseq_set_state(GS_STATE_END_DEMO);
5311 case GS_EVENT_LOOP_BRIEF:
5312 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5321 // Called when a state is being left.
5322 // The current state is still at old_state, but as soon as
5323 // this function leaves, then the current state will become
5324 // new state. You should never try to change the state
5325 // in here... if you think you need to, you probably really
5326 // need to post an event, not change the state.
5327 void game_leave_state( int old_state, int new_state )
5329 int end_mission = 1;
5331 switch (new_state) {
5332 case GS_STATE_GAME_PAUSED:
5333 case GS_STATE_DEBUG_PAUSED:
5334 case GS_STATE_OPTIONS_MENU:
5335 case GS_STATE_CONTROL_CONFIG:
5336 case GS_STATE_MISSION_LOG_SCROLLBACK:
5337 case GS_STATE_DEATH_DIED:
5338 case GS_STATE_SHOW_GOALS:
5339 case GS_STATE_HOTKEY_SCREEN:
5340 case GS_STATE_MULTI_PAUSED:
5341 case GS_STATE_TRAINING_PAUSED:
5342 case GS_STATE_EVENT_DEBUG:
5343 case GS_STATE_GAMEPLAY_HELP:
5344 end_mission = 0; // these events shouldn't end a mission
5348 switch (old_state) {
5349 case GS_STATE_BRIEFING:
5350 brief_stop_voices();
5351 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5352 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5353 && (new_state != GS_STATE_TEAM_SELECT) ){
5354 common_select_close();
5355 if ( new_state == GS_STATE_MAIN_MENU ) {
5356 freespace_stop_mission();
5360 // COMMAND LINE OPTION
5361 if (Cmdline_multi_stream_chat_to_file){
5362 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5363 cfclose(Multi_chat_stream);
5367 case GS_STATE_DEBRIEF:
5368 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5373 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5374 multi_df_debrief_close();
5377 case GS_STATE_LOAD_MISSION_MENU:
5378 mission_load_menu_close();
5381 case GS_STATE_SIMULATOR_ROOM:
5385 case GS_STATE_CAMPAIGN_ROOM:
5386 campaign_room_close();
5389 case GS_STATE_CMD_BRIEF:
5390 if (new_state == GS_STATE_OPTIONS_MENU) {
5395 if (new_state == GS_STATE_MAIN_MENU)
5396 freespace_stop_mission();
5401 case GS_STATE_RED_ALERT:
5405 case GS_STATE_SHIP_SELECT:
5406 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5407 new_state != GS_STATE_HOTKEY_SCREEN &&
5408 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5409 common_select_close();
5410 if ( new_state == GS_STATE_MAIN_MENU ) {
5411 freespace_stop_mission();
5416 case GS_STATE_WEAPON_SELECT:
5417 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5418 new_state != GS_STATE_HOTKEY_SCREEN &&
5419 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5420 common_select_close();
5421 if ( new_state == GS_STATE_MAIN_MENU ) {
5422 freespace_stop_mission();
5427 case GS_STATE_TEAM_SELECT:
5428 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5429 new_state != GS_STATE_HOTKEY_SCREEN &&
5430 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5431 common_select_close();
5432 if ( new_state == GS_STATE_MAIN_MENU ) {
5433 freespace_stop_mission();
5438 case GS_STATE_MAIN_MENU:
5439 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5446 case GS_STATE_OPTIONS_MENU:
5447 //game_start_time();
5448 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5449 multi_join_clear_game_list();
5451 options_menu_close();
5454 case GS_STATE_BARRACKS_MENU:
5455 if(new_state != GS_STATE_VIEW_MEDALS){
5460 case GS_STATE_MISSION_LOG_SCROLLBACK:
5461 hud_scrollback_close();
5464 case GS_STATE_TRAINING_MENU:
5465 training_menu_close();
5468 case GS_STATE_GAME_PLAY:
5469 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5470 player_save_target_and_weapon_link_prefs();
5471 game_stop_looped_sounds();
5474 sound_env_disable();
5475 joy_ff_stop_effects();
5477 // stop game time under certain conditions
5478 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5483 // shut down any recording or playing demos
5488 // when in multiplayer and going back to the main menu, send a leave game packet
5489 // right away (before calling stop mission). stop_mission was taking to long to
5490 // close mission down and I want people to get notified ASAP.
5491 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5492 multi_quit_game(PROMPT_NONE);
5495 freespace_stop_mission();
5496 Game_time_compression = F1_0;
5500 case GS_STATE_TECH_MENU:
5504 case GS_STATE_TRAINING_PAUSED:
5505 Training_num_lines = 0;
5506 // fall through to GS_STATE_GAME_PAUSED
5508 case GS_STATE_GAME_PAUSED:
5510 if ( end_mission ) {
5515 case GS_STATE_DEBUG_PAUSED:
5518 pause_debug_close();
5522 case GS_STATE_HUD_CONFIG:
5526 // join/start a game
5527 case GS_STATE_MULTI_JOIN_GAME:
5528 if(new_state != GS_STATE_OPTIONS_MENU){
5529 multi_join_game_close();
5533 case GS_STATE_MULTI_HOST_SETUP:
5534 case GS_STATE_MULTI_CLIENT_SETUP:
5535 // if this is just the host going into the options screen, don't do anything
5536 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5540 // close down the proper state
5541 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5542 multi_create_game_close();
5544 multi_game_client_setup_close();
5547 // COMMAND LINE OPTION
5548 if (Cmdline_multi_stream_chat_to_file){
5549 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5550 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5551 cfclose(Multi_chat_stream);
5556 case GS_STATE_CONTROL_CONFIG:
5557 control_config_close();
5560 case GS_STATE_DEATH_DIED:
5561 Game_mode &= ~GM_DEAD_DIED;
5563 // early end while respawning or blowing up in a multiplayer game
5564 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5566 freespace_stop_mission();
5570 case GS_STATE_DEATH_BLEW_UP:
5571 Game_mode &= ~GM_DEAD_BLEW_UP;
5573 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5574 // to determine if I should do anything.
5575 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5577 freespace_stop_mission();
5580 // if we are not respawing as an observer or as a player, our new state will not
5581 // be gameplay state.
5582 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5583 game_stop_time(); // hasn't been called yet!!
5584 freespace_stop_mission();
5590 case GS_STATE_CREDITS:
5594 case GS_STATE_VIEW_MEDALS:
5598 case GS_STATE_SHOW_GOALS:
5599 mission_show_goals_close();
5602 case GS_STATE_HOTKEY_SCREEN:
5603 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5604 mission_hotkey_close();
5608 case GS_STATE_MULTI_MISSION_SYNC:
5609 // if we're moving into the options menu, don't do anything
5610 if(new_state == GS_STATE_OPTIONS_MENU){
5614 Assert( Game_mode & GM_MULTIPLAYER );
5616 if ( new_state == GS_STATE_GAME_PLAY ){
5617 // palette_restore_palette();
5619 // change a couple of flags to indicate our state!!!
5620 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5621 send_netplayer_update_packet();
5623 // set the game mode
5624 Game_mode |= GM_IN_MISSION;
5628 case GS_STATE_VIEW_CUTSCENES:
5629 cutscenes_screen_close();
5632 case GS_STATE_MULTI_STD_WAIT:
5633 multi_standalone_wait_close();
5636 case GS_STATE_STANDALONE_MAIN:
5637 standalone_main_close();
5638 if(new_state == GS_STATE_MULTI_STD_WAIT){
5639 init_multiplayer_stats();
5643 case GS_STATE_MULTI_PAUSED:
5644 // if ( end_mission ){
5649 case GS_STATE_INGAME_PRE_JOIN:
5650 multi_ingame_select_close();
5653 case GS_STATE_STANDALONE_POSTGAME:
5654 multi_standalone_postgame_close();
5657 case GS_STATE_INITIAL_PLAYER_SELECT:
5658 player_select_close();
5661 case GS_STATE_MULTI_START_GAME:
5662 multi_start_game_close();
5665 case GS_STATE_MULTI_HOST_OPTIONS:
5666 multi_host_options_close();
5669 case GS_STATE_END_OF_CAMPAIGN:
5670 mission_campaign_end_close();
5673 case GS_STATE_LOOP_BRIEF:
5679 // Called when a state is being entered.
5680 // The current state is set to the state we're entering at
5681 // this point, and old_state is set to the state we're coming
5682 // from. You should never try to change the state
5683 // in here... if you think you need to, you probably really
5684 // need to post an event, not change the state.
5686 void game_enter_state( int old_state, int new_state )
5688 switch (new_state) {
5689 case GS_STATE_MAIN_MENU:
5690 // in multiplayer mode, be sure that we are not doing networking anymore.
5691 if ( Game_mode & GM_MULTIPLAYER ) {
5692 Assert( Net_player != NULL );
5693 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5696 Game_time_compression = F1_0;
5698 // determine which ship this guy is currently based on
5699 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5702 if (Player->on_bastion) {
5710 case GS_STATE_BRIEFING:
5711 main_hall_stop_music();
5712 main_hall_stop_ambient();
5714 if (Game_mode & GM_NORMAL) {
5715 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5716 // MWA: or from options or hotkey screens
5717 // JH: or if the command brief state already did this
5718 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5719 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5720 && (old_state != GS_STATE_CMD_BRIEF) ) {
5721 if ( !game_start_mission() ) // this should put us into a new state on failure!
5725 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5726 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5727 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5729 Game_time_compression = F1_0;
5731 if ( red_alert_mission() ) {
5732 gameseq_post_event(GS_EVENT_RED_ALERT);
5739 case GS_STATE_DEBRIEF:
5740 game_stop_looped_sounds();
5741 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5742 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5747 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5748 multi_df_debrief_init();
5751 case GS_STATE_LOAD_MISSION_MENU:
5752 mission_load_menu_init();
5755 case GS_STATE_SIMULATOR_ROOM:
5759 case GS_STATE_CAMPAIGN_ROOM:
5760 campaign_room_init();
5763 case GS_STATE_RED_ALERT:
5764 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5768 case GS_STATE_CMD_BRIEF: {
5769 int team_num = 0; // team number used as index for which cmd brief to use.
5771 if (old_state == GS_STATE_OPTIONS_MENU) {
5775 main_hall_stop_music();
5776 main_hall_stop_ambient();
5778 if (Game_mode & GM_NORMAL) {
5779 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5780 // MWA: or from options or hotkey screens
5781 // JH: or if the command brief state already did this
5782 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5783 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5784 if ( !game_start_mission() ) // this should put us into a new state on failure!
5789 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5790 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5791 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5793 cmd_brief_init(team_num);
5799 case GS_STATE_SHIP_SELECT:
5803 case GS_STATE_WEAPON_SELECT:
5804 weapon_select_init();
5807 case GS_STATE_TEAM_SELECT:
5811 case GS_STATE_GAME_PAUSED:
5816 case GS_STATE_DEBUG_PAUSED:
5817 // game_stop_time();
5818 // os_set_title("FreeSpace - PAUSED");
5821 case GS_STATE_TRAINING_PAUSED:
5828 case GS_STATE_OPTIONS_MENU:
5830 options_menu_init();
5833 case GS_STATE_GAME_PLAY:
5834 // coming from the gameplay state or the main menu, we might need to load the mission
5835 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5836 if ( !game_start_mission() ) // this should put us into a new state.
5841 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5842 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5843 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5844 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5845 (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) ) {
5846 // JAS: Used to do all paging here.
5850 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5854 main_hall_stop_music();
5855 main_hall_stop_ambient();
5856 event_music_first_pattern(); // start the first pattern
5859 // special code that restores player ship selection and weapons loadout when doing a quick start
5860 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5861 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5862 wss_direct_restore_loadout();
5866 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5867 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5868 event_music_first_pattern(); // start the first pattern
5871 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5872 event_music_first_pattern(); // start the first pattern
5874 player_restore_target_and_weapon_link_prefs();
5876 Game_mode |= GM_IN_MISSION;
5879 // required to truely make mouse deltas zeroed in debug mouse code
5880 void mouse_force_pos(int x, int y);
5881 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5886 // only start time if in single player, or coming from multi wait state
5889 (Game_mode & GM_NORMAL) &&
5890 (old_state != GS_STATE_VIEW_CUTSCENES)
5892 (Game_mode & GM_MULTIPLAYER) && (
5893 (old_state == GS_STATE_MULTI_PAUSED) ||
5894 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5900 // when coming from the multi paused state, reset the timestamps
5901 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5902 multi_reset_timestamps();
5905 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5906 // initialize all object update details
5907 multi_oo_gameplay_init();
5910 // under certain circumstances, the server should reset the object update rate limiting stuff
5911 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5912 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5914 // reinitialize the rate limiting system for all clients
5915 multi_oo_rate_init_all();
5918 // multiplayer clients should always re-initialize their control info rate limiting system
5919 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5920 multi_oo_rate_init_all();
5924 if(Game_mode & GM_MULTIPLAYER){
5925 multi_ping_reset_players();
5928 Game_subspace_effect = 0;
5929 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5930 Game_subspace_effect = 1;
5931 if( !(Game_mode & GM_STANDALONE_SERVER) ){
5932 game_start_subspace_ambient_sound();
5936 sound_env_set(&Game_sound_env);
5937 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5939 // clear multiplayer button info i
5940 extern button_info Multi_ship_status_bi;
5941 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5944 case GS_STATE_HUD_CONFIG:
5948 case GS_STATE_MULTI_JOIN_GAME:
5949 multi_join_clear_game_list();
5951 if (old_state != GS_STATE_OPTIONS_MENU) {
5952 multi_join_game_init();
5957 case GS_STATE_MULTI_HOST_SETUP:
5958 // don't reinitialize if we're coming back from the host options screen
5959 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5960 multi_create_game_init();
5965 case GS_STATE_MULTI_CLIENT_SETUP:
5966 if (old_state != GS_STATE_OPTIONS_MENU) {
5967 multi_game_client_setup_init();
5972 case GS_STATE_CONTROL_CONFIG:
5973 control_config_init();
5976 case GS_STATE_TECH_MENU:
5980 case GS_STATE_BARRACKS_MENU:
5981 if(old_state != GS_STATE_VIEW_MEDALS){
5986 case GS_STATE_MISSION_LOG_SCROLLBACK:
5987 hud_scrollback_init();
5990 case GS_STATE_DEATH_DIED:
5991 Player_died_time = timestamp(10);
5993 if(!(Game_mode & GM_MULTIPLAYER)){
5994 player_show_death_message();
5996 Game_mode |= GM_DEAD_DIED;
5999 case GS_STATE_DEATH_BLEW_UP:
6000 if ( !popupdead_is_active() ) {
6001 Player_ai->target_objnum = -1;
6004 // stop any local EMP effect
6007 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6008 Game_mode |= GM_DEAD_BLEW_UP;
6009 Show_viewing_from_self = 0;
6011 // timestamp how long we should wait before displaying the died popup
6012 if ( !popupdead_is_active() ) {
6013 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6017 case GS_STATE_GAMEPLAY_HELP:
6018 gameplay_help_init();
6021 case GS_STATE_CREDITS:
6022 main_hall_stop_music();
6023 main_hall_stop_ambient();
6027 case GS_STATE_VIEW_MEDALS:
6028 medal_main_init(Player);
6031 case GS_STATE_SHOW_GOALS:
6032 mission_show_goals_init();
6035 case GS_STATE_HOTKEY_SCREEN:
6036 mission_hotkey_init();
6039 case GS_STATE_MULTI_MISSION_SYNC:
6040 // if we're coming from the options screen, don't do any
6041 if(old_state == GS_STATE_OPTIONS_MENU){
6045 switch(Multi_sync_mode){
6046 case MULTI_SYNC_PRE_BRIEFING:
6047 // if moving from game forming to the team select state
6050 case MULTI_SYNC_POST_BRIEFING:
6051 // if moving from briefing into the mission itself
6054 // tell everyone that we're now loading data
6055 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6056 send_netplayer_update_packet();
6058 // JAS: Used to do all paging here!!!!
6060 Net_player->state = NETPLAYER_STATE_WAITING;
6061 send_netplayer_update_packet();
6063 Game_time_compression = F1_0;
6065 case MULTI_SYNC_INGAME:
6071 case GS_STATE_VIEW_CUTSCENES:
6072 cutscenes_screen_init();
6075 case GS_STATE_MULTI_STD_WAIT:
6076 multi_standalone_wait_init();
6079 case GS_STATE_STANDALONE_MAIN:
6080 // don't initialize if we're coming from one of these 2 states unless there are no
6081 // players left (reset situation)
6082 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6083 standalone_main_init();
6087 case GS_STATE_MULTI_PAUSED:
6091 case GS_STATE_INGAME_PRE_JOIN:
6092 multi_ingame_select_init();
6095 case GS_STATE_STANDALONE_POSTGAME:
6096 multi_standalone_postgame_init();
6099 case GS_STATE_INITIAL_PLAYER_SELECT:
6100 player_select_init();
6103 case GS_STATE_MULTI_START_GAME:
6104 multi_start_game_init();
6107 case GS_STATE_MULTI_HOST_OPTIONS:
6108 multi_host_options_init();
6111 case GS_STATE_END_OF_CAMPAIGN:
6112 mission_campaign_end_init();
6115 case GS_STATE_LOOP_BRIEF:
6122 // do stuff that may need to be done regardless of state
6123 void game_do_state_common(int state,int no_networking)
6125 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6126 snd_do_frame(); // update sound system
6127 event_music_do_frame(); // music needs to play across many states
6129 multi_log_process();
6131 if (no_networking) {
6135 // maybe do a multiplayer frame based on game mode and state type
6136 if (Game_mode & GM_MULTIPLAYER) {
6138 case GS_STATE_OPTIONS_MENU:
6139 case GS_STATE_GAMEPLAY_HELP:
6140 case GS_STATE_HOTKEY_SCREEN:
6141 case GS_STATE_HUD_CONFIG:
6142 case GS_STATE_CONTROL_CONFIG:
6143 case GS_STATE_MISSION_LOG_SCROLLBACK:
6144 case GS_STATE_SHOW_GOALS:
6145 case GS_STATE_VIEW_CUTSCENES:
6146 case GS_STATE_EVENT_DEBUG:
6147 multi_maybe_do_frame();
6151 game_do_networking();
6155 // Called once a frame.
6156 // You should never try to change the state
6157 // in here... if you think you need to, you probably really
6158 // need to post an event, not change the state.
6159 int Game_do_state_should_skip = 0;
6160 void game_do_state(int state)
6162 // always lets the do_state_common() function determine if the state should be skipped
6163 Game_do_state_should_skip = 0;
6165 // legal to set the should skip state anywhere in this function
6166 game_do_state_common(state); // do stuff that may need to be done regardless of state
6168 if(Game_do_state_should_skip){
6173 case GS_STATE_MAIN_MENU:
6174 game_set_frametime(GS_STATE_MAIN_MENU);
6175 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6178 main_hall_do(flFrametime);
6182 case GS_STATE_OPTIONS_MENU:
6183 game_set_frametime(GS_STATE_OPTIONS_MENU);
6184 options_menu_do_frame(flFrametime);
6187 case GS_STATE_BARRACKS_MENU:
6188 game_set_frametime(GS_STATE_BARRACKS_MENU);
6189 barracks_do_frame(flFrametime);
6192 case GS_STATE_TRAINING_MENU:
6193 game_set_frametime(GS_STATE_TRAINING_MENU);
6194 training_menu_do_frame(flFrametime);
6197 case GS_STATE_TECH_MENU:
6198 game_set_frametime(GS_STATE_TECH_MENU);
6199 techroom_do_frame(flFrametime);
6202 case GS_STATE_GAMEPLAY_HELP:
6203 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6204 gameplay_help_do_frame(flFrametime);
6207 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6211 case GS_STATE_GAME_PAUSED:
6215 case GS_STATE_DEBUG_PAUSED:
6217 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6222 case GS_STATE_TRAINING_PAUSED:
6223 game_training_pause_do();
6226 case GS_STATE_LOAD_MISSION_MENU:
6227 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6228 mission_load_menu_do();
6231 case GS_STATE_BRIEFING:
6232 game_set_frametime(GS_STATE_BRIEFING);
6233 brief_do_frame(flFrametime);
6236 case GS_STATE_DEBRIEF:
6237 game_set_frametime(GS_STATE_DEBRIEF);
6238 debrief_do_frame(flFrametime);
6241 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6242 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6243 multi_df_debrief_do();
6246 case GS_STATE_SHIP_SELECT:
6247 game_set_frametime(GS_STATE_SHIP_SELECT);
6248 ship_select_do(flFrametime);
6251 case GS_STATE_WEAPON_SELECT:
6252 game_set_frametime(GS_STATE_WEAPON_SELECT);
6253 weapon_select_do(flFrametime);
6256 case GS_STATE_MISSION_LOG_SCROLLBACK:
6257 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6258 hud_scrollback_do_frame(flFrametime);
6261 case GS_STATE_HUD_CONFIG:
6262 game_set_frametime(GS_STATE_HUD_CONFIG);
6263 hud_config_do_frame(flFrametime);
6266 case GS_STATE_MULTI_JOIN_GAME:
6267 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6268 multi_join_game_do_frame();
6271 case GS_STATE_MULTI_HOST_SETUP:
6272 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6273 multi_create_game_do();
6276 case GS_STATE_MULTI_CLIENT_SETUP:
6277 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6278 multi_game_client_setup_do_frame();
6281 case GS_STATE_CONTROL_CONFIG:
6282 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6283 control_config_do_frame(flFrametime);
6286 case GS_STATE_DEATH_DIED:
6290 case GS_STATE_DEATH_BLEW_UP:
6294 case GS_STATE_SIMULATOR_ROOM:
6295 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6296 sim_room_do_frame(flFrametime);
6299 case GS_STATE_CAMPAIGN_ROOM:
6300 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6301 campaign_room_do_frame(flFrametime);
6304 case GS_STATE_RED_ALERT:
6305 game_set_frametime(GS_STATE_RED_ALERT);
6306 red_alert_do_frame(flFrametime);
6309 case GS_STATE_CMD_BRIEF:
6310 game_set_frametime(GS_STATE_CMD_BRIEF);
6311 cmd_brief_do_frame(flFrametime);
6314 case GS_STATE_CREDITS:
6315 game_set_frametime(GS_STATE_CREDITS);
6316 credits_do_frame(flFrametime);
6319 case GS_STATE_VIEW_MEDALS:
6320 game_set_frametime(GS_STATE_VIEW_MEDALS);
6324 case GS_STATE_SHOW_GOALS:
6325 game_set_frametime(GS_STATE_SHOW_GOALS);
6326 mission_show_goals_do_frame(flFrametime);
6329 case GS_STATE_HOTKEY_SCREEN:
6330 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6331 mission_hotkey_do_frame(flFrametime);
6334 case GS_STATE_VIEW_CUTSCENES:
6335 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6336 cutscenes_screen_do_frame();
6339 case GS_STATE_MULTI_STD_WAIT:
6340 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6341 multi_standalone_wait_do();
6344 case GS_STATE_STANDALONE_MAIN:
6345 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6346 standalone_main_do();
6349 case GS_STATE_MULTI_PAUSED:
6350 game_set_frametime(GS_STATE_MULTI_PAUSED);
6354 case GS_STATE_TEAM_SELECT:
6355 game_set_frametime(GS_STATE_TEAM_SELECT);
6359 case GS_STATE_INGAME_PRE_JOIN:
6360 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6361 multi_ingame_select_do();
6364 case GS_STATE_EVENT_DEBUG:
6366 game_set_frametime(GS_STATE_EVENT_DEBUG);
6367 game_show_event_debug(flFrametime);
6371 case GS_STATE_STANDALONE_POSTGAME:
6372 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6373 multi_standalone_postgame_do();
6376 case GS_STATE_INITIAL_PLAYER_SELECT:
6377 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6381 case GS_STATE_MULTI_MISSION_SYNC:
6382 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6386 case GS_STATE_MULTI_START_GAME:
6387 game_set_frametime(GS_STATE_MULTI_START_GAME);
6388 multi_start_game_do();
6391 case GS_STATE_MULTI_HOST_OPTIONS:
6392 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6393 multi_host_options_do();
6396 case GS_STATE_END_OF_CAMPAIGN:
6397 mission_campaign_end_do();
6400 case GS_STATE_END_DEMO:
6401 game_set_frametime(GS_STATE_END_DEMO);
6402 end_demo_campaign_do();
6405 case GS_STATE_LOOP_BRIEF:
6406 game_set_frametime(GS_STATE_LOOP_BRIEF);
6410 } // end switch(gs_current_state)
6414 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6415 int game_do_ram_check(int ram_in_bytes)
6417 if ( ram_in_bytes < 30*1024*1024 ) {
6418 int allowed_to_run = 1;
6419 if ( ram_in_bytes < 25*1024*1024 ) {
6424 int Freespace_total_ram_MB;
6425 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6427 if ( allowed_to_run ) {
6429 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);
6433 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6434 if ( msgbox_rval == IDCANCEL ) {
6441 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);
6443 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6454 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6455 // If so, copy it over and remove the update directory.
6456 void game_maybe_update_launcher(char *exe_dir)
6459 char src_filename[MAX_PATH];
6460 char dest_filename[MAX_PATH];
6462 strcpy(src_filename, exe_dir);
6463 strcat(src_filename, NOX("\\update\\freespace.exe"));
6465 strcpy(dest_filename, exe_dir);
6466 strcat(dest_filename, NOX("\\freespace.exe"));
6468 // see if src_filename exists
6470 fp = fopen(src_filename, "rb");
6476 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6478 // copy updated freespace.exe to freespace exe dir
6479 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6480 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 );
6484 // delete the file in the update directory
6485 DeleteFile(src_filename);
6487 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6488 char update_dir[MAX_PATH];
6489 strcpy(update_dir, exe_dir);
6490 strcat(update_dir, NOX("\\update"));
6491 RemoveDirectory(update_dir);
6497 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6501 int sub_total_destroyed = 0;
6505 // get the total for all his children
6506 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6507 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6510 // find the # of faces for this _individual_ object
6511 total = submodel_get_num_polys(model_num, sm);
6512 if(strstr(pm->submodel[sm].name, "-destroyed")){
6513 sub_total_destroyed = total;
6517 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6520 *out_total += total + sub_total;
6521 *out_destroyed_total += sub_total_destroyed;
6524 #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);
6525 void game_spew_pof_info()
6527 char *pof_list[1000];
6530 int idx, model_num, i, j;
6532 int total, root_total, model_total, destroyed_total, counted;
6536 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6538 // spew info on all the pofs
6544 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6549 for(idx=0; idx<num_files; idx++, counted++){
6550 sprintf(str, "%s.pof", pof_list[idx]);
6551 model_num = model_load(str, 0, NULL);
6553 pm = model_get(model_num);
6555 // if we have a real model
6560 // go through and print all raw submodels
6561 cfputs("RAW\n", out);
6564 for (i=0; i<pm->n_models; i++) {
6565 total = submodel_get_num_polys(model_num, i);
6567 model_total += total;
6568 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6571 sprintf(str, "Model total %d\n", model_total);
6574 // now go through and do it by LOD
6575 cfputs("BY LOD\n\n", out);
6576 for(i=0; i<pm->n_detail_levels; i++){
6577 sprintf(str, "LOD %d\n", i);
6581 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6583 destroyed_total = 0;
6584 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6585 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6588 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6591 sprintf(str, "TOTAL: %d\n", total + root_total);
6593 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6595 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6598 cfputs("------------------------------------------------------------------------\n\n", out);
6602 if(counted >= MAX_POLYGON_MODELS - 5){
6615 game_spew_pof_info();
6618 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6623 // Don't let more than one instance of Freespace run.
6624 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6626 SetForegroundWindow(hwnd);
6631 // Find out how much RAM is on this machine
6634 ms.dwLength = sizeof(MEMORYSTATUS);
6635 GlobalMemoryStatus(&ms);
6636 Freespace_total_ram = ms.dwTotalPhys;
6638 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6642 if ( ms.dwTotalVirtual < 1024 ) {
6643 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6647 if (!vm_init(24*1024*1024)) {
6648 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 );
6652 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6654 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);
6664 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6665 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6666 seem worth bothering with.
6670 lResult = RegOpenKeyEx(
6671 HKEY_LOCAL_MACHINE, // Where it is
6672 "Software\\Microsoft\\DirectX", // name of key
6673 NULL, // DWORD reserved
6674 KEY_QUERY_VALUE, // Allows all changes
6675 &hKey // Location to store key
6678 if (lResult == ERROR_SUCCESS) {
6680 DWORD dwType, dwLen;
6683 lResult = RegQueryValueEx(
6684 hKey, // Handle to key
6685 "Version", // The values name
6686 NULL, // DWORD reserved
6687 &dwType, // What kind it is
6688 (ubyte *) version, // value to set
6689 &dwLen // How many bytes to set
6692 if (lResult == ERROR_SUCCESS) {
6693 dx_version = atoi(strstr(version, ".") + 1);
6697 DWORD dwType, dwLen;
6700 lResult = RegQueryValueEx(
6701 hKey, // Handle to key
6702 "InstalledVersion", // The values name
6703 NULL, // DWORD reserved
6704 &dwType, // What kind it is
6705 (ubyte *) &val, // value to set
6706 &dwLen // How many bytes to set
6709 if (lResult == ERROR_SUCCESS) {
6717 if (dx_version < 3) {
6718 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6719 "latest version of DirectX at:\n\n"
6720 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6722 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6723 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6728 //=====================================================
6729 // Make sure we're running in the right directory.
6733 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6734 char *p = exe_dir + strlen(exe_dir);
6736 // chop off the filename
6737 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6743 if ( strlen(exe_dir) > 0 ) {
6744 SetCurrentDirectory(exe_dir);
6747 // check for updated freespace.exe
6748 game_maybe_update_launcher(exe_dir);
6756 extern void windebug_memwatch_init();
6757 windebug_memwatch_init();
6761 parse_cmdline(szCmdLine);
6763 #ifdef STANDALONE_ONLY_BUILD
6765 nprintf(("Network", "Standalone running"));
6768 nprintf(("Network", "Standalone running"));
6776 // maybe spew pof stuff
6777 if(Cmdline_spew_pof_info){
6778 game_spew_pof_info();
6783 // non-demo, non-standalone, play the intro movie
6788 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) ){
6790 #if defined(OEM_BUILD)
6791 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6793 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6794 #endif // defined(OEM_BUILD)
6799 if ( !Is_standalone ) {
6801 // release -- movies always play
6804 // 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
6806 // movie_play( NOX("intro.mve"), 0 );
6808 // debug version, movie will only play with -showmovies
6809 #elif !defined(NDEBUG)
6812 // movie_play( NOX("intro.mve"), 0);
6815 if ( Cmdline_show_movies )
6816 movie_play( NOX("intro.mve"), 0 );
6825 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6827 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6831 // only important for non THREADED mode
6834 state = gameseq_process_events();
6835 if ( state == GS_STATE_QUIT_GAME ){
6842 demo_upsell_show_screens();
6844 #elif defined(OEM_BUILD)
6845 // show upsell screens on exit
6846 oem_upsell_show_screens();
6853 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6859 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6861 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6863 // Do nothing here - RecordExceptionInfo() has already done
6864 // everything that is needed. Actually this code won't even
6865 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6866 // the __except clause.
6872 fprintf(stderr, "WinMain: exceptions shall fall through\n");
6873 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6877 // launcher the fslauncher program on exit
6878 void game_launch_launcher_on_exit()
6882 PROCESS_INFORMATION pi;
6883 char cmd_line[2048];
6884 char original_path[1024] = "";
6886 memset( &si, 0, sizeof(STARTUPINFO) );
6890 _getcwd(original_path, 1023);
6892 // set up command line
6893 strcpy(cmd_line, original_path);
6894 strcat(cmd_line, "\\");
6895 strcat(cmd_line, LAUNCHER_FNAME);
6896 strcat(cmd_line, " -straight_to_update");
6898 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6899 cmd_line, // pointer to command line string
6900 NULL, // pointer to process security attributes
6901 NULL, // pointer to thread security attributes
6902 FALSE, // handle inheritance flag
6903 CREATE_DEFAULT_ERROR_MODE, // creation flags
6904 NULL, // pointer to new environment block
6905 NULL, // pointer to current directory name
6906 &si, // pointer to STARTUPINFO
6907 &pi // pointer to PROCESS_INFORMATION
6909 // to eliminate build warnings
6919 // This function is called when FreeSpace terminates normally.
6921 void game_shutdown(void)
6927 // don't ever flip a page on the standalone!
6928 if(!(Game_mode & GM_STANDALONE_SERVER)){
6934 // if the player has left the "player select" screen and quit the game without actually choosing
6935 // a player, Player will be NULL, in which case we shouldn't write the player file out!
6936 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6940 // load up common multiplayer icons
6941 multi_unload_common_icons();
6943 shockwave_close(); // release any memory used by shockwave system
6944 fireball_close(); // free fireball system
6945 ship_close(); // free any memory that was allocated for the ships
6946 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6947 unload_animating_pointer();// frees the frames used for the animating mouse pointer
6948 bm_unload_all(); // free bitmaps
6949 mission_campaign_close(); // close out the campaign stuff
6950 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
6952 #ifdef MULTI_USE_LAG
6956 // the menu close functions will unload the bitmaps if they were displayed during the game
6957 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6960 training_menu_close();
6963 extern void joy_close();
6966 audiostream_close();
6968 event_music_close();
6972 // HACKITY HACK HACK
6973 // if this flag is set, we should be firing up the launcher when exiting freespace
6974 extern int Multi_update_fireup_launcher_on_exit;
6975 if(Multi_update_fireup_launcher_on_exit){
6976 game_launch_launcher_on_exit();
6980 // game_stop_looped_sounds()
6982 // This function will call the appropriate stop looped sound functions for those
6983 // modules which use looping sounds. It is not enough just to stop a looping sound
6984 // at the DirectSound level, the game is keeping track of looping sounds, and this
6985 // function is used to inform the game that looping sounds are being halted.
6987 void game_stop_looped_sounds()
6989 hud_stop_looped_locking_sounds();
6990 hud_stop_looped_engine_sounds();
6991 afterburner_stop_sounds();
6992 player_stop_looped_sounds();
6993 obj_snd_stop_all(); // stop all object-linked persistant sounds
6994 game_stop_subspace_ambient_sound();
6995 snd_stop(Radar_static_looping);
6996 Radar_static_looping = -1;
6997 snd_stop(Target_static_looping);
6998 shipfx_stop_engine_wash_sound();
6999 Target_static_looping = -1;
7002 //////////////////////////////////////////////////////////////////////////
7004 // Code for supporting an animating mouse pointer
7007 //////////////////////////////////////////////////////////////////////////
7009 typedef struct animating_obj
7018 static animating_obj Animating_mouse;
7020 // ----------------------------------------------------------------------------
7021 // init_animating_pointer()
7023 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7024 // gets properly initialized
7026 void init_animating_pointer()
7028 Animating_mouse.first_frame = -1;
7029 Animating_mouse.num_frames = 0;
7030 Animating_mouse.current_frame = -1;
7031 Animating_mouse.time = 0.0f;
7032 Animating_mouse.elapsed_time = 0.0f;
7035 // ----------------------------------------------------------------------------
7036 // load_animating_pointer()
7038 // Called at game init to load in the frames for the animating mouse pointer
7040 // input: filename => filename of animation file that holds the animation
7042 void load_animating_pointer(char *filename, int dx, int dy)
7047 init_animating_pointer();
7049 am = &Animating_mouse;
7050 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7051 if ( am->first_frame == -1 )
7052 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7053 am->current_frame = 0;
7054 am->time = am->num_frames / i2fl(fps);
7057 // ----------------------------------------------------------------------------
7058 // unload_animating_pointer()
7060 // Called at game shutdown to free the memory used to store the animation frames
7062 void unload_animating_pointer()
7067 am = &Animating_mouse;
7068 for ( i = 0; i < am->num_frames; i++ ) {
7069 Assert( (am->first_frame+i) >= 0 );
7070 bm_release(am->first_frame + i);
7073 am->first_frame = -1;
7075 am->current_frame = -1;
7078 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7079 void game_render_mouse(float frametime)
7084 // if animating cursor exists, play the next frame
7085 am = &Animating_mouse;
7086 if ( am->first_frame != -1 ) {
7087 mouse_get_pos(&mx, &my);
7088 am->elapsed_time += frametime;
7089 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7090 if ( am->current_frame >= am->num_frames ) {
7091 am->current_frame = 0;
7092 am->elapsed_time = 0.0f;
7094 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7098 // ----------------------------------------------------------------------------
7099 // game_maybe_draw_mouse()
7101 // determines whether to draw the mouse pointer at all, and what frame of
7102 // animation to use if the mouse is animating
7104 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7106 // input: frametime => elapsed frame time in seconds since last call
7108 void game_maybe_draw_mouse(float frametime)
7112 game_state = gameseq_get_state();
7114 switch ( game_state ) {
7115 case GS_STATE_GAME_PAUSED:
7116 // case GS_STATE_MULTI_PAUSED:
7117 case GS_STATE_GAME_PLAY:
7118 case GS_STATE_DEATH_DIED:
7119 case GS_STATE_DEATH_BLEW_UP:
7120 if ( popup_active() || popupdead_is_active() ) {
7132 if ( !Mouse_hidden )
7133 game_render_mouse(frametime);
7137 void game_do_training_checks()
7141 waypoint_list *wplp;
7143 if (Training_context & TRAINING_CONTEXT_SPEED) {
7144 s = (int) Player_obj->phys_info.fspeed;
7145 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7146 if (!Training_context_speed_set) {
7147 Training_context_speed_set = 1;
7148 Training_context_speed_timestamp = timestamp();
7152 Training_context_speed_set = 0;
7155 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7156 wplp = &Waypoint_lists[Training_context_path];
7157 if (wplp->count > Training_context_goal_waypoint) {
7158 i = Training_context_goal_waypoint;
7160 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7161 if (d <= Training_context_distance) {
7162 Training_context_at_waypoint = i;
7163 if (Training_context_goal_waypoint == i) {
7164 Training_context_goal_waypoint++;
7165 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7172 if (i == wplp->count)
7175 } while (i != Training_context_goal_waypoint);
7179 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7180 Players_target = Player_ai->target_objnum;
7181 Players_targeted_subsys = Player_ai->targeted_subsys;
7182 Players_target_timestamp = timestamp();
7186 /////////// Following is for event debug view screen
7190 #define EVENT_DEBUG_MAX 5000
7191 #define EVENT_DEBUG_EVENT 0x8000
7193 int Event_debug_index[EVENT_DEBUG_MAX];
7196 void game_add_event_debug_index(int n, int indent)
7198 if (ED_count < EVENT_DEBUG_MAX)
7199 Event_debug_index[ED_count++] = n | (indent << 16);
7202 void game_add_event_debug_sexp(int n, int indent)
7207 if (Sexp_nodes[n].first >= 0) {
7208 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7209 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7213 game_add_event_debug_index(n, indent);
7214 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7215 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7217 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7220 void game_event_debug_init()
7225 for (e=0; e<Num_mission_events; e++) {
7226 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7227 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7231 void game_show_event_debug(float frametime)
7235 int font_height, font_width;
7237 static int scroll_offset = 0;
7239 k = game_check_key();
7245 if (scroll_offset < 0)
7255 scroll_offset -= 20;
7256 if (scroll_offset < 0)
7261 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7265 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7271 gr_set_color_fast(&Color_bright);
7273 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7275 gr_set_color_fast(&Color_normal);
7277 gr_get_string_size(&font_width, &font_height, NOX("test"));
7278 y_max = gr_screen.max_h - font_height - 5;
7282 while (k < ED_count) {
7283 if (y_index > y_max)
7286 z = Event_debug_index[k];
7287 if (z & EVENT_DEBUG_EVENT) {
7289 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7290 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7291 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7292 Mission_events[z].repeat_count, Mission_events[z].interval);
7300 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7301 switch (Sexp_nodes[z & 0x7fff].value) {
7303 strcat(buf, NOX(" (True)"));
7307 strcat(buf, NOX(" (False)"));
7310 case SEXP_KNOWN_TRUE:
7311 strcat(buf, NOX(" (Always true)"));
7314 case SEXP_KNOWN_FALSE:
7315 strcat(buf, NOX(" (Always false)"));
7318 case SEXP_CANT_EVAL:
7319 strcat(buf, NOX(" (Can't eval)"));
7323 case SEXP_NAN_FOREVER:
7324 strcat(buf, NOX(" (Not a number)"));
7329 gr_printf(10, y_index, buf);
7330 y_index += font_height;
7343 extern int Tmap_npixels;
7345 int Tmap_num_too_big = 0;
7346 int Num_models_needing_splitting = 0;
7348 void Time_model( int modelnum )
7350 // mprintf(( "Timing ship '%s'\n", si->name ));
7352 vector eye_pos, model_pos;
7353 matrix eye_orient, model_orient;
7355 polymodel *pm = model_get( modelnum );
7357 int l = strlen(pm->filename);
7359 if ( (l == '/') || (l=='\\') || (l==':')) {
7365 char *pof_file = &pm->filename[l];
7367 int model_needs_splitting = 0;
7369 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7371 for (i=0; i<pm->n_textures; i++ ) {
7372 char filename[1024];
7375 int bmp_num = pm->original_textures[i];
7376 if ( bmp_num > -1 ) {
7377 bm_get_palette(pm->original_textures[i], pal, filename );
7379 bm_get_info( pm->original_textures[i],&w, &h );
7382 if ( (w > 512) || (h > 512) ) {
7383 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7385 model_needs_splitting++;
7388 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7392 if ( model_needs_splitting ) {
7393 Num_models_needing_splitting++;
7395 eye_orient = model_orient = vmd_identity_matrix;
7396 eye_pos = model_pos = vmd_zero_vector;
7398 eye_pos.z = -pm->rad*2.0f;
7400 vector eye_to_model;
7402 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7403 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7405 fix t1 = timer_get_fixed_seconds();
7408 ta.p = ta.b = ta.h = 0.0f;
7413 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7415 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7417 modelstats_num_polys = modelstats_num_verts = 0;
7419 while( ta.h < PI2 ) {
7422 vm_angles_2_matrix(&m1, &ta );
7423 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7430 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7432 model_clear_instance( modelnum );
7433 model_set_detail_level(0); // use highest detail level
7434 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7442 int k = key_inkey();
7443 if ( k == KEY_ESC ) {
7448 fix t2 = timer_get_fixed_seconds();
7450 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7451 //bitmaps_used_this_frame /= framecount;
7453 modelstats_num_polys /= framecount;
7454 modelstats_num_verts /= framecount;
7456 Tmap_npixels /=framecount;
7459 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7460 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 );
7461 // 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 );
7467 int Time_models = 0;
7468 DCF_BOOL( time_models, Time_models );
7470 void Do_model_timings_test()
7474 if ( !Time_models ) return;
7476 mprintf(( "Timing models!\n" ));
7480 ubyte model_used[MAX_POLYGON_MODELS];
7481 int model_id[MAX_POLYGON_MODELS];
7482 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7487 for (i=0; i<Num_ship_types; i++ ) {
7488 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7490 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7491 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7494 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7495 if ( !Texture_fp ) return;
7497 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7498 if ( !Time_fp ) return;
7500 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7501 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7503 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7504 if ( model_used[i] ) {
7505 Time_model( model_id[i] );
7509 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7510 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7519 // Call this function when you want to inform the player that a feature is not
7520 // enabled in the DEMO version of FreSpace
7521 void game_feature_not_in_demo_popup()
7523 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7526 // format the specified time (fixed point) into a nice string
7527 void game_format_time(fix m_time,char *time_str)
7530 int hours,minutes,seconds;
7533 mtime = f2fl(m_time);
7535 // get the hours, minutes and seconds
7536 hours = (int)(mtime / 3600.0f);
7538 mtime -= (3600.0f * (float)hours);
7540 seconds = (int)mtime%60;
7541 minutes = (int)mtime/60;
7543 // print the hour if necessary
7545 sprintf(time_str,XSTR( "%d:", 201),hours);
7546 // if there are less than 10 minutes, print a leading 0
7548 strcpy(tmp,NOX("0"));
7549 strcat(time_str,tmp);
7553 // print the minutes
7555 sprintf(tmp,XSTR( "%d:", 201),minutes);
7556 strcat(time_str,tmp);
7558 sprintf(time_str,XSTR( "%d:", 201),minutes);
7561 // print the seconds
7563 strcpy(tmp,NOX("0"));
7564 strcat(time_str,tmp);
7566 sprintf(tmp,"%d",seconds);
7567 strcat(time_str,tmp);
7570 // Stuff version string in *str.
7571 void get_version_string(char *str)
7574 if ( FS_VERSION_BUILD == 0 ) {
7575 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7577 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7580 #if defined (FS2_DEMO)
7582 #elif defined (OEM_BUILD)
7583 strcat(str, " (OEM)");
7589 char myname[_MAX_PATH];
7590 int namelen, major, minor, build, waste;
7591 unsigned int buf_size;
7597 // Find my EXE file name
7598 hMod = GetModuleHandle(NULL);
7599 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7601 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7602 infop = (char *)malloc(version_size);
7603 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7605 // get the product version
7606 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7607 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7609 sprintf(str,"Dv%d.%02d",major, minor);
7611 sprintf(str,"v%d.%02d",major, minor);
7616 void get_version_string_short(char *str)
7618 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7621 // ----------------------------------------------------------------
7623 // OEM UPSELL SCREENS BEGIN
7625 // ----------------------------------------------------------------
7626 #if defined(OEM_BUILD)
7628 #define NUM_OEM_UPSELL_SCREENS 3
7629 #define OEM_UPSELL_SCREEN_DELAY 10000
7631 static int Oem_upsell_bitmaps_loaded = 0;
7632 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7633 static int Oem_upsell_screen_number = 0;
7634 static int Oem_upsell_show_next_bitmap_time;
7637 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7650 static int Oem_normal_cursor = -1;
7651 static int Oem_web_cursor = -1;
7652 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7653 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7655 void oem_upsell_next_screen()
7657 Oem_upsell_screen_number++;
7658 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7659 // extra long delay, mouse shown on last upsell
7660 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7664 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7668 void oem_upsell_load_bitmaps()
7672 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7673 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7677 void oem_upsell_unload_bitmaps()
7681 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7682 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7683 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7688 Oem_upsell_bitmaps_loaded = 0;
7691 // clickable hotspot on 3rd OEM upsell screen
7692 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7694 28, 350, 287, 96 // x, y, w, h
7697 45, 561, 460, 152 // x, y, w, h
7701 void oem_upsell_show_screens()
7703 int current_time, k;
7706 if ( !Oem_upsell_bitmaps_loaded ) {
7707 oem_upsell_load_bitmaps();
7708 Oem_upsell_bitmaps_loaded = 1;
7711 // may use upsell screens more than once
7712 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7713 Oem_upsell_screen_number = 0;
7719 int nframes; // used to pass, not really needed (should be 1)
7720 Oem_normal_cursor = gr_get_cursor_bitmap();
7721 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7722 Assert(Oem_web_cursor >= 0);
7723 if (Oem_web_cursor < 0) {
7724 Oem_web_cursor = Oem_normal_cursor;
7729 //oem_reset_trailer_timer();
7731 current_time = timer_get_milliseconds();
7736 // advance screen on keypress or timeout
7737 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7738 oem_upsell_next_screen();
7741 // check if we are done
7742 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7743 Oem_upsell_screen_number--;
7746 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7751 // show me the upsell
7752 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7753 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7757 // if this is the 3rd upsell, make it clickable, d00d
7758 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7760 int button_state = mouse_get_pos(&mx, &my);
7761 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])
7762 && (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]) )
7765 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7768 if (button_state & MOUSE_LEFT_BUTTON) {
7770 multi_pxo_url(OEM_UPSELL_URL);
7774 // switch cursor back to normal one
7775 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7780 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7790 oem_upsell_unload_bitmaps();
7792 // switch cursor back to normal one
7793 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7797 #endif // defined(OEM_BUILD)
7798 // ----------------------------------------------------------------
7800 // OEM UPSELL SCREENS END
7802 // ----------------------------------------------------------------
7806 // ----------------------------------------------------------------
7808 // DEMO UPSELL SCREENS BEGIN
7810 // ----------------------------------------------------------------
7814 //#define NUM_DEMO_UPSELL_SCREENS 4
7816 #define NUM_DEMO_UPSELL_SCREENS 2
7817 #define DEMO_UPSELL_SCREEN_DELAY 3000
7819 static int Demo_upsell_bitmaps_loaded = 0;
7820 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7821 static int Demo_upsell_screen_number = 0;
7822 static int Demo_upsell_show_next_bitmap_time;
7825 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7838 void demo_upsell_next_screen()
7840 Demo_upsell_screen_number++;
7841 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7842 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7844 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7848 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7849 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7850 #ifndef HARDWARE_ONLY
7851 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7858 void demo_upsell_load_bitmaps()
7862 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7863 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7867 void demo_upsell_unload_bitmaps()
7871 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7872 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7873 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7878 Demo_upsell_bitmaps_loaded = 0;
7881 void demo_upsell_show_screens()
7883 int current_time, k;
7886 if ( !Demo_upsell_bitmaps_loaded ) {
7887 demo_upsell_load_bitmaps();
7888 Demo_upsell_bitmaps_loaded = 1;
7891 // may use upsell screens more than once
7892 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7893 Demo_upsell_screen_number = 0;
7900 demo_reset_trailer_timer();
7902 current_time = timer_get_milliseconds();
7909 // don't time out, wait for keypress
7911 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7912 demo_upsell_next_screen();
7917 demo_upsell_next_screen();
7920 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7921 Demo_upsell_screen_number--;
7924 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7929 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7930 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7935 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7945 demo_upsell_unload_bitmaps();
7950 // ----------------------------------------------------------------
7952 // DEMO UPSELL SCREENS END
7954 // ----------------------------------------------------------------
7957 // ----------------------------------------------------------------
7959 // Subspace Ambient Sound START
7961 // ----------------------------------------------------------------
7963 static int Subspace_ambient_left_channel = -1;
7964 static int Subspace_ambient_right_channel = -1;
7967 void game_start_subspace_ambient_sound()
7969 if ( Subspace_ambient_left_channel < 0 ) {
7970 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7973 if ( Subspace_ambient_right_channel < 0 ) {
7974 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7978 void game_stop_subspace_ambient_sound()
7980 if ( Subspace_ambient_left_channel >= 0 ) {
7981 snd_stop(Subspace_ambient_left_channel);
7982 Subspace_ambient_left_channel = -1;
7985 if ( Subspace_ambient_right_channel >= 0 ) {
7986 snd_stop(Subspace_ambient_right_channel);
7987 Subspace_ambient_right_channel = -1;
7991 // ----------------------------------------------------------------
7993 // Subspace Ambient Sound END
7995 // ----------------------------------------------------------------
7997 // ----------------------------------------------------------------
7999 // CDROM detection code START
8001 // ----------------------------------------------------------------
8003 #define CD_SIZE_72_MINUTE_MAX (697000000)
8005 uint game_get_cd_used_space(char *path)
8009 char use_path[512] = "";
8010 char sub_path[512] = "";
8011 WIN32_FIND_DATA find;
8014 // recurse through all files and directories
8015 strcpy(use_path, path);
8016 strcat(use_path, "*.*");
8017 find_handle = FindFirstFile(use_path, &find);
8020 if(find_handle == INVALID_HANDLE_VALUE){
8026 // subdirectory. make sure to ignore . and ..
8027 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8029 strcpy(sub_path, path);
8030 strcat(sub_path, find.cFileName);
8031 strcat(sub_path, "\\");
8032 total += game_get_cd_used_space(sub_path);
8034 total += (uint)find.nFileSizeLow;
8036 } while(FindNextFile(find_handle, &find));
8039 FindClose(find_handle);
8051 // if volume_name is non-null, the CD name must match that
8052 int find_freespace_cd(char *volume_name)
8055 char oldpath[MAX_PATH];
8059 int volume_match = 0;
8063 GetCurrentDirectory(MAX_PATH, oldpath);
8065 for (i = 0; i < 26; i++)
8071 path[0] = (char)('A'+i);
8072 if (GetDriveType(path) == DRIVE_CDROM) {
8074 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8075 nprintf(("CD", "CD volume: %s\n", volume));
8077 // check for any CD volume
8078 int volume1_present = 0;
8079 int volume2_present = 0;
8080 int volume3_present = 0;
8082 char full_check[512] = "";
8084 // look for setup.exe
8085 strcpy(full_check, path);
8086 strcat(full_check, "setup.exe");
8087 find_handle = _findfirst(full_check, &find);
8088 if(find_handle != -1){
8089 volume1_present = 1;
8090 _findclose(find_handle);
8093 // look for intro.mve
8094 strcpy(full_check, path);
8095 strcat(full_check, "intro.mve");
8096 find_handle = _findfirst(full_check, &find);
8097 if(find_handle != -1){
8098 volume2_present = 1;
8099 _findclose(find_handle);
8102 // look for endpart1.mve
8103 strcpy(full_check, path);
8104 strcat(full_check, "endpart1.mve");
8105 find_handle = _findfirst(full_check, &find);
8106 if(find_handle != -1){
8107 volume3_present = 1;
8108 _findclose(find_handle);
8111 // see if we have the specific CD we're looking for
8112 if ( volume_name ) {
8114 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8118 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8122 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8126 if ( volume1_present || volume2_present || volume3_present ) {
8131 // 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
8132 if ( volume_match ){
8134 // 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
8135 if(volume2_present || volume3_present) {
8136 // first step - check to make sure its a cdrom
8137 if(GetDriveType(path) != DRIVE_CDROM){
8141 #if !defined(OEM_BUILD)
8142 // oem not on 80 min cds, so dont check tha size
8144 uint used_space = game_get_cd_used_space(path);
8145 if(used_space < CD_SIZE_72_MINUTE_MAX){
8148 #endif // !defined(OEM_BUILD)
8156 #endif // RELEASE_REAL
8162 SetCurrentDirectory(oldpath);
8171 int set_cdrom_path(int drive_num)
8175 if (drive_num < 0) { //no CD
8177 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8180 strcpy(Game_CDROM_dir,""); //set directory
8184 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8200 i = find_freespace_cd();
8202 rval = set_cdrom_path(i);
8206 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8208 nprintf(("CD", "FreeSpace CD not found\n"));
8216 int Last_cd_label_found = 0;
8217 char Last_cd_label[256];
8219 int game_cd_changed()
8226 if ( strlen(Game_CDROM_dir) == 0 ) {
8230 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8232 if ( found != Last_cd_label_found ) {
8233 Last_cd_label_found = found;
8235 mprintf(( "CD '%s' was inserted\n", label ));
8238 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8242 if ( Last_cd_label_found ) {
8243 if ( !stricmp( Last_cd_label, label )) {
8244 //mprintf(( "CD didn't change\n" ));
8246 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8250 // none found before, none found now.
8251 //mprintf(( "still no CD...\n" ));
8255 Last_cd_label_found = found;
8257 strcpy( Last_cd_label, label );
8259 strcpy( Last_cd_label, "" );
8268 // check if _any_ FreeSpace2 CDs are in the drive
8269 // return: 1 => CD now in drive
8270 // 0 => Could not find CD, they refuse to put it in the drive
8271 int game_do_cd_check(char *volume_name)
8273 #if !defined(GAME_CD_CHECK)
8279 int num_attempts = 0;
8280 int refresh_files = 0;
8282 int path_set_ok, popup_rval;
8284 cd_drive_num = find_freespace_cd(volume_name);
8285 path_set_ok = set_cdrom_path(cd_drive_num);
8286 if ( path_set_ok ) {
8288 if ( refresh_files ) {
8300 // no CD found, so prompt user
8301 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8303 if ( popup_rval != 1 ) {
8308 if ( num_attempts++ > 5 ) {
8319 // check if _any_ FreeSpace2 CDs are in the drive
8320 // return: 1 => CD now in drive
8321 // 0 => Could not find CD, they refuse to put it in the drive
8322 int game_do_cd_check_specific(char *volume_name, int cdnum)
8327 int num_attempts = 0;
8328 int refresh_files = 0;
8330 int path_set_ok, popup_rval;
8332 cd_drive_num = find_freespace_cd(volume_name);
8333 path_set_ok = set_cdrom_path(cd_drive_num);
8334 if ( path_set_ok ) {
8336 if ( refresh_files ) {
8347 // no CD found, so prompt user
8348 #if defined(DVD_MESSAGE_HACK)
8349 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8351 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8354 if ( popup_rval != 1 ) {
8359 if ( num_attempts++ > 5 ) {
8369 // only need to do this in RELEASE_REAL
8370 int game_do_cd_mission_check(char *filename)
8376 fs_builtin_mission *m = game_find_builtin_mission(filename);
8378 // check for changed CD
8379 if(game_cd_changed()){
8384 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8388 // not builtin, so do a general check (any FS2 CD will do)
8390 return game_do_cd_check();
8393 // does not have any CD requirement, do a general check
8394 if(strlen(m->cd_volume) <= 0){
8395 return game_do_cd_check();
8399 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8401 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8403 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8406 return game_do_cd_check();
8409 // did we find the cd?
8410 if(find_freespace_cd(m->cd_volume) >= 0){
8414 // make sure the volume exists
8415 int num_attempts = 0;
8416 int refresh_files = 0;
8418 int path_set_ok, popup_rval;
8420 cd_drive_num = find_freespace_cd(m->cd_volume);
8421 path_set_ok = set_cdrom_path(cd_drive_num);
8422 if ( path_set_ok ) {
8424 if ( refresh_files ) {
8431 // no CD found, so prompt user
8432 #if defined(DVD_MESSAGE_HACK)
8433 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8435 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8439 if ( popup_rval != 1 ) {
8444 if ( num_attempts++ > 5 ) {
8456 // ----------------------------------------------------------------
8458 // CDROM detection code END
8460 // ----------------------------------------------------------------
8462 // ----------------------------------------------------------------
8463 // SHIPS TBL VERIFICATION STUFF
8466 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8467 #define NUM_SHIPS_TBL_CHECKSUMS 1
8469 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8470 -463907578, // US - beta 1
8471 1696074201, // FS2 demo
8474 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8475 // -1022810006, // 1.0 FULL
8476 -1254285366 // 1.2 FULL (German)
8479 void verify_ships_tbl()
8483 Game_ships_tbl_valid = 1;
8489 // detect if the packfile exists
8490 CFILE *detect = cfopen("ships.tbl", "rb");
8491 Game_ships_tbl_valid = 0;
8495 Game_ships_tbl_valid = 0;
8499 // get the long checksum of the file
8501 cfseek(detect, 0, SEEK_SET);
8502 cf_chksum_long(detect, &file_checksum);
8506 // now compare the checksum/filesize against known #'s
8507 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8508 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8509 Game_ships_tbl_valid = 1;
8516 DCF(shipspew, "display the checksum for the current ships.tbl")
8519 CFILE *detect = cfopen("ships.tbl", "rb");
8520 // get the long checksum of the file
8522 cfseek(detect, 0, SEEK_SET);
8523 cf_chksum_long(detect, &file_checksum);
8526 dc_printf("%d", file_checksum);
8529 // ----------------------------------------------------------------
8530 // WEAPONS TBL VERIFICATION STUFF
8533 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8534 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8536 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8537 141718090, // US - beta 1
8538 -266420030, // demo 1
8541 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8542 // 399297860, // 1.0 FULL
8543 -553984927 // 1.2 FULL (german)
8546 void verify_weapons_tbl()
8550 Game_weapons_tbl_valid = 1;
8556 // detect if the packfile exists
8557 CFILE *detect = cfopen("weapons.tbl", "rb");
8558 Game_weapons_tbl_valid = 0;
8562 Game_weapons_tbl_valid = 0;
8566 // get the long checksum of the file
8568 cfseek(detect, 0, SEEK_SET);
8569 cf_chksum_long(detect, &file_checksum);
8573 // now compare the checksum/filesize against known #'s
8574 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8575 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8576 Game_weapons_tbl_valid = 1;
8583 DCF(wepspew, "display the checksum for the current weapons.tbl")
8586 CFILE *detect = cfopen("weapons.tbl", "rb");
8587 // get the long checksum of the file
8589 cfseek(detect, 0, SEEK_SET);
8590 cf_chksum_long(detect, &file_checksum);
8593 dc_printf("%d", file_checksum);
8596 // if the game is running using hacked data
8597 int game_hacked_data()
8600 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8608 void display_title_screen()
8610 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8611 ///int title_bitmap;
8614 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8615 if (title_bitmap == -1) {
8620 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8621 extern void d3d_start_frame();
8626 gr_set_bitmap(title_bitmap);
8632 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8633 extern void d3d_stop_frame();
8640 bm_unload(title_bitmap);
8641 #endif // FS2_DEMO || OEM_BUILD
8644 // return true if the game is running with "low memory", which is less than 48MB
8645 bool game_using_low_mem()
8647 if (Use_low_mem == 0) {