2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
18 * Revision 1.18 2002/06/16 04:46:33 relnev
19 * set up correct checksums for demo
21 * Revision 1.17 2002/06/09 04:41:17 relnev
22 * added copyright header
24 * Revision 1.16 2002/06/09 03:16:04 relnev
27 * removed unneeded asm, old sdl 2d setup.
29 * fixed crash caused by opengl_get_region.
31 * Revision 1.15 2002/06/05 08:05:28 relnev
32 * stub/warning removal.
34 * reworked the sound code.
36 * Revision 1.14 2002/06/05 04:03:32 relnev
37 * finished cfilesystem.
39 * removed some old code.
41 * fixed mouse save off-by-one.
45 * Revision 1.13 2002/06/02 04:26:34 relnev
48 * Revision 1.12 2002/06/02 00:31:35 relnev
49 * implemented osregistry
51 * Revision 1.11 2002/06/01 09:00:34 relnev
52 * silly debug memmanager
54 * Revision 1.10 2002/06/01 07:12:32 relnev
55 * a few NDEBUG updates.
57 * removed a few warnings.
59 * Revision 1.9 2002/05/31 03:05:59 relnev
62 * Revision 1.8 2002/05/29 02:52:32 theoddone33
63 * Enable OpenGL renderer
65 * Revision 1.7 2002/05/28 08:52:03 relnev
66 * implemented two assembly stubs.
68 * cleaned up a few warnings.
70 * added a little demo hackery to make it progress a little farther.
72 * Revision 1.6 2002/05/28 06:28:20 theoddone33
73 * Filesystem mods, actually reads some data files now
75 * Revision 1.5 2002/05/28 04:07:28 theoddone33
76 * New graphics stubbing arrangement
78 * Revision 1.4 2002/05/27 22:46:52 theoddone33
79 * Remove more undefined symbols
81 * Revision 1.3 2002/05/26 23:31:18 relnev
82 * added a few files that needed to be compiled
84 * freespace.cpp: now compiles
86 * Revision 1.2 2002/05/07 03:16:44 theoddone33
87 * The Great Newline Fix
89 * Revision 1.1.1.1 2002/05/03 03:28:09 root
93 * 201 6/16/00 3:15p Jefff
94 * sim of the year dvd version changes, a few german soty localization
97 * 200 11/03/99 11:06a Jefff
100 * 199 10/26/99 5:07p Jamest
101 * fixed jeffs dumb debug code
103 * 198 10/25/99 5:53p Jefff
104 * call control_config_common_init() on startup
106 * 197 10/14/99 10:18a Daveb
107 * Fixed incorrect CD checking problem on standalone server.
109 * 196 10/13/99 9:22a Daveb
110 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
111 * related to movies. Fixed launcher spawning from PXO screen.
113 * 195 10/06/99 11:05a Jefff
114 * new oem upsell 3 hotspot coords
116 * 194 10/06/99 10:31a Jefff
119 * 193 10/01/99 9:10a Daveb
122 * 192 9/15/99 4:57a Dave
123 * Updated ships.tbl checksum
125 * 191 9/15/99 3:58a Dave
126 * Removed framerate warning at all times.
128 * 190 9/15/99 3:16a Dave
129 * Remove mt-011.fs2 from the builtin mission list.
131 * 189 9/15/99 1:45a Dave
132 * Don't init joystick on standalone. Fixed campaign mode on standalone.
133 * Fixed no-score-report problem in TvT
135 * 188 9/14/99 6:08a Dave
136 * Updated (final) single, multi, and campaign list.
138 * 187 9/14/99 3:26a Dave
139 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
140 * respawn-too-early problem. Made a few crash points safe.
142 * 186 9/13/99 4:52p Dave
145 * 185 9/12/99 8:09p Dave
146 * Fixed problem where skip-training button would cause mission messages
147 * not to get paged out for the current mission.
149 * 184 9/10/99 11:53a Dave
150 * Shutdown graphics before sound to eliminate apparent lockups when
151 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
153 * 183 9/09/99 11:40p Dave
154 * Handle an Assert() in beam code. Added supernova sounds. Play the right
155 * 2 end movies properly, based upon what the player did in the mission.
157 * 182 9/08/99 10:29p Dave
158 * Make beam sound pausing and unpausing much safer.
160 * 181 9/08/99 10:01p Dave
161 * Make sure game won't run in a drive's root directory. Make sure
162 * standalone routes suqad war messages properly to the host.
164 * 180 9/08/99 3:22p Dave
165 * Updated builtin mission list.
167 * 179 9/08/99 12:01p Jefff
168 * fixed Game_builtin_mission_list typo on Training-2.fs2
170 * 178 9/08/99 9:48a Andsager
171 * Add force feedback for engine wash.
173 * 177 9/07/99 4:01p Dave
174 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
175 * does everything properly (setting up address when binding). Remove
176 * black rectangle background from UI_INPUTBOX.
178 * 176 9/13/99 2:40a Dave
179 * Comment in full 80 minute CD check for RELEASE_REAL builds.
181 * 175 9/06/99 6:38p Dave
182 * Improved CD detection code.
184 * 174 9/06/99 1:30a Dave
185 * Intermediate checkin. Started on enforcing CD-in-drive to play the
188 * 173 9/06/99 1:16a Dave
189 * Make sure the user sees the intro movie.
191 * 172 9/04/99 8:00p Dave
192 * Fixed up 1024 and 32 bit movie support.
194 * 171 9/03/99 1:32a Dave
195 * CD checking by act. Added support to play 2 cutscenes in a row
196 * seamlessly. Fixed super low level cfile bug related to files in the
197 * root directory of a CD. Added cheat code to set campaign mission # in
200 * 170 9/01/99 10:49p Dave
201 * Added nice SquadWar checkbox to the client join wait screen.
203 * 169 9/01/99 10:14a Dave
206 * 168 8/29/99 4:51p Dave
207 * Fixed damaged checkin.
209 * 167 8/29/99 4:18p Andsager
210 * New "burst" limit for friendly damage. Also credit more damage done
211 * against large friendly ships.
213 * 166 8/27/99 6:38p Alanl
214 * crush the blasted repeating messages bug
216 * 164 8/26/99 9:09p Dave
217 * Force framerate check in everything but a RELEASE_REAL build.
219 * 163 8/26/99 9:45a Dave
220 * First pass at easter eggs and cheats.
222 * 162 8/24/99 8:55p Dave
223 * Make sure nondimming pixels work properly in tech menu.
225 * 161 8/24/99 1:49a Dave
226 * Fixed client-side afterburner stuttering. Added checkbox for no version
227 * checking on PXO join. Made button info passing more friendly between
230 * 160 8/22/99 5:53p Dave
231 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
232 * instead of ship designations for multiplayer players.
234 * 159 8/22/99 1:19p Dave
235 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
236 * which d3d cards are detected.
238 * 158 8/20/99 2:09p Dave
239 * PXO banner cycling.
241 * 157 8/19/99 10:59a Dave
242 * Packet loss detection.
244 * 156 8/19/99 10:12a Alanl
245 * preload mission-specific messages on machines greater than 48MB
247 * 155 8/16/99 4:04p Dave
248 * Big honking checkin.
250 * 154 8/11/99 5:54p Dave
251 * Fixed collision problem. Fixed standalone ghost problem.
253 * 153 8/10/99 7:59p Jefff
256 * 152 8/10/99 6:54p Dave
257 * Mad optimizations. Added paging to the nebula effect.
259 * 151 8/10/99 3:44p Jefff
260 * loads Intelligence information on startup
262 * 150 8/09/99 3:47p Dave
263 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
264 * non-nebula missions.
266 * 149 8/09/99 2:21p Andsager
267 * Fix patching from multiplayer direct to launcher update tab.
269 * 148 8/09/99 10:36a Dave
270 * Version info for game.
272 * 147 8/06/99 9:46p Dave
273 * Hopefully final changes for the demo.
275 * 146 8/06/99 3:34p Andsager
276 * Make title version info "(D)" -> "D" show up nicely
278 * 145 8/06/99 2:59p Adamp
279 * Fixed NT launcher/update problem.
281 * 144 8/06/99 1:52p Dave
282 * Bumped up MAX_BITMAPS for the demo.
284 * 143 8/06/99 12:17p Andsager
285 * Demo: down to just 1 demo dog
287 * 142 8/05/99 9:39p Dave
288 * Yet another new checksum.
290 * 141 8/05/99 6:19p Dave
291 * New demo checksums.
293 * 140 8/05/99 5:31p Andsager
294 * Up demo version 1.01
296 * 139 8/05/99 4:22p Andsager
297 * No time limit on upsell screens. Reverse order of display of upsell
300 * 138 8/05/99 4:17p Dave
301 * Tweaks to client interpolation.
303 * 137 8/05/99 3:52p Danw
305 * 136 8/05/99 3:01p Danw
307 * 135 8/05/99 2:43a Anoop
308 * removed duplicate definition.
310 * 134 8/05/99 2:13a Dave
313 * 133 8/05/99 2:05a Dave
316 * 132 8/05/99 1:22a Andsager
319 * 131 8/04/99 9:51p Andsager
320 * Add title screen to demo
322 * 130 8/04/99 6:47p Jefff
323 * fixed link error resulting from #ifdefs
325 * 129 8/04/99 6:26p Dave
326 * Updated ship tbl checksum.
328 * 128 8/04/99 5:40p Andsager
329 * Add multiple demo dogs
331 * 127 8/04/99 5:36p Andsager
332 * Show upsell screens at end of demo campaign before returning to main
335 * 126 8/04/99 11:42a Danw
336 * tone down EAX reverb
338 * 125 8/04/99 11:23a Dave
339 * Updated demo checksums.
341 * 124 8/03/99 11:02p Dave
342 * Maybe fixed sync problems in multiplayer.
344 * 123 8/03/99 6:21p Jefff
347 * 122 8/03/99 3:44p Andsager
348 * Launch laucher if trying to run FS without first having configured
351 * 121 8/03/99 12:45p Dave
354 * 120 8/02/99 9:13p Dave
357 * 119 7/30/99 10:31p Dave
358 * Added comm menu to the configurable hud files.
360 * 118 7/30/99 5:17p Andsager
361 * first fs2demo checksums
363 * 117 7/29/99 3:09p Anoop
365 * 116 7/29/99 12:05a Dave
366 * Nebula speed optimizations.
368 * 115 7/27/99 8:59a Andsager
369 * Make major, minor version consistent for all builds. Only show major
370 * and minor for launcher update window.
372 * 114 7/26/99 5:50p Dave
373 * Revised ingame join. Better? We'll see....
375 * 113 7/26/99 5:27p Andsager
376 * Add training mission as builtin to demo build
378 * 112 7/24/99 1:54p Dave
379 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
382 * 111 7/22/99 4:00p Dave
383 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
385 * 110 7/21/99 8:10p Dave
386 * First run of supernova effect.
388 * 109 7/20/99 1:49p Dave
389 * Peter Drake build. Fixed some release build warnings.
391 * 108 7/19/99 2:26p Andsager
392 * set demo multiplayer missions
394 * 107 7/18/99 5:19p Dave
395 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
397 * 106 7/16/99 1:50p Dave
398 * 8 bit aabitmaps. yay.
400 * 105 7/15/99 3:07p Dave
401 * 32 bit detection support. Mouse coord commandline.
403 * 104 7/15/99 2:13p Dave
404 * Added 32 bit detection.
406 * 103 7/15/99 9:20a Andsager
407 * FS2_DEMO initial checkin
409 * 102 7/14/99 11:02a Dave
410 * Skill level default back to easy. Blech.
412 * 101 7/09/99 5:54p Dave
413 * Seperated cruiser types into individual types. Added tons of new
414 * briefing icons. Campaign screen.
416 * 100 7/08/99 4:43p Andsager
417 * New check for sparky_hi and print if not found.
419 * 99 7/08/99 10:53a Dave
420 * New multiplayer interpolation scheme. Not 100% done yet, but still
421 * better than the old way.
423 * 98 7/06/99 4:24p Dave
424 * Mid-level checkin. Starting on some potentially cool multiplayer
427 * 97 7/06/99 3:35p Andsager
428 * Allow movie to play before red alert mission.
430 * 96 7/03/99 5:50p Dave
431 * Make rotated bitmaps draw properly in padlock views.
433 * 95 7/02/99 9:55p Dave
434 * Player engine wash sound.
436 * 94 7/02/99 4:30p Dave
437 * Much more sophisticated lightning support.
439 * 93 6/29/99 7:52p Dave
440 * Put in exception handling in FS2.
442 * 92 6/22/99 9:37p Dave
443 * Put in pof spewing.
445 * 91 6/16/99 4:06p Dave
446 * New pilot info popup. Added new draw-bitmap-as-poly function.
448 * 90 6/15/99 1:56p Andsager
449 * For release builds, allow start up in high res only with
452 * 89 6/15/99 9:34a Dave
453 * Fixed key checking in single threaded version of the stamp notification
456 * 88 6/09/99 2:55p Andsager
457 * Allow multiple asteroid subtypes (of large, medium, small) and follow
460 * 87 6/08/99 1:14a Dave
461 * Multi colored hud test.
463 * 86 6/04/99 9:52a Dave
464 * Fixed some rendering problems.
466 * 85 6/03/99 10:15p Dave
467 * Put in temporary main hall screen.
469 * 84 6/02/99 6:18p Dave
470 * Fixed TNT lockup problems! Wheeeee!
472 * 83 6/01/99 3:52p Dave
473 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
474 * dead popup, pxo find player popup, pxo private room popup.
476 * 82 5/26/99 1:28p Jasenw
477 * changed coords for loading ani
479 * 81 5/26/99 11:46a Dave
480 * Added ship-blasting lighting and made the randomization of lighting
481 * much more customizable.
483 * 80 5/24/99 5:45p Dave
484 * Added detail levels to the nebula, with a decent speedup. Split nebula
485 * lightning into its own section.
503 #include "systemvars.h"
508 #include "starfield.h"
509 #include "lighting.h"
514 #include "fireballs.h"
518 #include "floating.h"
519 #include "gamesequence.h"
521 #include "optionsmenu.h"
522 #include "playermenu.h"
523 #include "trainingmenu.h"
524 #include "techmenu.h"
527 #include "hudmessage.h"
529 #include "missiongoals.h"
530 #include "missionparse.h"
535 #include "multiutil.h"
536 #include "multimsgs.h"
540 #include "freespace.h"
541 #include "managepilot.h"
543 #include "contexthelp.h"
546 #include "missionbrief.h"
547 #include "missiondebrief.h"
549 #include "missionshipchoice.h"
551 #include "hudconfig.h"
552 #include "controlsconfig.h"
553 #include "missionmessage.h"
554 #include "missiontraining.h"
556 #include "hudtarget.h"
560 #include "eventmusic.h"
561 #include "animplay.h"
562 #include "missionweaponchoice.h"
563 #include "missionlog.h"
564 #include "audiostr.h"
566 #include "missioncampaign.h"
568 #include "missionhotkey.h"
569 #include "objectsnd.h"
570 #include "cmeasure.h"
572 #include "linklist.h"
573 #include "shockwave.h"
574 #include "afterburner.h"
579 #include "stand_gui.h"
580 #include "pcxutils.h"
581 #include "hudtargetbox.h"
582 #include "multi_xfer.h"
583 #include "hudescort.h"
584 #include "multiutil.h"
587 #include "multiteamselect.h"
590 #include "readyroom.h"
591 #include "mainhallmenu.h"
592 #include "multilag.h"
594 #include "particle.h"
596 #include "multi_ingame.h"
597 #include "snazzyui.h"
598 #include "asteroid.h"
599 #include "popupdead.h"
600 #include "multi_voice.h"
601 #include "missioncmdbrief.h"
602 #include "redalert.h"
603 #include "gameplayhelp.h"
604 #include "multilag.h"
605 #include "staticrand.h"
606 #include "multi_pmsg.h"
607 #include "levelpaging.h"
608 #include "observer.h"
609 #include "multi_pause.h"
610 #include "multi_endgame.h"
611 #include "cutscenes.h"
612 #include "multi_respawn.h"
613 // #include "movie.h"
614 #include "multi_obj.h"
615 #include "multi_log.h"
617 #include "localize.h"
618 #include "osregistry.h"
619 #include "barracks.h"
620 #include "missionpause.h"
622 #include "alphacolors.h"
623 #include "objcollide.h"
626 #include "neblightning.h"
627 #include "shipcontrails.h"
630 #include "multi_dogfight.h"
631 #include "multi_rate.h"
632 #include "muzzleflash.h"
636 #include "mainhalltemp.h"
637 #include "exceptionhandler.h"
641 #include "supernova.h"
642 #include "hudshield.h"
643 // #include "names.h"
645 #include "missionloopbrief.h"
649 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
655 // 1.00.04 5/26/98 MWA -- going final (12 pm)
656 // 1.00.03 5/26/98 MWA -- going final (3 am)
657 // 1.00.02 5/25/98 MWA -- going final
658 // 1.00.01 5/25/98 MWA -- going final
659 // 0.90 5/21/98 MWA -- getting ready for final.
660 // 0.10 4/9/98. Set by MK.
662 // Demo version: (obsolete since DEMO codebase split from tree)
663 // 0.03 4/10/98 AL. Interplay rev
664 // 0.02 4/8/98 MK. Increased when this system was modified.
665 // 0.01 4/7/98? AL. First release to Interplay QA.
668 // 1.00 5/28/98 AL. First release to Interplay QA.
670 void game_level_init(int seed = -1);
671 void game_post_level_init();
672 void game_do_frame();
673 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
674 void game_reset_time();
675 void game_show_framerate(); // draws framerate in lower right corner
677 int Game_no_clear = 0;
679 int Pofview_running = 0;
680 int Nebedit_running = 0;
682 typedef struct big_expl_flash {
683 float max_flash_intensity; // max intensity
684 float cur_flash_intensity; // cur intensity
685 int flash_start; // start time
688 #define FRAME_FILTER 16
690 #define DEFAULT_SKILL_LEVEL 1
691 int Game_skill_level = DEFAULT_SKILL_LEVEL;
693 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
694 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
696 #define EXE_FNAME ("fs2.exe")
697 #define LAUNCHER_FNAME ("freespace2.exe")
699 // JAS: Code for warphole camera.
700 // Needs to be cleaned up.
701 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
702 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
703 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
704 matrix Camera_orient = IDENTITY_MATRIX;
705 float Camera_damping = 1.0f;
706 float Camera_time = 0.0f;
707 float Warpout_time = 0.0f;
708 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
709 int Warpout_sound = -1;
711 int Use_joy_mouse = 0;
712 int Use_palette_flash = 1;
714 int Use_fullscreen_at_startup = 0;
716 int Show_area_effect = 0;
717 object *Last_view_target = NULL;
719 int dogfight_blown = 0;
722 float frametimes[FRAME_FILTER];
723 float frametotal = 0.0f;
727 int Show_framerate = 0;
729 int Show_framerate = 1;
732 int Framerate_cap = 120;
735 int Show_target_debug_info = 0;
736 int Show_target_weapons = 0;
740 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
743 int Debug_octant = -1;
745 fix Game_time_compression = F1_0;
747 // if the ships.tbl the player has is valid
748 int Game_ships_tbl_valid = 0;
750 // if the weapons.tbl the player has is valid
751 int Game_weapons_tbl_valid = 0;
755 extern int Player_attacking_enabled;
759 int Pre_player_entry;
761 int Fred_running = 0;
762 char Game_current_mission_filename[MAX_FILENAME_LEN];
763 int game_single_step = 0;
764 int last_single_step=0;
766 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
767 extern int MSG_WINDOW_Y_START;
768 extern int MSG_WINDOW_HEIGHT;
770 int game_zbuffer = 1;
771 //static int Game_music_paused;
772 static int Game_paused;
776 #define EXPIRE_BAD_CHECKSUM 1
777 #define EXPIRE_BAD_TIME 2
779 extern void ssm_init();
780 extern void ssm_level_init();
781 extern void ssm_process();
783 // static variable to contain the time this version was built
784 // commented out for now until
785 // I figure out how to get the username into the file
786 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
788 // defines and variables used for dumping frame for making trailers.
790 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
791 int Debug_dump_trigger = 0;
792 int Debug_dump_frame_count;
793 int Debug_dump_frame_num = 0;
794 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
797 // amount of time to wait after the player has died before we display the death died popup
798 #define PLAYER_DIED_POPUP_WAIT 2500
799 int Player_died_popup_wait = -1;
800 int Player_multi_died_check = -1;
802 // builtin mission list stuff
804 int Game_builtin_mission_count = 6;
805 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
806 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
807 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
808 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
809 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
810 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
811 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
813 #elif defined(PD_BUILD)
814 int Game_builtin_mission_count = 4;
815 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
816 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
817 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
818 { "sm1-01", (FSB_FROM_VOLITION), "" },
819 { "sm1-05", (FSB_FROM_VOLITION), "" },
821 #elif defined(MULTIPLAYER_BETA)
822 int Game_builtin_mission_count = 17;
823 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
825 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
826 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
827 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
828 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
829 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
830 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
831 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
832 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
833 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
834 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
835 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
838 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
839 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
840 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
841 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
843 #elif defined(OEM_BUILD)
844 int Game_builtin_mission_count = 17;
845 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
846 // oem version - act 1 only
847 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
850 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
851 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
852 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
853 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
854 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
855 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
856 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
857 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
858 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
859 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
860 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
861 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
862 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
863 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
868 int Game_builtin_mission_count = 92;
869 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
870 // single player campaign
871 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
874 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
875 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
876 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
877 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
878 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
879 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
880 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
881 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
882 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
883 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
884 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
885 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
886 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
887 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
896 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
897 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
898 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
899 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
900 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
901 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
902 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
903 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
904 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
907 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
908 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
909 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
911 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
912 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 // multiplayer missions
923 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
924 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
925 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
929 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
936 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
939 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
977 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
978 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
979 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
980 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
985 // Internal function prototypes
986 void game_maybe_draw_mouse(float frametime);
987 void init_animating_pointer();
988 void load_animating_pointer(char *filename, int dx, int dy);
989 void unload_animating_pointer();
990 void game_do_training_checks();
991 void game_shutdown(void);
992 void game_show_event_debug(float frametime);
993 void game_event_debug_init();
995 void demo_upsell_show_screens();
996 void game_start_subspace_ambient_sound();
997 void game_stop_subspace_ambient_sound();
998 void verify_ships_tbl();
999 void verify_weapons_tbl();
1000 void display_title_screen();
1002 // loading background filenames
1003 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1004 "LoadingBG", // GR_640
1005 "2_LoadingBG" // GR_1024
1009 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1010 "Loading.ani", // GR_640
1011 "2_Loading.ani" // GR_1024
1014 #if defined(FS2_DEMO)
1015 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1019 #elif defined(OEM_BUILD)
1020 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1027 char Game_CDROM_dir[MAX_PATH_LEN];
1030 // How much RAM is on this machine. Set in WinMain
1031 uint Freespace_total_ram = 0;
1034 float Game_flash_red = 0.0f;
1035 float Game_flash_green = 0.0f;
1036 float Game_flash_blue = 0.0f;
1037 float Sun_spot = 0.0f;
1038 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1040 // game shudder stuff (in ms)
1041 int Game_shudder_time = -1;
1042 int Game_shudder_total = 0;
1043 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1046 sound_env Game_sound_env;
1047 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1048 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1050 int Game_sound_env_update_timestamp;
1052 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1055 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1057 fs_builtin_mission *game_find_builtin_mission(char *filename)
1061 // look through all existing builtin missions
1062 for(idx=0; idx<Game_builtin_mission_count; idx++){
1063 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1064 return &Game_builtin_mission_list[idx];
1072 int game_get_default_skill_level()
1074 return DEFAULT_SKILL_LEVEL;
1078 void game_flash_reset()
1080 Game_flash_red = 0.0f;
1081 Game_flash_green = 0.0f;
1082 Game_flash_blue = 0.0f;
1084 Big_expl_flash.max_flash_intensity = 0.0f;
1085 Big_expl_flash.cur_flash_intensity = 0.0f;
1086 Big_expl_flash.flash_start = 0;
1089 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1090 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1092 void game_framerate_check_init()
1094 // zero critical time
1095 Gf_critical_time = 0.0f;
1098 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1099 // if this is a glide card
1100 if(gr_screen.mode == GR_GLIDE){
1102 extern GrHwConfiguration hwconfig;
1105 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1106 Gf_critical = 15.0f;
1110 Gf_critical = 10.0f;
1115 Gf_critical = 15.0f;
1118 // d3d. only care about good cards here I guess (TNT)
1120 Gf_critical = 15.0f;
1123 // if this is a glide card
1124 if(gr_screen.mode == GR_GLIDE){
1126 extern GrHwConfiguration hwconfig;
1129 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1130 Gf_critical = 25.0f;
1134 Gf_critical = 20.0f;
1139 Gf_critical = 25.0f;
1142 // d3d. only care about good cards here I guess (TNT)
1144 Gf_critical = 25.0f;
1149 extern float Framerate;
1150 void game_framerate_check()
1154 // if the current framerate is above the critical level, add frametime
1155 if(Framerate >= Gf_critical){
1156 Gf_critical_time += flFrametime;
1159 if(!Show_framerate){
1163 // display if we're above the critical framerate
1164 if(Framerate < Gf_critical){
1165 gr_set_color_fast(&Color_bright_red);
1166 gr_string(200, y_start, "Framerate warning");
1171 // display our current pct of good frametime
1172 if(f2fl(Missiontime) >= 0.0f){
1173 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1176 gr_set_color_fast(&Color_bright_green);
1178 gr_set_color_fast(&Color_bright_red);
1181 gr_printf(200, y_start, "%d%%", (int)pct);
1188 // Adds a flash effect. These can be positive or negative.
1189 // The range will get capped at around -1 to 1, so stick
1190 // with a range like that.
1191 void game_flash( float r, float g, float b )
1193 Game_flash_red += r;
1194 Game_flash_green += g;
1195 Game_flash_blue += b;
1197 if ( Game_flash_red < -1.0f ) {
1198 Game_flash_red = -1.0f;
1199 } else if ( Game_flash_red > 1.0f ) {
1200 Game_flash_red = 1.0f;
1203 if ( Game_flash_green < -1.0f ) {
1204 Game_flash_green = -1.0f;
1205 } else if ( Game_flash_green > 1.0f ) {
1206 Game_flash_green = 1.0f;
1209 if ( Game_flash_blue < -1.0f ) {
1210 Game_flash_blue = -1.0f;
1211 } else if ( Game_flash_blue > 1.0f ) {
1212 Game_flash_blue = 1.0f;
1217 // Adds a flash for Big Ship explosions
1218 // cap range from 0 to 1
1219 void big_explosion_flash(float flash)
1221 Big_expl_flash.flash_start = timestamp(1);
1225 } else if (flash < 0.0f) {
1229 Big_expl_flash.max_flash_intensity = flash;
1230 Big_expl_flash.cur_flash_intensity = 0.0f;
1233 // Amount to diminish palette towards normal, per second.
1234 #define DIMINISH_RATE 0.75f
1235 #define SUN_DIMINISH_RATE 6.00f
1239 float sn_glare_scale = 1.7f;
1242 dc_get_arg(ARG_FLOAT);
1243 sn_glare_scale = Dc_arg_float;
1246 float Supernova_last_glare = 0.0f;
1247 void game_sunspot_process(float frametime)
1251 float Sun_spot_goal = 0.0f;
1254 sn_stage = supernova_active();
1256 // sunspot differently based on supernova stage
1258 // approaching. player still in control
1261 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1264 light_get_global_dir(&light_dir, 0);
1266 dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1269 // scale it some more
1270 dot = dot * (0.5f + (pct * 0.5f));
1273 Sun_spot_goal += (dot * sn_glare_scale);
1276 // draw the sun glow
1277 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1278 // draw the glow for this sun
1279 stars_draw_sun_glow(0);
1282 Supernova_last_glare = Sun_spot_goal;
1285 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1288 Sun_spot_goal = 0.9f;
1289 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1291 if(Sun_spot_goal > 1.0f){
1292 Sun_spot_goal = 1.0f;
1295 Sun_spot_goal *= sn_glare_scale;
1296 Supernova_last_glare = Sun_spot_goal;
1299 // fade to white. display dead popup
1302 Supernova_last_glare += (2.0f * flFrametime);
1303 if(Supernova_last_glare > 2.0f){
1304 Supernova_last_glare = 2.0f;
1307 Sun_spot_goal = Supernova_last_glare;
1314 // check sunspots for all suns
1315 n_lights = light_get_global_count();
1318 for(idx=0; idx<n_lights; idx++){
1319 //(vector *eye_pos, matrix *eye_orient)
1320 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1323 light_get_global_dir(&light_dir, idx);
1325 float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1327 Sun_spot_goal += (float)pow(dot,85.0f);
1329 // draw the glow for this sun
1330 stars_draw_sun_glow(idx);
1332 Sun_spot_goal = 0.0f;
1338 Sun_spot_goal = 0.0f;
1342 float dec_amount = frametime*SUN_DIMINISH_RATE;
1344 if ( Sun_spot < Sun_spot_goal ) {
1345 Sun_spot += dec_amount;
1346 if ( Sun_spot > Sun_spot_goal ) {
1347 Sun_spot = Sun_spot_goal;
1349 } else if ( Sun_spot > Sun_spot_goal ) {
1350 Sun_spot -= dec_amount;
1351 if ( Sun_spot < Sun_spot_goal ) {
1352 Sun_spot = Sun_spot_goal;
1358 // Call once a frame to diminish the
1359 // flash effect to 0.
1360 void game_flash_diminish(float frametime)
1362 float dec_amount = frametime*DIMINISH_RATE;
1364 if ( Game_flash_red > 0.0f ) {
1365 Game_flash_red -= dec_amount;
1366 if ( Game_flash_red < 0.0f )
1367 Game_flash_red = 0.0f;
1369 Game_flash_red += dec_amount;
1370 if ( Game_flash_red > 0.0f )
1371 Game_flash_red = 0.0f;
1374 if ( Game_flash_green > 0.0f ) {
1375 Game_flash_green -= dec_amount;
1376 if ( Game_flash_green < 0.0f )
1377 Game_flash_green = 0.0f;
1379 Game_flash_green += dec_amount;
1380 if ( Game_flash_green > 0.0f )
1381 Game_flash_green = 0.0f;
1384 if ( Game_flash_blue > 0.0f ) {
1385 Game_flash_blue -= dec_amount;
1386 if ( Game_flash_blue < 0.0f )
1387 Game_flash_blue = 0.0f;
1389 Game_flash_blue += dec_amount;
1390 if ( Game_flash_blue > 0.0f )
1391 Game_flash_blue = 0.0f;
1394 // update big_explosion_cur_flash
1395 #define TIME_UP 1500
1396 #define TIME_DOWN 2500
1397 int duration = TIME_UP + TIME_DOWN;
1398 int time = timestamp_until(Big_expl_flash.flash_start);
1399 if (time > -duration) {
1401 if (time < TIME_UP) {
1402 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1405 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1409 if ( Use_palette_flash ) {
1411 // static int or=0, og=0, ob=0;
1413 // Change the 200 to change the color range of colors.
1414 r = fl2i( Game_flash_red*128.0f );
1415 g = fl2i( Game_flash_green*128.0f );
1416 b = fl2i( Game_flash_blue*128.0f );
1418 if ( Sun_spot > 0.0f ) {
1419 r += fl2i(Sun_spot*128.0f);
1420 g += fl2i(Sun_spot*128.0f);
1421 b += fl2i(Sun_spot*128.0f);
1424 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1425 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1426 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1427 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1430 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1431 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1432 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1434 if ( (r!=0) || (g!=0) || (b!=0) ) {
1435 gr_flash( r, g, b );
1437 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1448 void game_level_close()
1450 // De-Initialize the game subsystems
1451 message_mission_shutdown();
1452 event_music_level_close();
1453 game_stop_looped_sounds();
1455 obj_snd_level_close(); // uninit object-linked persistant sounds
1456 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1457 anim_level_close(); // stop and clean up any anim instances
1458 shockwave_level_close();
1459 fireball_level_close();
1461 mission_event_shutdown();
1462 asteroid_level_close();
1463 model_cache_reset(); // Reset/free all the model caching stuff
1464 flak_level_close(); // unload flak stuff
1465 neb2_level_close(); // shutdown gaseous nebula stuff
1468 mflash_level_close();
1470 audiostream_unpause_all();
1475 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1476 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1477 void game_level_init(int seed)
1479 // seed the random number generator
1481 // if no seed was passed, seed the generator either from the time value, or from the
1482 // netgame security flags -- ensures that all players in multiplayer game will have the
1483 // same randon number sequence (with static rand functions)
1484 if ( Game_mode & GM_NORMAL ) {
1485 Game_level_seed = time(NULL);
1487 Game_level_seed = Netgame.security;
1490 // mwa 9/17/98 -- maybe this assert isn't needed????
1491 Assert( !(Game_mode & GM_MULTIPLAYER) );
1492 Game_level_seed = seed;
1494 srand( Game_level_seed );
1496 // semirand function needs to get re-initted every time in multiplayer
1497 if ( Game_mode & GM_MULTIPLAYER ){
1503 Key_normal_game = (Game_mode & GM_NORMAL);
1506 Game_shudder_time = -1;
1508 // Initialize the game subsystems
1509 // timestamp_reset(); // Must be inited before everything else
1511 game_reset_time(); // resets time, and resets saved time too
1513 obj_init(); // Must be inited before the other systems
1514 model_free_all(); // Free all existing models
1515 mission_brief_common_init(); // Free all existing briefing/debriefing text
1516 weapon_level_init();
1517 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1519 player_level_init();
1520 shipfx_flash_init(); // Init the ship gun flash system.
1521 game_flash_reset(); // Reset the flash effect
1522 particle_init(); // Reset the particle system
1526 shield_hit_init(); // Initialize system for showing shield hits
1527 radar_mission_init();
1528 mission_init_goals();
1531 obj_snd_level_init(); // init object-linked persistant sounds
1533 shockwave_level_init();
1534 afterburner_level_init();
1535 scoring_level_init( &Player->stats );
1537 asteroid_level_init();
1538 control_config_clear_used_status();
1539 collide_ship_ship_sounds_init();
1541 Pre_player_entry = 1; // Means the player has not yet entered.
1542 Entry_delay_time = 0; // Could get overwritten in mission read.
1543 fireball_preload(); // page in warphole bitmaps
1545 flak_level_init(); // initialize flak - bitmaps, etc
1546 ct_level_init(); // initialize ships contrails, etc
1547 awacs_level_init(); // initialize AWACS
1548 beam_level_init(); // initialize beam weapons
1549 mflash_level_init();
1551 supernova_level_init();
1553 // multiplayer dogfight hack
1556 shipfx_engine_wash_level_init();
1560 Last_view_target = NULL;
1565 // campaign wasn't ended
1566 Campaign_ended_in_mission = 0;
1569 // called when a mission is over -- does server specific stuff.
1570 void freespace_stop_mission()
1573 Game_mode &= ~GM_IN_MISSION;
1576 // called at frame interval to process networking stuff
1577 void game_do_networking()
1579 Assert( Net_player != NULL );
1580 if (!(Game_mode & GM_MULTIPLAYER)){
1584 // see if this player should be reading/writing data. Bit is set when at join
1585 // screen onward until quits back to main menu.
1586 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1590 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1593 multi_pause_do_frame();
1598 // Loads the best palette for this level, based
1599 // on nebula color and hud color. You could just call palette_load_table with
1600 // the appropriate filename, but who wants to do that.
1601 void game_load_palette()
1603 char palette_filename[1024];
1605 // We only use 3 hud colors right now
1606 // Assert( HUD_config.color >= 0 );
1607 // Assert( HUD_config.color <= 2 );
1609 Assert( Mission_palette >= 0 );
1610 Assert( Mission_palette <= 98 );
1612 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1613 strcpy( palette_filename, NOX("gamepalette-subspace") );
1615 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1618 mprintf(( "Loading palette %s\n", palette_filename ));
1620 // palette_load_table(palette_filename);
1623 void game_post_level_init()
1625 // Stuff which gets called after mission is loaded. Because player isn't created until
1626 // after mission loads, some things must get initted after the level loads
1628 model_level_post_init();
1631 hud_setup_escort_list();
1632 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1638 game_event_debug_init();
1641 training_mission_init();
1642 asteroid_create_all();
1644 game_framerate_check_init();
1648 // An estimate as to how high the count passed to game_loading_callback will go.
1649 // This is just a guess, it seems to always be about the same. The count is
1650 // proportional to the code being executed, not the time, so this works good
1651 // for a bar, assuming the code does about the same thing each time you
1652 // load a level. You can find this value by looking at the return value
1653 // of game_busy_callback(NULL), which I conveniently print out to the
1654 // debug output window with the '=== ENDING LOAD ==' stuff.
1655 //#define COUNT_ESTIMATE 3706
1656 #define COUNT_ESTIMATE 1111
1658 int Game_loading_callback_inited = 0;
1660 int Game_loading_background = -1;
1661 anim * Game_loading_ani = NULL;
1662 anim_instance *Game_loading_ani_instance;
1663 int Game_loading_frame=-1;
1665 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1674 // This gets called 10x per second and count is the number of times
1675 // game_busy() has been called since the current callback function
1677 void game_loading_callback(int count)
1679 game_do_networking();
1681 Assert( Game_loading_callback_inited==1 );
1682 Assert( Game_loading_ani != NULL );
1684 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1685 if ( framenum > Game_loading_ani->total_frames-1 ) {
1686 framenum = Game_loading_ani->total_frames-1;
1687 } else if ( framenum < 0 ) {
1692 while ( Game_loading_frame < framenum ) {
1693 Game_loading_frame++;
1694 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1698 if ( cbitmap > -1 ) {
1699 if ( Game_loading_background > -1 ) {
1700 gr_set_bitmap( Game_loading_background );
1704 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1705 gr_set_bitmap( cbitmap );
1706 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1708 bm_release(cbitmap);
1714 void game_loading_callback_init()
1716 Assert( Game_loading_callback_inited==0 );
1718 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1719 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1722 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1723 Assert( Game_loading_ani != NULL );
1724 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1725 Assert( Game_loading_ani_instance != NULL );
1726 Game_loading_frame = -1;
1728 Game_loading_callback_inited = 1;
1730 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1735 void game_loading_callback_close()
1737 Assert( Game_loading_callback_inited==1 );
1739 // Make sure bar shows all the way over.
1740 game_loading_callback(COUNT_ESTIMATE);
1742 int real_count = game_busy_callback( NULL );
1745 Game_loading_callback_inited = 0;
1748 mprintf(( "=================== ENDING LOAD ================\n" ));
1749 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1750 mprintf(( "================================================\n" ));
1752 // to remove warnings in release build
1756 free_anim_instance(Game_loading_ani_instance);
1757 Game_loading_ani_instance = NULL;
1758 anim_free(Game_loading_ani);
1759 Game_loading_ani = NULL;
1761 bm_release( Game_loading_background );
1762 common_free_interface_palette(); // restore game palette
1763 Game_loading_background = -1;
1765 gr_set_font( FONT1 );
1768 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1770 void game_maybe_update_sound_environment()
1772 // do nothing for now
1775 // Assign the sound environment for the game, based on the current mission
1777 void game_assign_sound_environment()
1780 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1781 Game_sound_env.id = SND_ENV_DRUGGED;
1782 Game_sound_env.volume = 0.800f;
1783 Game_sound_env.damping = 1.188f;
1784 Game_sound_env.decay = 6.392f;
1786 } else if (Num_asteroids > 30) {
1787 Game_sound_env.id = SND_ENV_AUDITORIUM;
1788 Game_sound_env.volume = 0.603f;
1789 Game_sound_env.damping = 0.5f;
1790 Game_sound_env.decay = 4.279f;
1793 Game_sound_env = Game_default_sound_env;
1797 Game_sound_env = Game_default_sound_env;
1798 Game_sound_env_update_timestamp = timestamp(1);
1801 // function which gets called before actually entering the mission. It is broken down into a funciton
1802 // since it will get called in one place from a single player game and from another place for
1803 // a multiplayer game
1804 void freespace_mission_load_stuff()
1806 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1807 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1808 if(!(Game_mode & GM_STANDALONE_SERVER)){
1810 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1812 game_loading_callback_init();
1814 event_music_level_init(); // preloads the first 2 seconds for each event music track
1817 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1820 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1823 ship_assign_sound_all(); // assign engine sounds to ships
1824 game_assign_sound_environment(); // assign the sound environment for this mission
1827 // call function in missionparse.cpp to fixup player/ai stuff.
1828 mission_parse_fixup_players();
1831 // Load in all the bitmaps for this level
1836 game_loading_callback_close();
1838 // the only thing we need to call on the standalone for now.
1840 // call function in missionparse.cpp to fixup player/ai stuff.
1841 mission_parse_fixup_players();
1843 // Load in all the bitmaps for this level
1849 uint load_mission_load;
1850 uint load_post_level_init;
1851 uint load_mission_stuff;
1853 // tells the server to load the mission and initialize structures
1854 int game_start_mission()
1856 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1858 load_gl_init = time(NULL);
1860 load_gl_init = time(NULL) - load_gl_init;
1862 if (Game_mode & GM_MULTIPLAYER) {
1863 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1865 // clear multiplayer stats
1866 init_multiplayer_stats();
1869 load_mission_load = time(NULL);
1870 if (mission_load()) {
1871 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1872 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1873 gameseq_post_event(GS_EVENT_MAIN_MENU);
1875 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1880 load_mission_load = time(NULL) - load_mission_load;
1882 // If this is a red alert mission in campaign mode, bash wingman status
1883 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1884 red_alert_bash_wingman_status();
1887 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1888 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1889 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1890 // game_load_palette();
1893 load_post_level_init = time(NULL);
1894 game_post_level_init();
1895 load_post_level_init = time(NULL) - load_post_level_init;
1899 void Do_model_timings_test();
1900 Do_model_timings_test();
1904 load_mission_stuff = time(NULL);
1905 freespace_mission_load_stuff();
1906 load_mission_stuff = time(NULL) - load_mission_stuff;
1911 int Interface_framerate = 0;
1914 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1915 DCF_BOOL( show_framerate, Show_framerate )
1916 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1917 DCF_BOOL( show_target_weapons, Show_target_weapons )
1918 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1919 DCF_BOOL( sound, Sound_enabled )
1920 DCF_BOOL( zbuffer, game_zbuffer )
1921 DCF_BOOL( shield_system, New_shield_system )
1922 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1923 DCF_BOOL( player_attacking, Player_attacking_enabled )
1924 DCF_BOOL( show_waypoints, Show_waypoints )
1925 DCF_BOOL( show_area_effect, Show_area_effect )
1926 DCF_BOOL( show_net_stats, Show_net_stats )
1927 DCF_BOOL( log, Log_debug_output_to_file )
1928 DCF_BOOL( training_msg_method, Training_msg_method )
1929 DCF_BOOL( show_player_pos, Show_player_pos )
1930 DCF_BOOL(i_framerate, Interface_framerate )
1932 DCF(show_mem,"Toggles showing mem usage")
1935 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1936 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1937 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1938 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1944 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1946 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1947 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1951 DCF(show_cpu,"Toggles showing cpu usage")
1954 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1955 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1956 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1957 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1963 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1965 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1966 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1973 // AL 4-8-98: always allow players to display their framerate
1976 DCF_BOOL( show_framerate, Show_framerate )
1983 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1986 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1987 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1988 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1989 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1991 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" );
1992 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1994 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1997 DCF(palette_flash,"Toggles palette flash effect on/off")
2000 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2001 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2002 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2003 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2005 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2006 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2009 int Use_low_mem = 0;
2011 DCF(low_mem,"Uses low memory settings regardless of RAM")
2014 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2015 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2016 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2017 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2019 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2020 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2022 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2028 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2031 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2032 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2033 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2034 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2036 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2037 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2038 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2042 int Framerate_delay = 0;
2044 float Freespace_gamma = 1.0f;
2046 DCF(gamma,"Sets Gamma factor")
2049 dc_get_arg(ARG_FLOAT|ARG_NONE);
2050 if ( Dc_arg_type & ARG_FLOAT ) {
2051 Freespace_gamma = Dc_arg_float;
2053 dc_printf( "Gamma reset to 1.0f\n" );
2054 Freespace_gamma = 1.0f;
2056 if ( Freespace_gamma < 0.1f ) {
2057 Freespace_gamma = 0.1f;
2058 } else if ( Freespace_gamma > 5.0f ) {
2059 Freespace_gamma = 5.0f;
2061 gr_set_gamma(Freespace_gamma);
2063 char tmp_gamma_string[32];
2064 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2065 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2069 dc_printf( "Usage: gamma <float>\n" );
2070 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2071 Dc_status = 0; // don't print status if help is printed. Too messy.
2075 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2084 Game_current_mission_filename[0] = 0;
2086 // seed the random number generator
2087 Game_init_seed = time(NULL);
2088 srand( Game_init_seed );
2090 Framerate_delay = 0;
2096 extern void bm_init();
2102 // Initialize the timer before the os
2110 GetCurrentDirectory(1024, whee);
2113 getcwd (whee, 1024);
2116 strcat(whee, EXE_FNAME);
2118 //Initialize the libraries
2119 s1 = timer_get_milliseconds();
2120 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2123 e1 = timer_get_milliseconds();
2125 // time a bunch of cfopens
2127 s2 = timer_get_milliseconds();
2129 for(int idx=0; idx<10000; idx++){
2130 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2135 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2137 e2 = timer_get_milliseconds();
2140 if (Is_standalone) {
2141 std_init_standalone();
2143 os_init( Osreg_class_name, Osreg_app_name );
2144 os_set_title(Osreg_title);
2147 // initialize localization module. Make sure this is down AFTER initialzing OS.
2148 // int t1 = timer_get_milliseconds();
2151 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2153 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2156 // verify that he has a valid weapons.tbl
2157 verify_weapons_tbl();
2159 // Output version numbers to registry for auto patching purposes
2160 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2161 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2162 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2164 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2165 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2166 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2169 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2173 Asteroids_enabled = 1;
2176 /////////////////////////////
2178 /////////////////////////////
2183 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2184 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2186 if (!stricmp(ptr, NOX("no sound"))) {
2187 Cmdline_freespace_no_sound = 1;
2189 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2191 } else if (!stricmp(ptr, NOX("EAX"))) {
2196 if (!Is_standalone) {
2197 snd_init(use_a3d, use_eax);
2199 /////////////////////////////
2201 /////////////////////////////
2203 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2206 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);
2208 // fire up the UpdateLauncher executable
2210 PROCESS_INFORMATION pi;
2212 memset( &si, 0, sizeof(STARTUPINFO) );
2215 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2216 NULL, // pointer to command line string
2217 NULL, // pointer to process security attributes
2218 NULL, // pointer to thread security attributes
2219 FALSE, // handle inheritance flag
2220 CREATE_DEFAULT_ERROR_MODE, // creation flags
2221 NULL, // pointer to new environment block
2222 NULL, // pointer to current directory name
2223 &si, // pointer to STARTUPINFO
2224 &pi // pointer to PROCESS_INFORMATION
2227 // If the Launcher could not be started up, let the user know
2229 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2238 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2240 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);
2248 // check for hi res pack file
2249 int has_sparky_hi = 0;
2251 // check if sparky_hi exists -- access mode 0 means does file exist
2254 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2257 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2260 // see if we've got 32 bit in the string
2261 if(strstr(ptr, "32 bit")){
2268 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2270 // always 640 for E3
2271 gr_init(GR_640, GR_GLIDE);
2273 // regular or hi-res ?
2275 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2277 if(strstr(ptr, NOX("(1024x768)"))){
2279 gr_init(GR_1024, GR_GLIDE);
2281 gr_init(GR_640, GR_GLIDE);
2284 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2286 // always 640 for E3
2288 gr_init(GR_640, GR_DIRECT3D, depth);
2290 // regular or hi-res ?
2292 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2294 if(strstr(ptr, NOX("(1024x768)"))){
2298 gr_init(GR_1024, GR_DIRECT3D, depth);
2302 gr_init(GR_640, GR_DIRECT3D, depth);
2308 if ( Use_fullscreen_at_startup && !Is_standalone) {
2309 gr_init(GR_640, GR_DIRECTDRAW);
2311 gr_init(GR_640, GR_SOFTWARE);
2314 if ( !Is_standalone ) {
2315 gr_init(GR_640, GR_DIRECTDRAW);
2317 gr_init(GR_640, GR_SOFTWARE);
2322 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2323 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2324 gr_init(GR_1024, GR_OPENGL);
2326 gr_init(GR_640, GR_OPENGL);
2330 gr_init(GR_640, GR_SOFTWARE);
2335 extern int Gr_inited;
2336 if(trying_d3d && !Gr_inited){
2338 extern char Device_init_error[512];
2339 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2348 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2349 Freespace_gamma = (float)atof(ptr);
2350 if ( Freespace_gamma == 0.0f ) {
2351 Freespace_gamma = 1.80f;
2352 } else if ( Freespace_gamma < 0.1f ) {
2353 Freespace_gamma = 0.1f;
2354 } else if ( Freespace_gamma > 5.0f ) {
2355 Freespace_gamma = 5.0f;
2357 char tmp_gamma_string[32];
2358 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2359 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2361 gr_set_gamma(Freespace_gamma);
2363 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2366 display_title_screen();
2370 // attempt to load up master tracker registry info (login and password)
2371 Multi_tracker_id = -1;
2373 // pxo login and password
2374 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2376 nprintf(("Network","Error reading in PXO login data\n"));
2377 strcpy(Multi_tracker_login,"");
2379 strcpy(Multi_tracker_login,ptr);
2381 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2383 nprintf(("Network","Error reading PXO password\n"));
2384 strcpy(Multi_tracker_passwd,"");
2386 strcpy(Multi_tracker_passwd,ptr);
2389 // pxo squad name and password
2390 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2392 nprintf(("Network","Error reading in PXO squad name\n"));
2393 strcpy(Multi_tracker_squad_name, "");
2395 strcpy(Multi_tracker_squad_name, ptr);
2398 // If less than 48MB of RAM, use low memory model.
2401 (Freespace_total_ram < 48*1024*1024) ||
2404 mprintf(( "Using normal memory settings...\n" ));
2405 bm_set_low_mem(1); // Use every other frame of bitmaps
2407 mprintf(( "Using high memory settings...\n" ));
2408 bm_set_low_mem(0); // Use all frames of bitmaps
2411 // load non-darkening pixel defs
2412 palman_load_pixels();
2414 // hud shield icon stuff
2415 hud_shield_game_init();
2417 control_config_common_init(); // sets up localization stuff in the control config
2423 gamesnd_parse_soundstbl();
2428 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2433 player_controls_init();
2436 //if(!Is_standalone){
2444 ship_init(); // read in ships.tbl
2446 mission_campaign_init(); // load in the default campaign
2448 // navmap_init(); // init the navigation map system
2449 context_help_init();
2450 techroom_intel_init(); // parse species.tbl, load intel info
2452 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2453 init_animating_pointer();
2455 mission_brief_common_init(); // Mark all the briefing structures as empty.
2456 gr_font_init(); // loads up all fonts
2458 neb2_init(); // fullneb stuff
2462 player_tips_init(); // helpful tips
2465 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2466 pilot_load_pic_list();
2467 pilot_load_squad_pic_list();
2469 load_animating_pointer(NOX("cursor"), 0, 0);
2471 // initialize alpha colors
2472 alpha_colors_init();
2475 // Game_music_paused = 0;
2482 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2483 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2485 mprintf(("cfile_init() took %d\n", e1 - s1));
2486 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2489 char transfer_text[128];
2491 float Start_time = 0.0f;
2493 float Framerate = 0.0f;
2495 float Timing_total = 0.0f;
2496 float Timing_render2 = 0.0f;
2497 float Timing_render3 = 0.0f;
2498 float Timing_flip = 0.0f;
2499 float Timing_clear = 0.0f;
2501 MONITOR(NumPolysDrawn);
2507 void game_get_framerate()
2509 char text[128] = "";
2511 if ( frame_int == -1 ) {
2513 for (i=0; i<FRAME_FILTER; i++ ) {
2514 frametimes[i] = 0.0f;
2519 frametotal -= frametimes[frame_int];
2520 frametotal += flFrametime;
2521 frametimes[frame_int] = flFrametime;
2522 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2524 if ( frametotal != 0.0 ) {
2525 if ( Framecount >= FRAME_FILTER )
2526 Framerate = FRAME_FILTER / frametotal;
2528 Framerate = Framecount / frametotal;
2529 sprintf( text, NOX("FPS: %.1f"), Framerate );
2531 sprintf( text, NOX("FPS: ?") );
2535 if (Show_framerate) {
2536 gr_set_color_fast(&HUD_color_debug);
2537 gr_string( 570, 2, text );
2541 void game_show_framerate()
2545 cur_time = f2fl(timer_get_approx_seconds());
2546 if (cur_time - Start_time > 30.0f) {
2547 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2548 Start_time += 1000.0f;
2551 //mprintf(( "%s\n", text ));
2554 if ( Debug_dump_frames )
2558 // possibly show control checking info
2559 control_check_indicate();
2561 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2562 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2563 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2564 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2567 if ( Show_cpu == 1 ) {
2572 dy = gr_get_font_height() + 1;
2574 gr_set_color_fast(&HUD_color_debug);
2578 extern int D3D_textures_in;
2579 extern int D3D_textures_in_frame;
2580 extern int Glide_textures_in;
2581 extern int Glide_textures_in_frame;
2582 extern int Glide_explosion_vram;
2583 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2585 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2587 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2591 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2593 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2595 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2597 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2599 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2604 extern int Num_pairs; // Number of object pairs that were checked.
2605 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2608 extern int Num_pairs_checked; // What percent of object pairs were checked.
2609 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2611 Num_pairs_checked = 0;
2615 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2618 if ( Timing_total > 0.01f ) {
2619 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2621 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2623 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2625 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2627 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2637 dy = gr_get_font_height() + 1;
2639 gr_set_color_fast(&HUD_color_debug);
2642 extern int TotalRam;
2643 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2648 extern int Model_ram;
2649 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2653 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2655 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2657 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2661 extern int D3D_textures_in;
2662 extern int Glide_textures_in;
2663 extern int Glide_textures_in_frame;
2664 extern int Glide_explosion_vram;
2665 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2667 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2669 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2676 if ( Show_player_pos ) {
2680 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));
2683 MONITOR_INC(NumPolys, modelstats_num_polys);
2684 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2685 MONITOR_INC(NumVerts, modelstats_num_verts );
2687 modelstats_num_polys = 0;
2688 modelstats_num_polys_drawn = 0;
2689 modelstats_num_verts = 0;
2690 modelstats_num_sortnorms = 0;
2694 void game_show_standalone_framerate()
2696 float frame_rate=30.0f;
2697 if ( frame_int == -1 ) {
2699 for (i=0; i<FRAME_FILTER; i++ ) {
2700 frametimes[i] = 0.0f;
2705 frametotal -= frametimes[frame_int];
2706 frametotal += flFrametime;
2707 frametimes[frame_int] = flFrametime;
2708 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2710 if ( frametotal != 0.0 ) {
2711 if ( Framecount >= FRAME_FILTER ){
2712 frame_rate = FRAME_FILTER / frametotal;
2714 frame_rate = Framecount / frametotal;
2717 std_set_standalone_fps(frame_rate);
2721 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2722 void game_show_time_left()
2726 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2727 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2728 // checking how much time is left
2730 if ( Mission_end_time == -1 ){
2734 diff = f2i(Mission_end_time - Missiontime);
2735 // be sure to bash to 0. diff could be negative on frame that we quit mission
2740 hud_set_default_color();
2741 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2744 //========================================================================================
2745 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2746 //========================================================================================
2750 DCF(ai_pause,"Pauses ai")
2753 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2754 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2755 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2756 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2759 obj_init_all_ships_physics();
2762 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2763 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2766 DCF(single_step,"Single steps the game")
2769 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2770 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2771 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2772 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2774 last_single_step = 0; // Make so single step waits a frame before stepping
2777 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2778 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2781 DCF_BOOL(physics_pause, physics_paused)
2782 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2783 DCF_BOOL(ai_firing, Ai_firing_enabled )
2785 // Create some simple aliases to these commands...
2786 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2787 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2788 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2789 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2790 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2793 //========================================================================================
2794 //========================================================================================
2797 void game_training_pause_do()
2801 key = game_check_key();
2803 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2810 void game_increase_skill_level()
2813 if (Game_skill_level >= NUM_SKILL_LEVELS){
2814 Game_skill_level = 0;
2818 int Player_died_time;
2820 int View_percent = 100;
2823 DCF(view, "Sets the percent of the 3d view to render.")
2826 dc_get_arg(ARG_INT);
2827 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2828 View_percent = Dc_arg_int;
2830 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2836 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2840 dc_printf("View is set to %d%%\n", View_percent );
2845 // Set the clip region for the 3d rendering window
2846 void game_set_view_clip()
2848 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2849 // Set the clip region for the letterbox "dead view"
2850 int yborder = gr_screen.max_h/4;
2852 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2853 // J.S. I've changed my ways!! See the new "no constants" code!!!
2854 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2856 // Set the clip region for normal view
2857 if ( View_percent >= 100 ) {
2860 int xborder, yborder;
2862 if ( View_percent < 5 ) {
2866 float fp = i2fl(View_percent)/100.0f;
2867 int fi = fl2i(fl_sqrt(fp)*100.0f);
2868 if ( fi > 100 ) fi=100;
2870 xborder = ( gr_screen.max_w*(100-fi) )/200;
2871 yborder = ( gr_screen.max_h*(100-fi) )/200;
2873 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2879 void show_debug_stuff()
2882 int laser_count = 0, missile_count = 0;
2884 for (i=0; i<MAX_OBJECTS; i++) {
2885 if (Objects[i].type == OBJ_WEAPON){
2886 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2888 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2894 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2897 extern int Tool_enabled;
2902 int tst_bitmap = -1;
2904 float tst_offset, tst_offset_total;
2907 void game_tst_frame_pre()
2915 g3_rotate_vertex(&v, &tst_pos);
2916 g3_project_vertex(&v);
2919 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2923 // big ship? always tst
2925 // within 3000 meters
2926 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2930 // within 300 meters
2931 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2938 void game_tst_frame()
2948 tst_time = time(NULL);
2950 // load the tst bitmap
2951 switch((int)frand_range(0.0f, 3.0)){
2953 tst_bitmap = bm_load("ig_jim");
2955 mprintf(("TST 0\n"));
2959 tst_bitmap = bm_load("ig_kan");
2961 mprintf(("TST 1\n"));
2965 tst_bitmap = bm_load("ig_jim");
2967 mprintf(("TST 2\n"));
2971 tst_bitmap = bm_load("ig_kan");
2973 mprintf(("TST 3\n"));
2982 // get the tst bitmap dimensions
2984 bm_get_info(tst_bitmap, &w, &h);
2987 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2989 snd_play(&Snds[SND_VASUDAN_BUP]);
2991 // tst x and direction
2995 tst_offset_total = (float)w;
2996 tst_offset = (float)w;
2998 tst_x = (float)gr_screen.max_w;
2999 tst_offset_total = (float)-w;
3000 tst_offset = (float)w;
3008 float diff = (tst_offset_total / 0.5f) * flFrametime;
3014 tst_offset -= fl_abs(diff);
3015 } else if(tst_mode == 2){
3018 tst_offset -= fl_abs(diff);
3022 gr_set_bitmap(tst_bitmap);
3023 gr_bitmap((int)tst_x, (int)tst_y);
3026 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3030 // if we passed the switch point
3031 if(tst_offset <= 0.0f){
3036 tst_stamp = timestamp(1000);
3037 tst_offset = fl_abs(tst_offset_total);
3048 void game_tst_mark(object *objp, ship *shipp)
3057 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3060 sip = &Ship_info[shipp->ship_info_index];
3067 tst_pos = objp->pos;
3068 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3074 extern void render_shields();
3076 void player_repair_frame(float frametime)
3078 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3080 for(idx=0;idx<MAX_PLAYERS;idx++){
3083 np = &Net_players[idx];
3085 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)){
3087 // don't rearm/repair if the player is dead or dying/departing
3088 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3089 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3094 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3095 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3101 #define NUM_FRAMES_TEST 300
3102 #define NUM_MIXED_SOUNDS 16
3103 void do_timing_test(float flFrametime)
3105 static int framecount = 0;
3106 static int test_running = 0;
3107 static float test_time = 0.0f;
3109 static int snds[NUM_MIXED_SOUNDS];
3112 if ( test_running ) {
3114 test_time += flFrametime;
3115 if ( framecount >= NUM_FRAMES_TEST ) {
3117 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3118 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3123 if ( Test_begin == 1 ) {
3129 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3132 // start looping digital sounds
3133 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3134 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3141 DCF(dcf_fov, "Change the field of view")
3144 dc_get_arg(ARG_FLOAT|ARG_NONE);
3145 if ( Dc_arg_type & ARG_NONE ) {
3146 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3147 dc_printf( "Zoom factor reset\n" );
3149 if ( Dc_arg_type & ARG_FLOAT ) {
3150 if (Dc_arg_float < 0.25f) {
3151 Viewer_zoom = 0.25f;
3152 dc_printf("Zoom factor pinned at 0.25.\n");
3153 } else if (Dc_arg_float > 1.25f) {
3154 Viewer_zoom = 1.25f;
3155 dc_printf("Zoom factor pinned at 1.25.\n");
3157 Viewer_zoom = Dc_arg_float;
3163 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3166 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3170 DCF(framerate_cap, "Sets the framerate cap")
3173 dc_get_arg(ARG_INT);
3174 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3175 Framerate_cap = Dc_arg_int;
3177 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3183 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3184 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3185 dc_printf("[n] must be from 1 to 120.\n");
3189 if ( Framerate_cap )
3190 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3192 dc_printf("There is no framerate cap currently active.\n");
3196 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3197 int Show_viewing_from_self = 0;
3199 void say_view_target()
3201 object *view_target;
3203 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3204 view_target = &Objects[Player_ai->target_objnum];
3206 view_target = Player_obj;
3208 if (Game_mode & GM_DEAD) {
3209 if (Player_ai->target_objnum != -1)
3210 view_target = &Objects[Player_ai->target_objnum];
3213 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3214 if (view_target != Player_obj){
3216 char *view_target_name = NULL;
3217 switch(Objects[Player_ai->target_objnum].type) {
3219 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3222 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3223 Viewer_mode &= ~VM_OTHER_SHIP;
3225 case OBJ_JUMP_NODE: {
3226 char jump_node_name[128];
3227 strcpy(jump_node_name, XSTR( "jump node", 184));
3228 view_target_name = jump_node_name;
3229 Viewer_mode &= ~VM_OTHER_SHIP;
3238 if ( view_target_name ) {
3239 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3240 Show_viewing_from_self = 1;
3243 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3244 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3245 Show_viewing_from_self = 1;
3247 if (Show_viewing_from_self)
3248 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3253 Last_view_target = view_target;
3257 float Game_hit_x = 0.0f;
3258 float Game_hit_y = 0.0f;
3260 // Reset at the beginning of each frame
3261 void game_whack_reset()
3267 // Apply a 2d whack to the player
3268 void game_whack_apply( float x, float y )
3270 // Do some force feedback
3271 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3277 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3280 // call to apply a "shudder"
3281 void game_shudder_apply(int time, float intensity)
3283 Game_shudder_time = timestamp(time);
3284 Game_shudder_total = time;
3285 Game_shudder_intensity = intensity;
3288 #define FF_SCALE 10000
3289 void apply_hud_shake(matrix *eye_orient)
3291 if (Viewer_obj == Player_obj) {
3292 physics_info *pi = &Player_obj->phys_info;
3300 // Make eye shake due to afterburner
3301 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3304 dtime = timestamp_until(pi->afterburner_decay);
3308 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3309 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3312 // Make eye shake due to engine wash
3314 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3317 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3318 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3320 // get the intensity
3321 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3325 vm_vec_rand_vec_quick(&rand_vec);
3328 joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3332 // make hud shake due to shuddering
3333 if(Game_shudder_time != -1){
3334 // if the timestamp has elapsed
3335 if(timestamp_elapsed(Game_shudder_time)){
3336 Game_shudder_time = -1;
3338 // otherwise apply some shudder
3342 dtime = timestamp_until(Game_shudder_time);
3346 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));
3347 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));
3352 vm_angles_2_matrix(&tm, &tangles);
3353 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3354 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3355 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3356 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3361 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3363 // Player's velocity just before he blew up. Used to keep camera target moving.
3364 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3366 // Set eye_pos and eye_orient based on view mode.
3367 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3371 static int last_Viewer_mode = 0;
3372 static int last_Game_mode = 0;
3373 static int last_Viewer_objnum = -1;
3375 // This code is supposed to detect camera "cuts"... like going between
3378 // determine if we need to regenerate the nebula
3379 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3380 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3381 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3382 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3383 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3384 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3385 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3386 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3387 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3390 // regenerate the nebula
3394 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3395 //mprintf(( "************** Camera cut! ************\n" ));
3396 last_Viewer_mode = Viewer_mode;
3397 last_Game_mode = Game_mode;
3399 // Camera moved. Tell stars & debris to not do blurring.
3405 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3406 player_display_packlock_view();
3409 game_set_view_clip();
3411 if (Game_mode & GM_DEAD) {
3412 vector vec_to_deader, view_pos;
3415 Viewer_mode |= VM_DEAD_VIEW;
3417 if (Player_ai->target_objnum != -1) {
3418 int view_from_player = 1;
3420 if (Viewer_mode & VM_OTHER_SHIP) {
3421 // View from target.
3422 Viewer_obj = &Objects[Player_ai->target_objnum];
3424 last_Viewer_objnum = Player_ai->target_objnum;
3426 if ( Viewer_obj->type == OBJ_SHIP ) {
3427 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3428 view_from_player = 0;
3431 last_Viewer_objnum = -1;
3434 if ( view_from_player ) {
3435 // View target from player ship.
3437 *eye_pos = Player_obj->pos;
3438 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3439 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3442 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3444 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3445 dist += flFrametime * 16.0f;
3447 vm_vec_scale(&vec_to_deader, -dist);
3448 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3450 view_pos = Player_obj->pos;
3452 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3453 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3454 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3455 Dead_player_last_vel = Player_obj->phys_info.vel;
3456 //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));
3457 } else if (Player_ai->target_objnum != -1) {
3458 view_pos = Objects[Player_ai->target_objnum].pos;
3460 // Make camera follow explosion, but gradually slow down.
3461 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3462 view_pos = Player_obj->pos;
3463 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3464 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3467 *eye_pos = Dead_camera_pos;
3469 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3471 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3476 // if supernova shockwave
3477 if(supernova_camera_cut()){
3481 // call it dead view
3482 Viewer_mode |= VM_DEAD_VIEW;
3484 // set eye pos and orient
3485 supernova_set_view(eye_pos, eye_orient);
3487 // If already blown up, these other modes can override.
3488 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3489 Viewer_mode &= ~VM_DEAD_VIEW;
3491 Viewer_obj = Player_obj;
3493 if (Viewer_mode & VM_OTHER_SHIP) {
3494 if (Player_ai->target_objnum != -1){
3495 Viewer_obj = &Objects[Player_ai->target_objnum];
3496 last_Viewer_objnum = Player_ai->target_objnum;
3498 Viewer_mode &= ~VM_OTHER_SHIP;
3499 last_Viewer_objnum = -1;
3502 last_Viewer_objnum = -1;
3505 if (Viewer_mode & VM_EXTERNAL) {
3508 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3509 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3511 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3513 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3514 vm_vec_normalize(&eye_dir);
3515 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3518 // Modify the orientation based on head orientation.
3519 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3521 } else if ( Viewer_mode & VM_CHASE ) {
3524 if ( Viewer_obj->phys_info.speed < 0.1 )
3525 move_dir = Viewer_obj->orient.fvec;
3527 move_dir = Viewer_obj->phys_info.vel;
3528 vm_vec_normalize(&move_dir);
3531 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3532 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3533 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3534 vm_vec_normalize(&eye_dir);
3536 // JAS: I added the following code because if you slew up using
3537 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3538 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3539 // call because the up and the forward vector are the same. I fixed
3540 // it by adding in a fraction of the right vector all the time to the
3542 vector tmp_up = Viewer_obj->orient.uvec;
3543 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3545 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3548 // Modify the orientation based on head orientation.
3549 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3550 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3551 *eye_pos = Camera_pos;
3553 ship * shipp = &Ships[Player_obj->instance];
3555 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3556 vm_vec_normalize(&eye_dir);
3557 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3560 // get an eye position based upon the correct type of object
3561 switch(Viewer_obj->type){
3563 // make a call to get the eye point for the player object
3564 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3567 // make a call to get the eye point for the player object
3568 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3574 #ifdef JOHNS_DEBUG_CODE
3575 john_debug_stuff(&eye_pos, &eye_orient);
3581 apply_hud_shake(eye_orient);
3583 // setup neb2 rendering
3584 neb2_render_setup(eye_pos, eye_orient);
3588 extern void ai_debug_render_stuff();
3591 int Game_subspace_effect = 0;
3592 DCF_BOOL( subspace, Game_subspace_effect );
3594 // Does everything needed to render a frame
3595 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3599 g3_start_frame(game_zbuffer);
3600 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3602 // maybe offset the HUD (jitter stuff)
3603 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3604 HUD_set_offsets(Viewer_obj, !dont_offset);
3606 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3607 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3608 // must be done before ships are rendered
3609 if ( MULTIPLAYER_CLIENT ) {
3610 shield_point_multi_setup();
3613 if ( Game_subspace_effect ) {
3614 stars_draw(0,0,0,1);
3616 stars_draw(1,1,1,0);
3619 obj_render_all(obj_render);
3620 beam_render_all(); // render all beam weapons
3621 particle_render_all(); // render particles after everything else.
3622 trail_render_all(); // render missilie trails after everything else.
3623 mflash_render_all(); // render all muzzle flashes
3625 // Why do we not show the shield effect in these modes? Seems ok.
3626 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3630 // render nebula lightning
3633 // render local player nebula
3634 neb2_render_player();
3637 ai_debug_render_stuff();
3640 #ifndef RELEASE_REAL
3641 // game_framerate_check();
3645 extern void snd_spew_debug_info();
3646 snd_spew_debug_info();
3649 //================ END OF 3D RENDERING STUFF ====================
3653 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3654 hud_maybe_clear_head_area();
3655 anim_render_all(0, flFrametime);
3658 extern int Multi_display_netinfo;
3659 if(Multi_display_netinfo){
3660 extern void multi_display_netinfo();
3661 multi_display_netinfo();
3664 game_tst_frame_pre();
3667 do_timing_test(flFrametime);
3671 extern int OO_update_index;
3672 multi_rate_display(OO_update_index, 375, 0);
3677 extern void oo_display();
3684 //#define JOHNS_DEBUG_CODE 1
3686 #ifdef JOHNS_DEBUG_CODE
3687 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3689 //if ( keyd_pressed[KEY_LSHIFT] )
3691 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3693 model_subsystem *turret = tsys->system_info;
3695 if (turret->type == SUBSYSTEM_TURRET ) {
3697 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3699 ship_model_start(tobj);
3701 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3702 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3703 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3705 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3707 ship_model_stop(tobj);
3717 // following function for dumping frames for purposes of building trailers.
3720 // function to toggle state of dumping every frame into PCX when playing the game
3721 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3725 if ( Debug_dump_frames == 0 ) {
3727 Debug_dump_frames = 15;
3728 Debug_dump_trigger = 0;
3729 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3730 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3733 Debug_dump_frames = 0;
3734 Debug_dump_trigger = 0;
3735 gr_dump_frame_stop();
3736 dc_printf( "Frame dumping is now OFF\n" );
3742 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3746 if ( Debug_dump_frames == 0 ) {
3748 Debug_dump_frames = 15;
3749 Debug_dump_trigger = 1;
3750 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3751 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3754 Debug_dump_frames = 0;
3755 Debug_dump_trigger = 0;
3756 gr_dump_frame_stop();
3757 dc_printf( "Frame dumping is now OFF\n" );
3763 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3767 if ( Debug_dump_frames == 0 ) {
3769 Debug_dump_frames = 30;
3770 Debug_dump_trigger = 0;
3771 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3772 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3775 Debug_dump_frames = 0;
3776 Debug_dump_trigger = 0;
3777 gr_dump_frame_stop();
3778 dc_printf( "Frame dumping is now OFF\n" );
3784 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3788 if ( Debug_dump_frames == 0 ) {
3790 Debug_dump_frames = 30;
3791 Debug_dump_trigger = 1;
3792 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3793 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3796 Debug_dump_frames = 0;
3797 Debug_dump_trigger = 0;
3798 gr_dump_frame_stop();
3799 dc_printf( "Triggered frame dumping is now OFF\n" );
3805 void game_maybe_dump_frame()
3807 if ( !Debug_dump_frames ){
3811 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3818 Debug_dump_frame_num++;
3824 extern int Player_dead_state;
3826 // Flip the page and time how long it took.
3827 void game_flip_page_and_time_it()
3831 t1 = timer_get_fixed_seconds();
3833 t2 = timer_get_fixed_seconds();
3835 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3836 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3839 void game_simulation_frame()
3841 // blow ships up in multiplayer dogfight
3842 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){
3843 // blow up all non-player ships
3844 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3847 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3849 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)){
3850 moveup = GET_NEXT(moveup);
3853 shipp = &Ships[Objects[moveup->objnum].instance];
3854 sip = &Ship_info[shipp->ship_info_index];
3856 // only blow up small ships
3857 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3858 // function to simply explode a ship where it is currently at
3859 ship_self_destruct( &Objects[moveup->objnum] );
3862 moveup = GET_NEXT(moveup);
3868 // process AWACS stuff - do this first thing
3871 // single player, set Player hits_this_frame to 0
3872 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3873 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3874 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3878 supernova_process();
3879 if(supernova_active() >= 5){
3883 // fire targeting lasers now so that
3884 // 1 - created this frame
3885 // 2 - collide this frame
3886 // 3 - render this frame
3887 // 4 - ignored and deleted next frame
3888 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3890 ship_process_targeting_lasers();
3892 // do this here so that it works for multiplayer
3894 // get viewer direction
3895 int viewer_direction = PHYSICS_VIEWER_REAR;
3897 if(Viewer_mode == 0){
3898 viewer_direction = PHYSICS_VIEWER_FRONT;
3900 if(Viewer_mode & VM_PADLOCK_UP){
3901 viewer_direction = PHYSICS_VIEWER_UP;
3903 else if(Viewer_mode & VM_PADLOCK_REAR){
3904 viewer_direction = PHYSICS_VIEWER_REAR;
3906 else if(Viewer_mode & VM_PADLOCK_LEFT){
3907 viewer_direction = PHYSICS_VIEWER_LEFT;
3909 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3910 viewer_direction = PHYSICS_VIEWER_RIGHT;
3913 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3915 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3918 #define VM_PADLOCK_UP (1 << 7)
3919 #define VM_PADLOCK_REAR (1 << 8)
3920 #define VM_PADLOCK_LEFT (1 << 9)
3921 #define VM_PADLOCK_RIGHT (1 << 10)
3923 // evaluate mission departures and arrivals before we process all objects.
3924 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3926 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3927 // ships/wing packets.
3928 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3929 mission_parse_eval_stuff();
3932 // if we're an observer, move ourselves seperately from the standard physics
3933 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3934 obj_observer_move(flFrametime);
3937 // move all the objects now
3938 obj_move_all(flFrametime);
3940 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3941 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3942 // ship_check_cargo_all();
3943 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3944 mission_eval_goals();
3948 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3949 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3950 training_check_objectives();
3953 // do all interpolation now
3954 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3955 // client side processing of warping in effect stages
3956 multi_do_client_warp(flFrametime);
3958 // client side movement of an observer
3959 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3960 obj_observer_move(flFrametime);
3963 // move all objects - does interpolation now as well
3964 obj_move_all(flFrametime);
3967 // only process the message queue when the player is "in" the game
3968 if ( !Pre_player_entry ){
3969 message_queue_process(); // process any messages send to the player
3972 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3973 message_maybe_distort(); // maybe distort incoming message if comms damaged
3974 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3975 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3976 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3979 if(!(Game_mode & GM_STANDALONE_SERVER)){
3980 // process some stuff every frame (before frame is rendered)
3981 emp_process_local();
3983 hud_update_frame(); // update hud systems
3985 if (!physics_paused) {
3986 // Move particle system
3987 particle_move_all(flFrametime);
3989 // Move missile trails
3990 trail_move_all(flFrametime);
3992 // process muzzle flashes
3993 mflash_process_all();
3995 // Flash the gun flashes
3996 shipfx_flash_do_frame(flFrametime);
3998 shockwave_move_all(flFrametime); // update all the shockwaves
4001 // subspace missile strikes
4004 obj_snd_do_frame(); // update the object-linked persistant sounds
4005 game_maybe_update_sound_environment();
4006 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4008 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4010 if ( Game_subspace_effect ) {
4011 game_start_subspace_ambient_sound();
4017 // Maybe render and process the dead-popup
4018 void game_maybe_do_dead_popup(float frametime)
4020 if ( popupdead_is_active() ) {
4022 int choice = popupdead_do_frame(frametime);
4024 if ( Game_mode & GM_NORMAL ) {
4028 if(game_do_cd_mission_check(Game_current_mission_filename)){
4029 gameseq_post_event(GS_EVENT_ENTER_GAME);
4031 gameseq_post_event(GS_EVENT_MAIN_MENU);
4036 gameseq_post_event(GS_EVENT_END_GAME);
4041 if(game_do_cd_mission_check(Game_current_mission_filename)){
4042 gameseq_post_event(GS_EVENT_START_GAME);
4044 gameseq_post_event(GS_EVENT_MAIN_MENU);
4048 // this should only happen during a red alert mission
4051 Assert(The_mission.red_alert);
4052 if(!The_mission.red_alert){
4054 if(game_do_cd_mission_check(Game_current_mission_filename)){
4055 gameseq_post_event(GS_EVENT_START_GAME);
4057 gameseq_post_event(GS_EVENT_MAIN_MENU);
4062 // choose the previous mission
4063 mission_campaign_previous_mission();
4065 if(game_do_cd_mission_check(Game_current_mission_filename)){
4066 gameseq_post_event(GS_EVENT_START_GAME);
4068 gameseq_post_event(GS_EVENT_MAIN_MENU);
4079 case POPUPDEAD_DO_MAIN_HALL:
4080 multi_quit_game(PROMPT_NONE,-1);
4083 case POPUPDEAD_DO_RESPAWN:
4084 multi_respawn_normal();
4085 event_music_player_respawn();
4088 case POPUPDEAD_DO_OBSERVER:
4089 multi_respawn_observer();
4090 event_music_player_respawn_as_observer();
4099 if ( leave_popup ) {
4105 // returns true if player is actually in a game_play stats
4106 int game_actually_playing()
4110 state = gameseq_get_state();
4111 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4117 // Draw the 2D HUD gauges
4118 void game_render_hud_2d()
4120 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4124 HUD_render_2d(flFrametime);
4128 // Draw the 3D-dependant HUD gauges
4129 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4131 g3_start_frame(0); // 0 = turn zbuffering off
4132 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4134 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4135 HUD_render_3d(flFrametime);
4139 game_sunspot_process(flFrametime);
4141 // Diminish the palette effect
4142 game_flash_diminish(flFrametime);
4150 int actually_playing;
4151 fix total_time1, total_time2;
4152 fix render2_time1=0, render2_time2=0;
4153 fix render3_time1=0, render3_time2=0;
4154 fix flip_time1=0, flip_time2=0;
4155 fix clear_time1=0, clear_time2=0;
4161 if (Framerate_delay) {
4162 int start_time = timer_get_milliseconds();
4163 while (timer_get_milliseconds() < start_time + Framerate_delay)
4169 demo_do_frame_start();
4171 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4176 // start timing frame
4177 timing_frame_start();
4179 total_time1 = timer_get_fixed_seconds();
4181 // var to hold which state we are in
4182 actually_playing = game_actually_playing();
4184 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4185 if (!(Game_mode & GM_STANDALONE_SERVER)){
4186 Assert( OBJ_INDEX(Player_obj) >= 0 );
4190 if (Missiontime > Entry_delay_time){
4191 Pre_player_entry = 0;
4193 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4196 // Note: These are done even before the player enters, else buffers can overflow.
4197 if (! (Game_mode & GM_STANDALONE_SERVER)){
4201 shield_frame_init();
4203 if ( Player->control_mode != PCM_NORMAL )
4206 if ( !Pre_player_entry && actually_playing ) {
4207 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4209 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4210 game_process_keys();
4212 // don't read flying controls if we're playing a demo back
4213 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4214 read_player_controls( Player_obj, flFrametime);
4218 // if we're not the master, we may have to send the server-critical ship status button_info bits
4219 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4220 multi_maybe_send_ship_status();
4225 // Reset the whack stuff
4228 // These two lines must be outside of Pre_player_entry code,
4229 // otherwise too many lights are added.
4232 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4236 game_simulation_frame();
4238 // if not actually in a game play state, then return. This condition could only be true in
4239 // a multiplayer game.
4240 if ( !actually_playing ) {
4241 Assert( Game_mode & GM_MULTIPLAYER );
4245 if (!Pre_player_entry) {
4246 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4247 clear_time1 = timer_get_fixed_seconds();
4248 // clear the screen to black
4250 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4254 clear_time2 = timer_get_fixed_seconds();
4255 render3_time1 = timer_get_fixed_seconds();
4256 game_render_frame_setup(&eye_pos, &eye_orient);
4257 game_render_frame( &eye_pos, &eye_orient );
4259 // save the eye position and orientation
4260 if ( Game_mode & GM_MULTIPLAYER ) {
4261 Net_player->s_info.eye_pos = eye_pos;
4262 Net_player->s_info.eye_orient = eye_orient;
4265 hud_show_target_model();
4267 // check to see if we should display the death died popup
4268 if(Game_mode & GM_DEAD_BLEW_UP){
4269 if(Game_mode & GM_MULTIPLAYER){
4270 // catch the situation where we're supposed to be warping out on this transition
4271 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4272 gameseq_post_event(GS_EVENT_DEBRIEF);
4273 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4274 Player_died_popup_wait = -1;
4278 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4279 Player_died_popup_wait = -1;
4285 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4286 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4287 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4288 if(!popupdead_is_active()){
4292 Player_multi_died_check = -1;
4296 render3_time2 = timer_get_fixed_seconds();
4297 render2_time1 = timer_get_fixed_seconds();
4300 game_get_framerate();
4301 game_show_framerate();
4303 game_show_time_left();
4305 // Draw the 2D HUD gauges
4306 if(supernova_active() < 3){
4307 game_render_hud_2d();
4310 game_set_view_clip();
4312 // Draw 3D HUD gauges
4313 game_render_hud_3d(&eye_pos, &eye_orient);
4317 render2_time2 = timer_get_fixed_seconds();
4319 // maybe render and process the dead popup
4320 game_maybe_do_dead_popup(flFrametime);
4322 // start timing frame
4323 timing_frame_stop();
4324 // timing_display(30, 10);
4326 // If a regular popup is active, don't flip (popup code flips)
4327 if( !popup_running_state() ){
4328 flip_time1 = timer_get_fixed_seconds();
4329 game_flip_page_and_time_it();
4330 flip_time2 = timer_get_fixed_seconds();
4334 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4337 game_show_standalone_framerate();
4341 game_do_training_checks();
4344 // process lightning (nebula only)
4347 total_time2 = timer_get_fixed_seconds();
4349 // Got some timing numbers
4350 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4351 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4352 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4353 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4354 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4357 demo_do_frame_end();
4359 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4365 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4366 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4367 // died. This resulted in screwed up death sequences.
4369 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4370 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4371 static int timer_paused=0;
4372 #if defined(TIMER_TEST) && !defined(NDEBUG)
4373 static int stop_count,start_count;
4374 static int time_stopped,time_started;
4376 int saved_timestamp_ticker = -1;
4378 void game_reset_time()
4380 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4384 // Last_time = timer_get_fixed_seconds();
4390 void game_stop_time()
4392 if (timer_paused==0) {
4394 time = timer_get_fixed_seconds();
4395 // Save how much time progressed so far in the frame so we can
4396 // use it when we unpause.
4397 Last_delta_time = time - Last_time;
4399 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4400 if (Last_delta_time < 0) {
4401 #if defined(TIMER_TEST) && !defined(NDEBUG)
4402 Int3(); //get Matt!!!!
4404 Last_delta_time = 0;
4406 #if defined(TIMER_TEST) && !defined(NDEBUG)
4407 time_stopped = time;
4410 // Stop the timer_tick stuff...
4411 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4412 saved_timestamp_ticker = timestamp_ticker;
4416 #if defined(TIMER_TEST) && !defined(NDEBUG)
4421 void game_start_time()
4424 Assert(timer_paused >= 0);
4425 if (timer_paused==0) {
4427 time = timer_get_fixed_seconds();
4428 #if defined(TIMER_TEST) && !defined(NDEBUG)
4430 Int3(); //get Matt!!!!
4433 // Take current time, and set it backwards to account for time
4434 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4435 // will be correct when it goes to calculate the frametime next
4437 Last_time = time - Last_delta_time;
4438 #if defined(TIMER_TEST) && !defined(NDEBUG)
4439 time_started = time;
4442 // Restore the timer_tick stuff...
4443 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4444 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4445 timestamp_ticker = saved_timestamp_ticker;
4446 saved_timestamp_ticker = -1;
4449 #if defined(TIMER_TEST) && !defined(NDEBUG)
4455 void game_set_frametime(int state)
4458 float frame_cap_diff;
4460 thistime = timer_get_fixed_seconds();
4462 if ( Last_time == 0 )
4463 Frametime = F1_0 / 30;
4465 Frametime = thistime - Last_time;
4467 // Frametime = F1_0 / 30;
4469 fix debug_frametime = Frametime; // Just used to display frametime.
4471 // If player hasn't entered mission yet, make frame take 1/4 second.
4472 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4475 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4477 fix frame_speed = F1_0 / Debug_dump_frames;
4479 if (Frametime > frame_speed ){
4480 nprintf(("warning","slow frame: %x\n",Frametime));
4483 thistime = timer_get_fixed_seconds();
4484 Frametime = thistime - Last_time;
4485 } while (Frametime < frame_speed );
4487 Frametime = frame_speed;
4491 Assert( Framerate_cap > 0 );
4493 // Cap the framerate so it doesn't get too high.
4497 cap = F1_0/Framerate_cap;
4498 if (Frametime < cap) {
4499 thistime = cap - Frametime;
4500 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4501 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4503 thistime = timer_get_fixed_seconds();
4507 if((Game_mode & GM_STANDALONE_SERVER) &&
4508 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4510 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4511 Sleep((DWORD)(frame_cap_diff*1000));
4513 thistime += fl2f((frame_cap_diff));
4515 Frametime = thistime - Last_time;
4518 // If framerate is too low, cap it.
4519 if (Frametime > MAX_FRAMETIME) {
4521 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4523 // to remove warnings in release build
4524 debug_frametime = fl2f(flFrametime);
4526 Frametime = MAX_FRAMETIME;
4529 Frametime = fixmul(Frametime, Game_time_compression);
4531 Last_time = thistime;
4532 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4534 flFrametime = f2fl(Frametime);
4535 //if(!(Game_mode & GM_PLAYING_DEMO)){
4536 timestamp_inc(flFrametime);
4538 /* if ((Framecount > 0) && (Framecount < 10)) {
4539 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4544 // This is called from game_do_frame(), and from navmap_do_frame()
4545 void game_update_missiontime()
4547 // TODO JAS: Put in if and move this into game_set_frametime,
4548 // fix navmap to call game_stop/start_time
4549 //if ( !timer_paused )
4550 Missiontime += Frametime;
4553 void game_do_frame()
4555 game_set_frametime(GS_STATE_GAME_PLAY);
4556 game_update_missiontime();
4558 if (Game_mode & GM_STANDALONE_SERVER) {
4559 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4562 if ( game_single_step && (last_single_step == game_single_step) ) {
4563 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4564 while( key_checkch() == 0 )
4566 os_set_title( XSTR( "FreeSpace", 171) );
4567 Last_time = timer_get_fixed_seconds();
4570 last_single_step = game_single_step;
4572 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4573 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4577 Keep_mouse_centered = 0;
4578 monitor_update(); // Update monitor variables
4581 void multi_maybe_do_frame()
4583 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4588 int Joymouse_button_status = 0;
4590 // Flush all input devices
4598 Joymouse_button_status = 0;
4600 //mprintf(("Game flush!\n" ));
4603 // function for multiplayer only which calls game_do_state_common() when running the
4605 void game_do_dc_networking()
4607 Assert( Game_mode & GM_MULTIPLAYER );
4609 game_do_state_common( gameseq_get_state() );
4612 // Call this whenever in a loop, or when you need to check for a keystroke.
4613 int game_check_key()
4619 // convert keypad enter to normal enter
4620 if ((k & KEY_MASK) == KEY_PADENTER)
4621 k = (k & ~KEY_MASK) | KEY_ENTER;
4628 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4629 static int Demo_show_trailer_timestamp = 0;
4631 void demo_reset_trailer_timer()
4633 Demo_show_trailer_timestamp = timer_get_milliseconds();
4636 void demo_maybe_show_trailer(int k)
4639 // if key pressed, reset demo trailer timer
4641 demo_reset_trailer_timer();
4645 // if mouse moved, reset demo trailer timer
4648 mouse_get_delta(&dx, &dy);
4649 if ( (dx > 0) || (dy > 0) ) {
4650 demo_reset_trailer_timer();
4654 // if joystick has moved, reset demo trailer timer
4657 joy_get_delta(&dx, &dy);
4658 if ( (dx > 0) || (dy > 0) ) {
4659 demo_reset_trailer_timer();
4663 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4664 // the low-level code. Ugly, I know... but was the simplest and most
4667 // if 30 seconds since last demo trailer time reset, launch movie
4668 if ( os_foreground() ) {
4669 int now = timer_get_milliseconds();
4670 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4671 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4673 movie_play( NOX("fstrailer2.mve") );
4674 demo_reset_trailer_timer();
4682 // same as game_check_key(), except this is used while actually in the game. Since there
4683 // generally are differences between game control keys and general UI keys, makes sense to
4684 // have seperate functions for each case. If you are not checking a game control while in a
4685 // mission, you should probably be using game_check_key() instead.
4690 if (!os_foreground()) {
4695 // If we're in a single player game, pause it.
4696 if (!(Game_mode & GM_MULTIPLAYER)){
4697 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4698 game_process_pause_key();
4706 demo_maybe_show_trailer(k);
4709 // Move the mouse cursor with the joystick.
4710 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4711 // Move the mouse cursor with the joystick
4715 joy_get_pos( &jx, &jy, &jz, &jr );
4717 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4718 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4721 mouse_get_real_pos( &mx, &my );
4722 mouse_set_pos( mx+dx, my+dy );
4727 m = mouse_down(MOUSE_LEFT_BUTTON);
4729 if ( j != Joymouse_button_status ) {
4730 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4731 Joymouse_button_status = j;
4733 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4734 } else if ( (!j) && (m) ) {
4735 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4740 // if we should be ignoring keys because of some multiplayer situations
4741 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4745 // If a popup is running, don't process all the Fn keys
4746 if( popup_active() ) {
4750 state = gameseq_get_state();
4752 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4755 case KEY_DEBUGGED + KEY_BACKSP:
4760 launch_context_help();
4765 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4767 // don't allow f2 while warping out in multiplayer
4768 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4773 case GS_STATE_INITIAL_PLAYER_SELECT:
4774 case GS_STATE_OPTIONS_MENU:
4775 case GS_STATE_HUD_CONFIG:
4776 case GS_STATE_CONTROL_CONFIG:
4777 case GS_STATE_DEATH_DIED:
4778 case GS_STATE_DEATH_BLEW_UP:
4779 case GS_STATE_VIEW_MEDALS:
4783 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4790 // hotkey selection screen -- only valid from briefing and beyond.
4793 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) ) {
4794 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4800 case KEY_DEBUGGED + KEY_F3:
4801 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4804 case KEY_DEBUGGED + KEY_F4:
4805 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4809 if(Game_mode & GM_MULTIPLAYER){
4810 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4811 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4815 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4816 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4822 case KEY_ESC | KEY_SHIFTED:
4823 // make sure to quit properly out of multiplayer
4824 if(Game_mode & GM_MULTIPLAYER){
4825 multi_quit_game(PROMPT_NONE);
4828 gameseq_post_event( GS_EVENT_QUIT_GAME );
4833 case KEY_DEBUGGED + KEY_P:
4836 case KEY_PRINT_SCRN:
4838 static int counter = 0;
4843 sprintf( tmp_name, NOX("screen%02d"), counter );
4845 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4846 gr_print_screen(tmp_name);
4854 case KEY_SHIFTED | KEY_ENTER: {
4856 #if !defined(NDEBUG)
4858 if ( Game_mode & GM_NORMAL ){
4862 // if we're in multiplayer mode, do some special networking
4863 if(Game_mode & GM_MULTIPLAYER){
4864 debug_console(game_do_dc_networking);
4871 if ( Game_mode & GM_NORMAL )
4885 gameseq_post_event(GS_EVENT_QUIT_GAME);
4888 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4891 void camera_set_position( vector *pos )
4896 void camera_set_orient( matrix *orient )
4898 Camera_orient = *orient;
4901 void camera_set_velocity( vector *vel, int instantaneous )
4903 Camera_desired_velocity.x = 0.0f;
4904 Camera_desired_velocity.y = 0.0f;
4905 Camera_desired_velocity.z = 0.0f;
4907 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4908 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4909 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4911 if ( instantaneous ) {
4912 Camera_velocity = Camera_desired_velocity;
4920 vector new_vel, delta_pos;
4922 apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4923 apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4924 apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4926 Camera_velocity = new_vel;
4928 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4930 vm_vec_add2( &Camera_pos, &delta_pos );
4932 float ot = Camera_time+0.0f;
4934 Camera_time += flFrametime;
4936 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4939 tmp.z = 4.739f; // always go this fast forward.
4941 // pick x and y velocities so they are always on a
4942 // circle with a 25 m radius.
4944 float tmp_angle = frand()*PI2;
4946 tmp.x = 22.0f * (float)sin(tmp_angle);
4947 tmp.y = -22.0f * (float)cos(tmp_angle);
4949 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4951 //mprintf(( "Changing velocity!\n" ));
4952 camera_set_velocity( &tmp, 0 );
4955 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4956 vector tmp = { 0.0f, 0.0f, 0.0f };
4957 camera_set_velocity( &tmp, 0 );
4962 void end_demo_campaign_do()
4964 #if defined(FS2_DEMO)
4965 // show upsell screens
4966 demo_upsell_show_screens();
4967 #elif defined(OEM_BUILD)
4968 // show oem upsell screens
4969 oem_upsell_show_screens();
4972 // drop into main hall
4973 gameseq_post_event( GS_EVENT_MAIN_MENU );
4976 // All code to process events. This is the only place
4977 // that you should change the state of the game.
4978 void game_process_event( int current_state, int event )
4980 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4983 case GS_EVENT_SIMULATOR_ROOM:
4984 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4987 case GS_EVENT_MAIN_MENU:
4988 gameseq_set_state(GS_STATE_MAIN_MENU);
4991 case GS_EVENT_OPTIONS_MENU:
4992 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4995 case GS_EVENT_BARRACKS_MENU:
4996 gameseq_set_state(GS_STATE_BARRACKS_MENU);
4999 case GS_EVENT_TECH_MENU:
5000 gameseq_set_state(GS_STATE_TECH_MENU);
5003 case GS_EVENT_TRAINING_MENU:
5004 gameseq_set_state(GS_STATE_TRAINING_MENU);
5007 case GS_EVENT_START_GAME:
5008 Select_default_ship = 0;
5009 Player_multi_died_check = -1;
5010 gameseq_set_state(GS_STATE_CMD_BRIEF);
5013 case GS_EVENT_START_BRIEFING:
5014 gameseq_set_state(GS_STATE_BRIEFING);
5017 case GS_EVENT_DEBRIEF:
5018 // did we end the campaign in the main freespace 2 single player campaign?
5019 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5020 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5022 gameseq_set_state(GS_STATE_DEBRIEF);
5025 Player_multi_died_check = -1;
5028 case GS_EVENT_SHIP_SELECTION:
5029 gameseq_set_state( GS_STATE_SHIP_SELECT );
5032 case GS_EVENT_WEAPON_SELECTION:
5033 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5036 case GS_EVENT_ENTER_GAME:
5038 // maybe start recording a demo
5040 demo_start_record("test.fsd");
5044 if (Game_mode & GM_MULTIPLAYER) {
5045 // if we're respawning, make sure we change the view mode so that the hud shows up
5046 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5050 gameseq_set_state(GS_STATE_GAME_PLAY);
5052 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5055 Player_multi_died_check = -1;
5057 // clear multiplayer button info
5058 extern button_info Multi_ship_status_bi;
5059 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5061 Start_time = f2fl(timer_get_approx_seconds());
5063 mprintf(("Entering game at time = %7.3f\n", Start_time));
5067 case GS_EVENT_START_GAME_QUICK:
5068 Select_default_ship = 1;
5069 gameseq_post_event(GS_EVENT_ENTER_GAME);
5073 case GS_EVENT_END_GAME:
5074 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5075 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5076 gameseq_set_state(GS_STATE_MAIN_MENU);
5081 Player_multi_died_check = -1;
5084 case GS_EVENT_QUIT_GAME:
5085 main_hall_stop_music();
5086 main_hall_stop_ambient();
5087 gameseq_set_state(GS_STATE_QUIT_GAME);
5089 Player_multi_died_check = -1;
5092 case GS_EVENT_GAMEPLAY_HELP:
5093 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5096 case GS_EVENT_PAUSE_GAME:
5097 gameseq_push_state(GS_STATE_GAME_PAUSED);
5100 case GS_EVENT_DEBUG_PAUSE_GAME:
5101 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5104 case GS_EVENT_TRAINING_PAUSE:
5105 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5108 case GS_EVENT_PREVIOUS_STATE:
5109 gameseq_pop_state();
5112 case GS_EVENT_TOGGLE_FULLSCREEN:
5113 #ifndef HARDWARE_ONLY
5115 if ( gr_screen.mode == GR_SOFTWARE ) {
5116 gr_init( GR_640, GR_DIRECTDRAW );
5117 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5118 gr_init( GR_640, GR_SOFTWARE );
5124 case GS_EVENT_TOGGLE_GLIDE:
5126 if ( gr_screen.mode != GR_GLIDE ) {
5127 gr_init( GR_640, GR_GLIDE );
5129 gr_init( GR_640, GR_SOFTWARE );
5134 case GS_EVENT_LOAD_MISSION_MENU:
5135 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5138 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5139 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5142 case GS_EVENT_HUD_CONFIG:
5143 gameseq_push_state( GS_STATE_HUD_CONFIG );
5146 case GS_EVENT_CONTROL_CONFIG:
5147 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5150 case GS_EVENT_DEATH_DIED:
5151 gameseq_set_state( GS_STATE_DEATH_DIED );
5154 case GS_EVENT_DEATH_BLEW_UP:
5155 if ( current_state == GS_STATE_DEATH_DIED ) {
5156 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5157 event_music_player_death();
5159 // multiplayer clients set their extra check here
5160 if(Game_mode & GM_MULTIPLAYER){
5161 // set the multi died absolute last chance check
5162 Player_multi_died_check = time(NULL);
5165 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5169 case GS_EVENT_NEW_CAMPAIGN:
5170 if (!mission_load_up_campaign()){
5171 readyroom_continue_campaign();
5174 Player_multi_died_check = -1;
5177 case GS_EVENT_CAMPAIGN_CHEAT:
5178 if (!mission_load_up_campaign()){
5180 // bash campaign value
5181 extern char Main_hall_campaign_cheat[512];
5184 // look for the mission
5185 for(idx=0; idx<Campaign.num_missions; idx++){
5186 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5187 Campaign.next_mission = idx;
5188 Campaign.prev_mission = idx - 1;
5195 readyroom_continue_campaign();
5198 Player_multi_died_check = -1;
5201 case GS_EVENT_CAMPAIGN_ROOM:
5202 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5205 case GS_EVENT_CMD_BRIEF:
5206 gameseq_set_state(GS_STATE_CMD_BRIEF);
5209 case GS_EVENT_RED_ALERT:
5210 gameseq_set_state(GS_STATE_RED_ALERT);
5213 case GS_EVENT_CREDITS:
5214 gameseq_set_state( GS_STATE_CREDITS );
5217 case GS_EVENT_VIEW_MEDALS:
5218 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5221 case GS_EVENT_SHOW_GOALS:
5222 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5225 case GS_EVENT_HOTKEY_SCREEN:
5226 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5229 // multiplayer stuff follow these comments
5231 case GS_EVENT_MULTI_JOIN_GAME:
5232 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5235 case GS_EVENT_MULTI_HOST_SETUP:
5236 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5239 case GS_EVENT_MULTI_CLIENT_SETUP:
5240 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5243 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5244 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5247 case GS_EVENT_MULTI_STD_WAIT:
5248 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5251 case GS_EVENT_STANDALONE_MAIN:
5252 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5255 case GS_EVENT_MULTI_PAUSE:
5256 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5259 case GS_EVENT_INGAME_PRE_JOIN:
5260 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5263 case GS_EVENT_EVENT_DEBUG:
5264 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5267 // Start a warpout where player automatically goes 70 no matter what
5268 // and can't cancel out of it.
5269 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5270 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5272 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5273 Player->saved_viewer_mode = Viewer_mode;
5274 Player->control_mode = PCM_WARPOUT_STAGE1;
5275 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5276 Warpout_time = 0.0f; // Start timer!
5279 case GS_EVENT_PLAYER_WARPOUT_START:
5280 if ( Player->control_mode != PCM_NORMAL ) {
5281 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5283 Player->saved_viewer_mode = Viewer_mode;
5284 Player->control_mode = PCM_WARPOUT_STAGE1;
5285 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5286 Warpout_time = 0.0f; // Start timer!
5287 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5291 case GS_EVENT_PLAYER_WARPOUT_STOP:
5292 if ( Player->control_mode != PCM_NORMAL ) {
5293 if ( !Warpout_forced ) { // cannot cancel forced warpout
5294 Player->control_mode = PCM_NORMAL;
5295 Viewer_mode = Player->saved_viewer_mode;
5296 hud_subspace_notify_abort();
5297 mprintf(( "Player put back to normal mode.\n" ));
5298 if ( Warpout_sound > -1 ) {
5299 snd_stop( Warpout_sound );
5306 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5307 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5308 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5309 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5311 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5312 shipfx_warpout_start( Player_obj );
5313 Player->control_mode = PCM_WARPOUT_STAGE2;
5314 Player->saved_viewer_mode = Viewer_mode;
5315 Viewer_mode |= VM_WARP_CHASE;
5317 vector tmp = Player_obj->pos;
5319 ship_get_eye( &tmp, &tmp_m, Player_obj );
5320 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5321 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5322 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5324 camera_set_position( &tmp );
5325 camera_set_orient( &Player_obj->orient );
5326 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5328 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5329 camera_set_velocity( &tmp_vel, 1);
5333 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5334 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5335 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5336 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5338 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5339 Player->control_mode = PCM_WARPOUT_STAGE3;
5343 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5344 mprintf(( "Player warped out. Going to debriefing!\n" ));
5345 Player->control_mode = PCM_NORMAL;
5346 Viewer_mode = Player->saved_viewer_mode;
5349 // we have a special debriefing screen for multiplayer furballs
5350 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5351 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5353 // do the normal debriefing for all other situations
5355 gameseq_post_event(GS_EVENT_DEBRIEF);
5359 case GS_EVENT_STANDALONE_POSTGAME:
5360 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5363 case GS_EVENT_INITIAL_PLAYER_SELECT:
5364 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5367 case GS_EVENT_GAME_INIT:
5368 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5369 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5371 // see if the command line option has been set to use the last pilot, and act acoordingly
5372 if( player_select_get_last_pilot() ) {
5373 // always enter the main menu -- do the automatic network startup stuff elsewhere
5374 // so that we still have valid checks for networking modes, etc.
5375 gameseq_set_state(GS_STATE_MAIN_MENU);
5377 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5382 case GS_EVENT_MULTI_MISSION_SYNC:
5383 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5386 case GS_EVENT_MULTI_START_GAME:
5387 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5390 case GS_EVENT_MULTI_HOST_OPTIONS:
5391 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5394 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5395 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5398 case GS_EVENT_TEAM_SELECT:
5399 gameseq_set_state(GS_STATE_TEAM_SELECT);
5402 case GS_EVENT_END_CAMPAIGN:
5403 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5406 case GS_EVENT_END_DEMO:
5407 gameseq_set_state(GS_STATE_END_DEMO);
5410 case GS_EVENT_LOOP_BRIEF:
5411 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5420 // Called when a state is being left.
5421 // The current state is still at old_state, but as soon as
5422 // this function leaves, then the current state will become
5423 // new state. You should never try to change the state
5424 // in here... if you think you need to, you probably really
5425 // need to post an event, not change the state.
5426 void game_leave_state( int old_state, int new_state )
5428 int end_mission = 1;
5430 switch (new_state) {
5431 case GS_STATE_GAME_PAUSED:
5432 case GS_STATE_DEBUG_PAUSED:
5433 case GS_STATE_OPTIONS_MENU:
5434 case GS_STATE_CONTROL_CONFIG:
5435 case GS_STATE_MISSION_LOG_SCROLLBACK:
5436 case GS_STATE_DEATH_DIED:
5437 case GS_STATE_SHOW_GOALS:
5438 case GS_STATE_HOTKEY_SCREEN:
5439 case GS_STATE_MULTI_PAUSED:
5440 case GS_STATE_TRAINING_PAUSED:
5441 case GS_STATE_EVENT_DEBUG:
5442 case GS_STATE_GAMEPLAY_HELP:
5443 end_mission = 0; // these events shouldn't end a mission
5447 switch (old_state) {
5448 case GS_STATE_BRIEFING:
5449 brief_stop_voices();
5450 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5451 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5452 && (new_state != GS_STATE_TEAM_SELECT) ){
5453 common_select_close();
5454 if ( new_state == GS_STATE_MAIN_MENU ) {
5455 freespace_stop_mission();
5459 // COMMAND LINE OPTION
5460 if (Cmdline_multi_stream_chat_to_file){
5461 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5462 cfclose(Multi_chat_stream);
5466 case GS_STATE_DEBRIEF:
5467 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5472 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5473 multi_df_debrief_close();
5476 case GS_STATE_LOAD_MISSION_MENU:
5477 mission_load_menu_close();
5480 case GS_STATE_SIMULATOR_ROOM:
5484 case GS_STATE_CAMPAIGN_ROOM:
5485 campaign_room_close();
5488 case GS_STATE_CMD_BRIEF:
5489 if (new_state == GS_STATE_OPTIONS_MENU) {
5494 if (new_state == GS_STATE_MAIN_MENU)
5495 freespace_stop_mission();
5500 case GS_STATE_RED_ALERT:
5504 case GS_STATE_SHIP_SELECT:
5505 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5506 new_state != GS_STATE_HOTKEY_SCREEN &&
5507 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5508 common_select_close();
5509 if ( new_state == GS_STATE_MAIN_MENU ) {
5510 freespace_stop_mission();
5515 case GS_STATE_WEAPON_SELECT:
5516 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5517 new_state != GS_STATE_HOTKEY_SCREEN &&
5518 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5519 common_select_close();
5520 if ( new_state == GS_STATE_MAIN_MENU ) {
5521 freespace_stop_mission();
5526 case GS_STATE_TEAM_SELECT:
5527 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5528 new_state != GS_STATE_HOTKEY_SCREEN &&
5529 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5530 common_select_close();
5531 if ( new_state == GS_STATE_MAIN_MENU ) {
5532 freespace_stop_mission();
5537 case GS_STATE_MAIN_MENU:
5538 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5545 case GS_STATE_OPTIONS_MENU:
5546 //game_start_time();
5547 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5548 multi_join_clear_game_list();
5550 options_menu_close();
5553 case GS_STATE_BARRACKS_MENU:
5554 if(new_state != GS_STATE_VIEW_MEDALS){
5559 case GS_STATE_MISSION_LOG_SCROLLBACK:
5560 hud_scrollback_close();
5563 case GS_STATE_TRAINING_MENU:
5564 training_menu_close();
5567 case GS_STATE_GAME_PLAY:
5568 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5569 player_save_target_and_weapon_link_prefs();
5570 game_stop_looped_sounds();
5573 sound_env_disable();
5574 joy_ff_stop_effects();
5576 // stop game time under certain conditions
5577 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5582 // shut down any recording or playing demos
5587 // when in multiplayer and going back to the main menu, send a leave game packet
5588 // right away (before calling stop mission). stop_mission was taking to long to
5589 // close mission down and I want people to get notified ASAP.
5590 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5591 multi_quit_game(PROMPT_NONE);
5594 freespace_stop_mission();
5595 Game_time_compression = F1_0;
5599 case GS_STATE_TECH_MENU:
5603 case GS_STATE_TRAINING_PAUSED:
5604 Training_num_lines = 0;
5605 // fall through to GS_STATE_GAME_PAUSED
5607 case GS_STATE_GAME_PAUSED:
5609 if ( end_mission ) {
5614 case GS_STATE_DEBUG_PAUSED:
5617 pause_debug_close();
5621 case GS_STATE_HUD_CONFIG:
5625 // join/start a game
5626 case GS_STATE_MULTI_JOIN_GAME:
5627 if(new_state != GS_STATE_OPTIONS_MENU){
5628 multi_join_game_close();
5632 case GS_STATE_MULTI_HOST_SETUP:
5633 case GS_STATE_MULTI_CLIENT_SETUP:
5634 // if this is just the host going into the options screen, don't do anything
5635 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5639 // close down the proper state
5640 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5641 multi_create_game_close();
5643 multi_game_client_setup_close();
5646 // COMMAND LINE OPTION
5647 if (Cmdline_multi_stream_chat_to_file){
5648 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5649 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5650 cfclose(Multi_chat_stream);
5655 case GS_STATE_CONTROL_CONFIG:
5656 control_config_close();
5659 case GS_STATE_DEATH_DIED:
5660 Game_mode &= ~GM_DEAD_DIED;
5662 // early end while respawning or blowing up in a multiplayer game
5663 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5665 freespace_stop_mission();
5669 case GS_STATE_DEATH_BLEW_UP:
5670 Game_mode &= ~GM_DEAD_BLEW_UP;
5672 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5673 // to determine if I should do anything.
5674 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5676 freespace_stop_mission();
5679 // if we are not respawing as an observer or as a player, our new state will not
5680 // be gameplay state.
5681 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5682 game_stop_time(); // hasn't been called yet!!
5683 freespace_stop_mission();
5689 case GS_STATE_CREDITS:
5693 case GS_STATE_VIEW_MEDALS:
5697 case GS_STATE_SHOW_GOALS:
5698 mission_show_goals_close();
5701 case GS_STATE_HOTKEY_SCREEN:
5702 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5703 mission_hotkey_close();
5707 case GS_STATE_MULTI_MISSION_SYNC:
5708 // if we're moving into the options menu, don't do anything
5709 if(new_state == GS_STATE_OPTIONS_MENU){
5713 Assert( Game_mode & GM_MULTIPLAYER );
5715 if ( new_state == GS_STATE_GAME_PLAY ){
5716 // palette_restore_palette();
5718 // change a couple of flags to indicate our state!!!
5719 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5720 send_netplayer_update_packet();
5722 // set the game mode
5723 Game_mode |= GM_IN_MISSION;
5727 case GS_STATE_VIEW_CUTSCENES:
5728 cutscenes_screen_close();
5731 case GS_STATE_MULTI_STD_WAIT:
5732 multi_standalone_wait_close();
5735 case GS_STATE_STANDALONE_MAIN:
5736 standalone_main_close();
5737 if(new_state == GS_STATE_MULTI_STD_WAIT){
5738 init_multiplayer_stats();
5742 case GS_STATE_MULTI_PAUSED:
5743 // if ( end_mission ){
5748 case GS_STATE_INGAME_PRE_JOIN:
5749 multi_ingame_select_close();
5752 case GS_STATE_STANDALONE_POSTGAME:
5753 multi_standalone_postgame_close();
5756 case GS_STATE_INITIAL_PLAYER_SELECT:
5757 player_select_close();
5760 case GS_STATE_MULTI_START_GAME:
5761 multi_start_game_close();
5764 case GS_STATE_MULTI_HOST_OPTIONS:
5765 multi_host_options_close();
5768 case GS_STATE_END_OF_CAMPAIGN:
5769 mission_campaign_end_close();
5772 case GS_STATE_LOOP_BRIEF:
5778 // Called when a state is being entered.
5779 // The current state is set to the state we're entering at
5780 // this point, and old_state is set to the state we're coming
5781 // from. You should never try to change the state
5782 // in here... if you think you need to, you probably really
5783 // need to post an event, not change the state.
5785 void game_enter_state( int old_state, int new_state )
5787 switch (new_state) {
5788 case GS_STATE_MAIN_MENU:
5789 // in multiplayer mode, be sure that we are not doing networking anymore.
5790 if ( Game_mode & GM_MULTIPLAYER ) {
5791 Assert( Net_player != NULL );
5792 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5795 Game_time_compression = F1_0;
5797 // determine which ship this guy is currently based on
5798 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5801 if (Player->on_bastion) {
5809 case GS_STATE_BRIEFING:
5810 main_hall_stop_music();
5811 main_hall_stop_ambient();
5813 if (Game_mode & GM_NORMAL) {
5814 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5815 // MWA: or from options or hotkey screens
5816 // JH: or if the command brief state already did this
5817 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5818 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5819 && (old_state != GS_STATE_CMD_BRIEF) ) {
5820 if ( !game_start_mission() ) // this should put us into a new state on failure!
5824 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5825 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5826 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5828 Game_time_compression = F1_0;
5830 if ( red_alert_mission() ) {
5831 gameseq_post_event(GS_EVENT_RED_ALERT);
5838 case GS_STATE_DEBRIEF:
5839 game_stop_looped_sounds();
5840 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5841 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5846 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5847 multi_df_debrief_init();
5850 case GS_STATE_LOAD_MISSION_MENU:
5851 mission_load_menu_init();
5854 case GS_STATE_SIMULATOR_ROOM:
5858 case GS_STATE_CAMPAIGN_ROOM:
5859 campaign_room_init();
5862 case GS_STATE_RED_ALERT:
5863 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5867 case GS_STATE_CMD_BRIEF: {
5868 int team_num = 0; // team number used as index for which cmd brief to use.
5870 if (old_state == GS_STATE_OPTIONS_MENU) {
5874 main_hall_stop_music();
5875 main_hall_stop_ambient();
5877 if (Game_mode & GM_NORMAL) {
5878 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5879 // MWA: or from options or hotkey screens
5880 // JH: or if the command brief state already did this
5881 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5882 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5883 if ( !game_start_mission() ) // this should put us into a new state on failure!
5888 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5889 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5890 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5892 cmd_brief_init(team_num);
5898 case GS_STATE_SHIP_SELECT:
5902 case GS_STATE_WEAPON_SELECT:
5903 weapon_select_init();
5906 case GS_STATE_TEAM_SELECT:
5910 case GS_STATE_GAME_PAUSED:
5915 case GS_STATE_DEBUG_PAUSED:
5916 // game_stop_time();
5917 // os_set_title("FreeSpace - PAUSED");
5920 case GS_STATE_TRAINING_PAUSED:
5927 case GS_STATE_OPTIONS_MENU:
5929 options_menu_init();
5932 case GS_STATE_GAME_PLAY:
5933 // coming from the gameplay state or the main menu, we might need to load the mission
5934 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5935 if ( !game_start_mission() ) // this should put us into a new state.
5940 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5941 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5942 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5943 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5944 (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) ) {
5945 // JAS: Used to do all paging here.
5949 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5953 main_hall_stop_music();
5954 main_hall_stop_ambient();
5955 event_music_first_pattern(); // start the first pattern
5958 // special code that restores player ship selection and weapons loadout when doing a quick start
5959 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5960 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5961 wss_direct_restore_loadout();
5965 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5966 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5967 event_music_first_pattern(); // start the first pattern
5970 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5971 event_music_first_pattern(); // start the first pattern
5973 player_restore_target_and_weapon_link_prefs();
5975 Game_mode |= GM_IN_MISSION;
5978 // required to truely make mouse deltas zeroed in debug mouse code
5979 void mouse_force_pos(int x, int y);
5980 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5985 // only start time if in single player, or coming from multi wait state
5988 (Game_mode & GM_NORMAL) &&
5989 (old_state != GS_STATE_VIEW_CUTSCENES)
5991 (Game_mode & GM_MULTIPLAYER) && (
5992 (old_state == GS_STATE_MULTI_PAUSED) ||
5993 (old_state == GS_STATE_MULTI_MISSION_SYNC)
5999 // when coming from the multi paused state, reset the timestamps
6000 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6001 multi_reset_timestamps();
6004 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6005 // initialize all object update details
6006 multi_oo_gameplay_init();
6009 // under certain circumstances, the server should reset the object update rate limiting stuff
6010 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6011 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6013 // reinitialize the rate limiting system for all clients
6014 multi_oo_rate_init_all();
6017 // multiplayer clients should always re-initialize their control info rate limiting system
6018 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6019 multi_oo_rate_init_all();
6023 if(Game_mode & GM_MULTIPLAYER){
6024 multi_ping_reset_players();
6027 Game_subspace_effect = 0;
6028 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6029 Game_subspace_effect = 1;
6030 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6031 game_start_subspace_ambient_sound();
6035 sound_env_set(&Game_sound_env);
6036 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6038 // clear multiplayer button info i
6039 extern button_info Multi_ship_status_bi;
6040 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6043 case GS_STATE_HUD_CONFIG:
6047 case GS_STATE_MULTI_JOIN_GAME:
6048 multi_join_clear_game_list();
6050 if (old_state != GS_STATE_OPTIONS_MENU) {
6051 multi_join_game_init();
6056 case GS_STATE_MULTI_HOST_SETUP:
6057 // don't reinitialize if we're coming back from the host options screen
6058 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6059 multi_create_game_init();
6064 case GS_STATE_MULTI_CLIENT_SETUP:
6065 if (old_state != GS_STATE_OPTIONS_MENU) {
6066 multi_game_client_setup_init();
6071 case GS_STATE_CONTROL_CONFIG:
6072 control_config_init();
6075 case GS_STATE_TECH_MENU:
6079 case GS_STATE_BARRACKS_MENU:
6080 if(old_state != GS_STATE_VIEW_MEDALS){
6085 case GS_STATE_MISSION_LOG_SCROLLBACK:
6086 hud_scrollback_init();
6089 case GS_STATE_DEATH_DIED:
6090 Player_died_time = timestamp(10);
6092 if(!(Game_mode & GM_MULTIPLAYER)){
6093 player_show_death_message();
6095 Game_mode |= GM_DEAD_DIED;
6098 case GS_STATE_DEATH_BLEW_UP:
6099 if ( !popupdead_is_active() ) {
6100 Player_ai->target_objnum = -1;
6103 // stop any local EMP effect
6106 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6107 Game_mode |= GM_DEAD_BLEW_UP;
6108 Show_viewing_from_self = 0;
6110 // timestamp how long we should wait before displaying the died popup
6111 if ( !popupdead_is_active() ) {
6112 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6116 case GS_STATE_GAMEPLAY_HELP:
6117 gameplay_help_init();
6120 case GS_STATE_CREDITS:
6121 main_hall_stop_music();
6122 main_hall_stop_ambient();
6126 case GS_STATE_VIEW_MEDALS:
6127 medal_main_init(Player);
6130 case GS_STATE_SHOW_GOALS:
6131 mission_show_goals_init();
6134 case GS_STATE_HOTKEY_SCREEN:
6135 mission_hotkey_init();
6138 case GS_STATE_MULTI_MISSION_SYNC:
6139 // if we're coming from the options screen, don't do any
6140 if(old_state == GS_STATE_OPTIONS_MENU){
6144 switch(Multi_sync_mode){
6145 case MULTI_SYNC_PRE_BRIEFING:
6146 // if moving from game forming to the team select state
6149 case MULTI_SYNC_POST_BRIEFING:
6150 // if moving from briefing into the mission itself
6153 // tell everyone that we're now loading data
6154 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6155 send_netplayer_update_packet();
6157 // JAS: Used to do all paging here!!!!
6159 Net_player->state = NETPLAYER_STATE_WAITING;
6160 send_netplayer_update_packet();
6162 Game_time_compression = F1_0;
6164 case MULTI_SYNC_INGAME:
6170 case GS_STATE_VIEW_CUTSCENES:
6171 cutscenes_screen_init();
6174 case GS_STATE_MULTI_STD_WAIT:
6175 multi_standalone_wait_init();
6178 case GS_STATE_STANDALONE_MAIN:
6179 // don't initialize if we're coming from one of these 2 states unless there are no
6180 // players left (reset situation)
6181 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6182 standalone_main_init();
6186 case GS_STATE_MULTI_PAUSED:
6190 case GS_STATE_INGAME_PRE_JOIN:
6191 multi_ingame_select_init();
6194 case GS_STATE_STANDALONE_POSTGAME:
6195 multi_standalone_postgame_init();
6198 case GS_STATE_INITIAL_PLAYER_SELECT:
6199 player_select_init();
6202 case GS_STATE_MULTI_START_GAME:
6203 multi_start_game_init();
6206 case GS_STATE_MULTI_HOST_OPTIONS:
6207 multi_host_options_init();
6210 case GS_STATE_END_OF_CAMPAIGN:
6211 mission_campaign_end_init();
6214 case GS_STATE_LOOP_BRIEF:
6221 // do stuff that may need to be done regardless of state
6222 void game_do_state_common(int state,int no_networking)
6224 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6225 snd_do_frame(); // update sound system
6226 event_music_do_frame(); // music needs to play across many states
6228 multi_log_process();
6230 if (no_networking) {
6234 // maybe do a multiplayer frame based on game mode and state type
6235 if (Game_mode & GM_MULTIPLAYER) {
6237 case GS_STATE_OPTIONS_MENU:
6238 case GS_STATE_GAMEPLAY_HELP:
6239 case GS_STATE_HOTKEY_SCREEN:
6240 case GS_STATE_HUD_CONFIG:
6241 case GS_STATE_CONTROL_CONFIG:
6242 case GS_STATE_MISSION_LOG_SCROLLBACK:
6243 case GS_STATE_SHOW_GOALS:
6244 case GS_STATE_VIEW_CUTSCENES:
6245 case GS_STATE_EVENT_DEBUG:
6246 multi_maybe_do_frame();
6250 game_do_networking();
6254 // Called once a frame.
6255 // You should never try to change the state
6256 // in here... if you think you need to, you probably really
6257 // need to post an event, not change the state.
6258 int Game_do_state_should_skip = 0;
6259 void game_do_state(int state)
6261 // always lets the do_state_common() function determine if the state should be skipped
6262 Game_do_state_should_skip = 0;
6264 // legal to set the should skip state anywhere in this function
6265 game_do_state_common(state); // do stuff that may need to be done regardless of state
6267 if(Game_do_state_should_skip){
6272 case GS_STATE_MAIN_MENU:
6273 game_set_frametime(GS_STATE_MAIN_MENU);
6274 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6277 main_hall_do(flFrametime);
6281 case GS_STATE_OPTIONS_MENU:
6282 game_set_frametime(GS_STATE_OPTIONS_MENU);
6283 options_menu_do_frame(flFrametime);
6286 case GS_STATE_BARRACKS_MENU:
6287 game_set_frametime(GS_STATE_BARRACKS_MENU);
6288 barracks_do_frame(flFrametime);
6291 case GS_STATE_TRAINING_MENU:
6292 game_set_frametime(GS_STATE_TRAINING_MENU);
6293 training_menu_do_frame(flFrametime);
6296 case GS_STATE_TECH_MENU:
6297 game_set_frametime(GS_STATE_TECH_MENU);
6298 techroom_do_frame(flFrametime);
6301 case GS_STATE_GAMEPLAY_HELP:
6302 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6303 gameplay_help_do_frame(flFrametime);
6306 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6310 case GS_STATE_GAME_PAUSED:
6314 case GS_STATE_DEBUG_PAUSED:
6316 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6321 case GS_STATE_TRAINING_PAUSED:
6322 game_training_pause_do();
6325 case GS_STATE_LOAD_MISSION_MENU:
6326 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6327 mission_load_menu_do();
6330 case GS_STATE_BRIEFING:
6331 game_set_frametime(GS_STATE_BRIEFING);
6332 brief_do_frame(flFrametime);
6335 case GS_STATE_DEBRIEF:
6336 game_set_frametime(GS_STATE_DEBRIEF);
6337 debrief_do_frame(flFrametime);
6340 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6341 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6342 multi_df_debrief_do();
6345 case GS_STATE_SHIP_SELECT:
6346 game_set_frametime(GS_STATE_SHIP_SELECT);
6347 ship_select_do(flFrametime);
6350 case GS_STATE_WEAPON_SELECT:
6351 game_set_frametime(GS_STATE_WEAPON_SELECT);
6352 weapon_select_do(flFrametime);
6355 case GS_STATE_MISSION_LOG_SCROLLBACK:
6356 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6357 hud_scrollback_do_frame(flFrametime);
6360 case GS_STATE_HUD_CONFIG:
6361 game_set_frametime(GS_STATE_HUD_CONFIG);
6362 hud_config_do_frame(flFrametime);
6365 case GS_STATE_MULTI_JOIN_GAME:
6366 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6367 multi_join_game_do_frame();
6370 case GS_STATE_MULTI_HOST_SETUP:
6371 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6372 multi_create_game_do();
6375 case GS_STATE_MULTI_CLIENT_SETUP:
6376 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6377 multi_game_client_setup_do_frame();
6380 case GS_STATE_CONTROL_CONFIG:
6381 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6382 control_config_do_frame(flFrametime);
6385 case GS_STATE_DEATH_DIED:
6389 case GS_STATE_DEATH_BLEW_UP:
6393 case GS_STATE_SIMULATOR_ROOM:
6394 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6395 sim_room_do_frame(flFrametime);
6398 case GS_STATE_CAMPAIGN_ROOM:
6399 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6400 campaign_room_do_frame(flFrametime);
6403 case GS_STATE_RED_ALERT:
6404 game_set_frametime(GS_STATE_RED_ALERT);
6405 red_alert_do_frame(flFrametime);
6408 case GS_STATE_CMD_BRIEF:
6409 game_set_frametime(GS_STATE_CMD_BRIEF);
6410 cmd_brief_do_frame(flFrametime);
6413 case GS_STATE_CREDITS:
6414 game_set_frametime(GS_STATE_CREDITS);
6415 credits_do_frame(flFrametime);
6418 case GS_STATE_VIEW_MEDALS:
6419 game_set_frametime(GS_STATE_VIEW_MEDALS);
6423 case GS_STATE_SHOW_GOALS:
6424 game_set_frametime(GS_STATE_SHOW_GOALS);
6425 mission_show_goals_do_frame(flFrametime);
6428 case GS_STATE_HOTKEY_SCREEN:
6429 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6430 mission_hotkey_do_frame(flFrametime);
6433 case GS_STATE_VIEW_CUTSCENES:
6434 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6435 cutscenes_screen_do_frame();
6438 case GS_STATE_MULTI_STD_WAIT:
6439 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6440 multi_standalone_wait_do();
6443 case GS_STATE_STANDALONE_MAIN:
6444 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6445 standalone_main_do();
6448 case GS_STATE_MULTI_PAUSED:
6449 game_set_frametime(GS_STATE_MULTI_PAUSED);
6453 case GS_STATE_TEAM_SELECT:
6454 game_set_frametime(GS_STATE_TEAM_SELECT);
6458 case GS_STATE_INGAME_PRE_JOIN:
6459 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6460 multi_ingame_select_do();
6463 case GS_STATE_EVENT_DEBUG:
6465 game_set_frametime(GS_STATE_EVENT_DEBUG);
6466 game_show_event_debug(flFrametime);
6470 case GS_STATE_STANDALONE_POSTGAME:
6471 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6472 multi_standalone_postgame_do();
6475 case GS_STATE_INITIAL_PLAYER_SELECT:
6476 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6480 case GS_STATE_MULTI_MISSION_SYNC:
6481 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6485 case GS_STATE_MULTI_START_GAME:
6486 game_set_frametime(GS_STATE_MULTI_START_GAME);
6487 multi_start_game_do();
6490 case GS_STATE_MULTI_HOST_OPTIONS:
6491 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6492 multi_host_options_do();
6495 case GS_STATE_END_OF_CAMPAIGN:
6496 mission_campaign_end_do();
6499 case GS_STATE_END_DEMO:
6500 game_set_frametime(GS_STATE_END_DEMO);
6501 end_demo_campaign_do();
6504 case GS_STATE_LOOP_BRIEF:
6505 game_set_frametime(GS_STATE_LOOP_BRIEF);
6509 } // end switch(gs_current_state)
6513 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6514 int game_do_ram_check(int ram_in_bytes)
6516 if ( ram_in_bytes < 30*1024*1024 ) {
6517 int allowed_to_run = 1;
6518 if ( ram_in_bytes < 25*1024*1024 ) {
6523 int Freespace_total_ram_MB;
6524 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6526 if ( allowed_to_run ) {
6528 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);
6533 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6534 if ( msgbox_rval == IDCANCEL ) {
6541 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);
6543 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6554 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6555 // If so, copy it over and remove the update directory.
6556 void game_maybe_update_launcher(char *exe_dir)
6559 char src_filename[MAX_PATH];
6560 char dest_filename[MAX_PATH];
6562 strcpy(src_filename, exe_dir);
6563 strcat(src_filename, NOX("\\update\\freespace.exe"));
6565 strcpy(dest_filename, exe_dir);
6566 strcat(dest_filename, NOX("\\freespace.exe"));
6568 // see if src_filename exists
6570 fp = fopen(src_filename, "rb");
6576 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6578 // copy updated freespace.exe to freespace exe dir
6579 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6580 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 );
6584 // delete the file in the update directory
6585 DeleteFile(src_filename);
6587 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6588 char update_dir[MAX_PATH];
6589 strcpy(update_dir, exe_dir);
6590 strcat(update_dir, NOX("\\update"));
6591 RemoveDirectory(update_dir);
6597 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6601 int sub_total_destroyed = 0;
6605 // get the total for all his children
6606 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6607 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6610 // find the # of faces for this _individual_ object
6611 total = submodel_get_num_polys(model_num, sm);
6612 if(strstr(pm->submodel[sm].name, "-destroyed")){
6613 sub_total_destroyed = total;
6617 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6620 *out_total += total + sub_total;
6621 *out_destroyed_total += sub_total_destroyed;
6624 #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);
6625 void game_spew_pof_info()
6627 char *pof_list[1000];
6630 int idx, model_num, i, j;
6632 int total, root_total, model_total, destroyed_total, counted;
6636 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6638 // spew info on all the pofs
6644 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6649 for(idx=0; idx<num_files; idx++, counted++){
6650 sprintf(str, "%s.pof", pof_list[idx]);
6651 model_num = model_load(str, 0, NULL);
6653 pm = model_get(model_num);
6655 // if we have a real model
6660 // go through and print all raw submodels
6661 cfputs("RAW\n", out);
6664 for (i=0; i<pm->n_models; i++) {
6665 total = submodel_get_num_polys(model_num, i);
6667 model_total += total;
6668 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6671 sprintf(str, "Model total %d\n", model_total);
6674 // now go through and do it by LOD
6675 cfputs("BY LOD\n\n", out);
6676 for(i=0; i<pm->n_detail_levels; i++){
6677 sprintf(str, "LOD %d\n", i);
6681 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6683 destroyed_total = 0;
6684 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6685 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6688 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6691 sprintf(str, "TOTAL: %d\n", total + root_total);
6693 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6695 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6698 cfputs("------------------------------------------------------------------------\n\n", out);
6702 if(counted >= MAX_POLYGON_MODELS - 5){
6715 game_spew_pof_info();
6718 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6723 // Don't let more than one instance of Freespace run.
6724 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6726 SetForegroundWindow(hwnd);
6731 // Find out how much RAM is on this machine
6734 ms.dwLength = sizeof(MEMORYSTATUS);
6735 GlobalMemoryStatus(&ms);
6736 Freespace_total_ram = ms.dwTotalPhys;
6738 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6742 if ( ms.dwTotalVirtual < 1024 ) {
6743 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6747 if (!vm_init(24*1024*1024)) {
6748 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 );
6752 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6754 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);
6762 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6763 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6764 seem worth bothering with.
6768 lResult = RegOpenKeyEx(
6769 HKEY_LOCAL_MACHINE, // Where it is
6770 "Software\\Microsoft\\DirectX", // name of key
6771 NULL, // DWORD reserved
6772 KEY_QUERY_VALUE, // Allows all changes
6773 &hKey // Location to store key
6776 if (lResult == ERROR_SUCCESS) {
6778 DWORD dwType, dwLen;
6781 lResult = RegQueryValueEx(
6782 hKey, // Handle to key
6783 "Version", // The values name
6784 NULL, // DWORD reserved
6785 &dwType, // What kind it is
6786 (ubyte *) version, // value to set
6787 &dwLen // How many bytes to set
6790 if (lResult == ERROR_SUCCESS) {
6791 dx_version = atoi(strstr(version, ".") + 1);
6795 DWORD dwType, dwLen;
6798 lResult = RegQueryValueEx(
6799 hKey, // Handle to key
6800 "InstalledVersion", // The values name
6801 NULL, // DWORD reserved
6802 &dwType, // What kind it is
6803 (ubyte *) &val, // value to set
6804 &dwLen // How many bytes to set
6807 if (lResult == ERROR_SUCCESS) {
6815 if (dx_version < 3) {
6816 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6817 "latest version of DirectX at:\n\n"
6818 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6820 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6821 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6826 //=====================================================
6827 // Make sure we're running in the right directory.
6831 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6832 char *p = exe_dir + strlen(exe_dir);
6834 // chop off the filename
6835 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6841 if ( strlen(exe_dir) > 0 ) {
6842 SetCurrentDirectory(exe_dir);
6845 // check for updated freespace.exe
6846 game_maybe_update_launcher(exe_dir);
6854 extern void windebug_memwatch_init();
6855 windebug_memwatch_init();
6859 parse_cmdline(szCmdLine);
6861 #ifdef STANDALONE_ONLY_BUILD
6863 nprintf(("Network", "Standalone running"));
6866 nprintf(("Network", "Standalone running"));
6874 // maybe spew pof stuff
6875 if(Cmdline_spew_pof_info){
6876 game_spew_pof_info();
6881 // non-demo, non-standalone, play the intro movie
6886 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) ){
6888 #if defined(OEM_BUILD)
6889 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6891 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6892 #endif // defined(OEM_BUILD)
6897 if ( !Is_standalone ) {
6899 // release -- movies always play
6902 // 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
6904 // movie_play( NOX("intro.mve"), 0 );
6906 // debug version, movie will only play with -showmovies
6907 #elif !defined(NDEBUG)
6910 // movie_play( NOX("intro.mve"), 0);
6913 if ( Cmdline_show_movies )
6914 movie_play( NOX("intro.mve"), 0 );
6923 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6925 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6929 // only important for non THREADED mode
6932 state = gameseq_process_events();
6933 if ( state == GS_STATE_QUIT_GAME ){
6940 demo_upsell_show_screens();
6942 #elif defined(OEM_BUILD)
6943 // show upsell screens on exit
6944 oem_upsell_show_screens();
6951 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6957 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6959 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6961 // Do nothing here - RecordExceptionInfo() has already done
6962 // everything that is needed. Actually this code won't even
6963 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6964 // the __except clause.
6968 nprintf(("WinMain", "exceptions shall fall through"));
6970 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6976 // launcher the fslauncher program on exit
6977 void game_launch_launcher_on_exit()
6981 PROCESS_INFORMATION pi;
6982 char cmd_line[2048];
6983 char original_path[1024] = "";
6985 memset( &si, 0, sizeof(STARTUPINFO) );
6989 _getcwd(original_path, 1023);
6991 // set up command line
6992 strcpy(cmd_line, original_path);
6993 strcat(cmd_line, "\\");
6994 strcat(cmd_line, LAUNCHER_FNAME);
6995 strcat(cmd_line, " -straight_to_update");
6997 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
6998 cmd_line, // pointer to command line string
6999 NULL, // pointer to process security attributes
7000 NULL, // pointer to thread security attributes
7001 FALSE, // handle inheritance flag
7002 CREATE_DEFAULT_ERROR_MODE, // creation flags
7003 NULL, // pointer to new environment block
7004 NULL, // pointer to current directory name
7005 &si, // pointer to STARTUPINFO
7006 &pi // pointer to PROCESS_INFORMATION
7008 // to eliminate build warnings
7018 // This function is called when FreeSpace terminates normally.
7020 void game_shutdown(void)
7026 // don't ever flip a page on the standalone!
7027 if(!(Game_mode & GM_STANDALONE_SERVER)){
7033 // if the player has left the "player select" screen and quit the game without actually choosing
7034 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7035 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7039 // load up common multiplayer icons
7040 multi_unload_common_icons();
7042 shockwave_close(); // release any memory used by shockwave system
7043 fireball_close(); // free fireball system
7044 ship_close(); // free any memory that was allocated for the ships
7045 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7046 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7047 bm_unload_all(); // free bitmaps
7048 mission_campaign_close(); // close out the campaign stuff
7049 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7051 #ifdef MULTI_USE_LAG
7055 // the menu close functions will unload the bitmaps if they were displayed during the game
7056 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7059 training_menu_close();
7062 extern void joy_close();
7065 audiostream_close();
7067 event_music_close();
7071 // HACKITY HACK HACK
7072 // if this flag is set, we should be firing up the launcher when exiting freespace
7073 extern int Multi_update_fireup_launcher_on_exit;
7074 if(Multi_update_fireup_launcher_on_exit){
7075 game_launch_launcher_on_exit();
7079 // game_stop_looped_sounds()
7081 // This function will call the appropriate stop looped sound functions for those
7082 // modules which use looping sounds. It is not enough just to stop a looping sound
7083 // at the DirectSound level, the game is keeping track of looping sounds, and this
7084 // function is used to inform the game that looping sounds are being halted.
7086 void game_stop_looped_sounds()
7088 hud_stop_looped_locking_sounds();
7089 hud_stop_looped_engine_sounds();
7090 afterburner_stop_sounds();
7091 player_stop_looped_sounds();
7092 obj_snd_stop_all(); // stop all object-linked persistant sounds
7093 game_stop_subspace_ambient_sound();
7094 snd_stop(Radar_static_looping);
7095 Radar_static_looping = -1;
7096 snd_stop(Target_static_looping);
7097 shipfx_stop_engine_wash_sound();
7098 Target_static_looping = -1;
7101 //////////////////////////////////////////////////////////////////////////
7103 // Code for supporting an animating mouse pointer
7106 //////////////////////////////////////////////////////////////////////////
7108 typedef struct animating_obj
7117 static animating_obj Animating_mouse;
7119 // ----------------------------------------------------------------------------
7120 // init_animating_pointer()
7122 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7123 // gets properly initialized
7125 void init_animating_pointer()
7127 Animating_mouse.first_frame = -1;
7128 Animating_mouse.num_frames = 0;
7129 Animating_mouse.current_frame = -1;
7130 Animating_mouse.time = 0.0f;
7131 Animating_mouse.elapsed_time = 0.0f;
7134 // ----------------------------------------------------------------------------
7135 // load_animating_pointer()
7137 // Called at game init to load in the frames for the animating mouse pointer
7139 // input: filename => filename of animation file that holds the animation
7141 void load_animating_pointer(char *filename, int dx, int dy)
7146 init_animating_pointer();
7148 am = &Animating_mouse;
7149 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7150 if ( am->first_frame == -1 )
7151 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7152 am->current_frame = 0;
7153 am->time = am->num_frames / i2fl(fps);
7156 // ----------------------------------------------------------------------------
7157 // unload_animating_pointer()
7159 // Called at game shutdown to free the memory used to store the animation frames
7161 void unload_animating_pointer()
7166 am = &Animating_mouse;
7167 for ( i = 0; i < am->num_frames; i++ ) {
7168 Assert( (am->first_frame+i) >= 0 );
7169 bm_release(am->first_frame + i);
7172 am->first_frame = -1;
7174 am->current_frame = -1;
7177 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7178 void game_render_mouse(float frametime)
7183 // if animating cursor exists, play the next frame
7184 am = &Animating_mouse;
7185 if ( am->first_frame != -1 ) {
7186 mouse_get_pos(&mx, &my);
7187 am->elapsed_time += frametime;
7188 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7189 if ( am->current_frame >= am->num_frames ) {
7190 am->current_frame = 0;
7191 am->elapsed_time = 0.0f;
7193 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7197 // ----------------------------------------------------------------------------
7198 // game_maybe_draw_mouse()
7200 // determines whether to draw the mouse pointer at all, and what frame of
7201 // animation to use if the mouse is animating
7203 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7205 // input: frametime => elapsed frame time in seconds since last call
7207 void game_maybe_draw_mouse(float frametime)
7211 game_state = gameseq_get_state();
7213 switch ( game_state ) {
7214 case GS_STATE_GAME_PAUSED:
7215 // case GS_STATE_MULTI_PAUSED:
7216 case GS_STATE_GAME_PLAY:
7217 case GS_STATE_DEATH_DIED:
7218 case GS_STATE_DEATH_BLEW_UP:
7219 if ( popup_active() || popupdead_is_active() ) {
7231 if ( !Mouse_hidden )
7232 game_render_mouse(frametime);
7236 void game_do_training_checks()
7240 waypoint_list *wplp;
7242 if (Training_context & TRAINING_CONTEXT_SPEED) {
7243 s = (int) Player_obj->phys_info.fspeed;
7244 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7245 if (!Training_context_speed_set) {
7246 Training_context_speed_set = 1;
7247 Training_context_speed_timestamp = timestamp();
7251 Training_context_speed_set = 0;
7254 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7255 wplp = &Waypoint_lists[Training_context_path];
7256 if (wplp->count > Training_context_goal_waypoint) {
7257 i = Training_context_goal_waypoint;
7259 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7260 if (d <= Training_context_distance) {
7261 Training_context_at_waypoint = i;
7262 if (Training_context_goal_waypoint == i) {
7263 Training_context_goal_waypoint++;
7264 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7271 if (i == wplp->count)
7274 } while (i != Training_context_goal_waypoint);
7278 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7279 Players_target = Player_ai->target_objnum;
7280 Players_targeted_subsys = Player_ai->targeted_subsys;
7281 Players_target_timestamp = timestamp();
7285 /////////// Following is for event debug view screen
7289 #define EVENT_DEBUG_MAX 5000
7290 #define EVENT_DEBUG_EVENT 0x8000
7292 int Event_debug_index[EVENT_DEBUG_MAX];
7295 void game_add_event_debug_index(int n, int indent)
7297 if (ED_count < EVENT_DEBUG_MAX)
7298 Event_debug_index[ED_count++] = n | (indent << 16);
7301 void game_add_event_debug_sexp(int n, int indent)
7306 if (Sexp_nodes[n].first >= 0) {
7307 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7308 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7312 game_add_event_debug_index(n, indent);
7313 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7314 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7316 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7319 void game_event_debug_init()
7324 for (e=0; e<Num_mission_events; e++) {
7325 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7326 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7330 void game_show_event_debug(float frametime)
7334 int font_height, font_width;
7336 static int scroll_offset = 0;
7338 k = game_check_key();
7344 if (scroll_offset < 0)
7354 scroll_offset -= 20;
7355 if (scroll_offset < 0)
7360 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7364 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7370 gr_set_color_fast(&Color_bright);
7372 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7374 gr_set_color_fast(&Color_normal);
7376 gr_get_string_size(&font_width, &font_height, NOX("test"));
7377 y_max = gr_screen.max_h - font_height - 5;
7381 while (k < ED_count) {
7382 if (y_index > y_max)
7385 z = Event_debug_index[k];
7386 if (z & EVENT_DEBUG_EVENT) {
7388 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7389 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7390 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7391 Mission_events[z].repeat_count, Mission_events[z].interval);
7399 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7400 switch (Sexp_nodes[z & 0x7fff].value) {
7402 strcat(buf, NOX(" (True)"));
7406 strcat(buf, NOX(" (False)"));
7409 case SEXP_KNOWN_TRUE:
7410 strcat(buf, NOX(" (Always true)"));
7413 case SEXP_KNOWN_FALSE:
7414 strcat(buf, NOX(" (Always false)"));
7417 case SEXP_CANT_EVAL:
7418 strcat(buf, NOX(" (Can't eval)"));
7422 case SEXP_NAN_FOREVER:
7423 strcat(buf, NOX(" (Not a number)"));
7428 gr_printf(10, y_index, buf);
7429 y_index += font_height;
7442 extern int Tmap_npixels;
7444 int Tmap_num_too_big = 0;
7445 int Num_models_needing_splitting = 0;
7447 void Time_model( int modelnum )
7449 // mprintf(( "Timing ship '%s'\n", si->name ));
7451 vector eye_pos, model_pos;
7452 matrix eye_orient, model_orient;
7454 polymodel *pm = model_get( modelnum );
7456 int l = strlen(pm->filename);
7458 if ( (l == '/') || (l=='\\') || (l==':')) {
7464 char *pof_file = &pm->filename[l];
7466 int model_needs_splitting = 0;
7468 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7470 for (i=0; i<pm->n_textures; i++ ) {
7471 char filename[1024];
7474 int bmp_num = pm->original_textures[i];
7475 if ( bmp_num > -1 ) {
7476 bm_get_palette(pm->original_textures[i], pal, filename );
7478 bm_get_info( pm->original_textures[i],&w, &h );
7481 if ( (w > 512) || (h > 512) ) {
7482 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7484 model_needs_splitting++;
7487 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7491 if ( model_needs_splitting ) {
7492 Num_models_needing_splitting++;
7494 eye_orient = model_orient = vmd_identity_matrix;
7495 eye_pos = model_pos = vmd_zero_vector;
7497 eye_pos.z = -pm->rad*2.0f;
7499 vector eye_to_model;
7501 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7502 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7504 fix t1 = timer_get_fixed_seconds();
7507 ta.p = ta.b = ta.h = 0.0f;
7512 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7514 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7516 modelstats_num_polys = modelstats_num_verts = 0;
7518 while( ta.h < PI2 ) {
7521 vm_angles_2_matrix(&m1, &ta );
7522 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7529 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7531 model_clear_instance( modelnum );
7532 model_set_detail_level(0); // use highest detail level
7533 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7541 int k = key_inkey();
7542 if ( k == KEY_ESC ) {
7547 fix t2 = timer_get_fixed_seconds();
7549 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7550 //bitmaps_used_this_frame /= framecount;
7552 modelstats_num_polys /= framecount;
7553 modelstats_num_verts /= framecount;
7555 Tmap_npixels /=framecount;
7558 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7559 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 );
7560 // 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 );
7566 int Time_models = 0;
7567 DCF_BOOL( time_models, Time_models );
7569 void Do_model_timings_test()
7573 if ( !Time_models ) return;
7575 mprintf(( "Timing models!\n" ));
7579 ubyte model_used[MAX_POLYGON_MODELS];
7580 int model_id[MAX_POLYGON_MODELS];
7581 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7586 for (i=0; i<Num_ship_types; i++ ) {
7587 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7589 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7590 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7593 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7594 if ( !Texture_fp ) return;
7596 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7597 if ( !Time_fp ) return;
7599 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7600 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7602 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7603 if ( model_used[i] ) {
7604 Time_model( model_id[i] );
7608 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7609 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7618 // Call this function when you want to inform the player that a feature is not
7619 // enabled in the DEMO version of FreSpace
7620 void game_feature_not_in_demo_popup()
7622 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7625 // format the specified time (fixed point) into a nice string
7626 void game_format_time(fix m_time,char *time_str)
7629 int hours,minutes,seconds;
7632 mtime = f2fl(m_time);
7634 // get the hours, minutes and seconds
7635 hours = (int)(mtime / 3600.0f);
7637 mtime -= (3600.0f * (float)hours);
7639 seconds = (int)mtime%60;
7640 minutes = (int)mtime/60;
7642 // print the hour if necessary
7644 sprintf(time_str,XSTR( "%d:", 201),hours);
7645 // if there are less than 10 minutes, print a leading 0
7647 strcpy(tmp,NOX("0"));
7648 strcat(time_str,tmp);
7652 // print the minutes
7654 sprintf(tmp,XSTR( "%d:", 201),minutes);
7655 strcat(time_str,tmp);
7657 sprintf(time_str,XSTR( "%d:", 201),minutes);
7660 // print the seconds
7662 strcpy(tmp,NOX("0"));
7663 strcat(time_str,tmp);
7665 sprintf(tmp,"%d",seconds);
7666 strcat(time_str,tmp);
7669 // Stuff version string in *str.
7670 void get_version_string(char *str)
7673 if ( FS_VERSION_BUILD == 0 ) {
7674 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7676 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7679 #if defined (FS2_DEMO)
7681 #elif defined (OEM_BUILD)
7682 strcat(str, " (OEM)");
7688 char myname[_MAX_PATH];
7689 int namelen, major, minor, build, waste;
7690 unsigned int buf_size;
7696 // Find my EXE file name
7697 hMod = GetModuleHandle(NULL);
7698 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7700 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7701 infop = (char *)malloc(version_size);
7702 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7704 // get the product version
7705 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7706 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7708 sprintf(str,"Dv%d.%02d",major, minor);
7710 sprintf(str,"v%d.%02d",major, minor);
7715 void get_version_string_short(char *str)
7717 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7720 // ----------------------------------------------------------------
7722 // OEM UPSELL SCREENS BEGIN
7724 // ----------------------------------------------------------------
7725 #if defined(OEM_BUILD)
7727 #define NUM_OEM_UPSELL_SCREENS 3
7728 #define OEM_UPSELL_SCREEN_DELAY 10000
7730 static int Oem_upsell_bitmaps_loaded = 0;
7731 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7732 static int Oem_upsell_screen_number = 0;
7733 static int Oem_upsell_show_next_bitmap_time;
7736 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7749 static int Oem_normal_cursor = -1;
7750 static int Oem_web_cursor = -1;
7751 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7752 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7754 void oem_upsell_next_screen()
7756 Oem_upsell_screen_number++;
7757 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7758 // extra long delay, mouse shown on last upsell
7759 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7763 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7767 void oem_upsell_load_bitmaps()
7771 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7772 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7776 void oem_upsell_unload_bitmaps()
7780 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7781 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7782 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7787 Oem_upsell_bitmaps_loaded = 0;
7790 // clickable hotspot on 3rd OEM upsell screen
7791 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7793 28, 350, 287, 96 // x, y, w, h
7796 45, 561, 460, 152 // x, y, w, h
7800 void oem_upsell_show_screens()
7802 int current_time, k;
7805 if ( !Oem_upsell_bitmaps_loaded ) {
7806 oem_upsell_load_bitmaps();
7807 Oem_upsell_bitmaps_loaded = 1;
7810 // may use upsell screens more than once
7811 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7812 Oem_upsell_screen_number = 0;
7818 int nframes; // used to pass, not really needed (should be 1)
7819 Oem_normal_cursor = gr_get_cursor_bitmap();
7820 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7821 Assert(Oem_web_cursor >= 0);
7822 if (Oem_web_cursor < 0) {
7823 Oem_web_cursor = Oem_normal_cursor;
7828 //oem_reset_trailer_timer();
7830 current_time = timer_get_milliseconds();
7835 // advance screen on keypress or timeout
7836 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7837 oem_upsell_next_screen();
7840 // check if we are done
7841 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7842 Oem_upsell_screen_number--;
7845 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7850 // show me the upsell
7851 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7852 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7856 // if this is the 3rd upsell, make it clickable, d00d
7857 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7859 int button_state = mouse_get_pos(&mx, &my);
7860 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])
7861 && (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]) )
7864 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7867 if (button_state & MOUSE_LEFT_BUTTON) {
7869 multi_pxo_url(OEM_UPSELL_URL);
7873 // switch cursor back to normal one
7874 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7879 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7889 oem_upsell_unload_bitmaps();
7891 // switch cursor back to normal one
7892 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7896 #endif // defined(OEM_BUILD)
7897 // ----------------------------------------------------------------
7899 // OEM UPSELL SCREENS END
7901 // ----------------------------------------------------------------
7905 // ----------------------------------------------------------------
7907 // DEMO UPSELL SCREENS BEGIN
7909 // ----------------------------------------------------------------
7913 //#define NUM_DEMO_UPSELL_SCREENS 4
7915 #define NUM_DEMO_UPSELL_SCREENS 2
7916 #define DEMO_UPSELL_SCREEN_DELAY 3000
7918 static int Demo_upsell_bitmaps_loaded = 0;
7919 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7920 static int Demo_upsell_screen_number = 0;
7921 static int Demo_upsell_show_next_bitmap_time;
7924 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7937 void demo_upsell_next_screen()
7939 Demo_upsell_screen_number++;
7940 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7941 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7943 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7947 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7948 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7949 #ifndef HARDWARE_ONLY
7950 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7957 void demo_upsell_load_bitmaps()
7961 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7962 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7966 void demo_upsell_unload_bitmaps()
7970 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7971 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7972 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7977 Demo_upsell_bitmaps_loaded = 0;
7980 void demo_upsell_show_screens()
7982 int current_time, k;
7985 if ( !Demo_upsell_bitmaps_loaded ) {
7986 demo_upsell_load_bitmaps();
7987 Demo_upsell_bitmaps_loaded = 1;
7990 // may use upsell screens more than once
7991 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7992 Demo_upsell_screen_number = 0;
7999 demo_reset_trailer_timer();
8001 current_time = timer_get_milliseconds();
8008 // don't time out, wait for keypress
8010 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8011 demo_upsell_next_screen();
8016 demo_upsell_next_screen();
8019 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8020 Demo_upsell_screen_number--;
8023 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8028 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8029 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8034 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8044 demo_upsell_unload_bitmaps();
8049 // ----------------------------------------------------------------
8051 // DEMO UPSELL SCREENS END
8053 // ----------------------------------------------------------------
8056 // ----------------------------------------------------------------
8058 // Subspace Ambient Sound START
8060 // ----------------------------------------------------------------
8062 static int Subspace_ambient_left_channel = -1;
8063 static int Subspace_ambient_right_channel = -1;
8066 void game_start_subspace_ambient_sound()
8068 if ( Subspace_ambient_left_channel < 0 ) {
8069 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8072 if ( Subspace_ambient_right_channel < 0 ) {
8073 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8077 void game_stop_subspace_ambient_sound()
8079 if ( Subspace_ambient_left_channel >= 0 ) {
8080 snd_stop(Subspace_ambient_left_channel);
8081 Subspace_ambient_left_channel = -1;
8084 if ( Subspace_ambient_right_channel >= 0 ) {
8085 snd_stop(Subspace_ambient_right_channel);
8086 Subspace_ambient_right_channel = -1;
8090 // ----------------------------------------------------------------
8092 // Subspace Ambient Sound END
8094 // ----------------------------------------------------------------
8096 // ----------------------------------------------------------------
8098 // CDROM detection code START
8100 // ----------------------------------------------------------------
8102 #define CD_SIZE_72_MINUTE_MAX (697000000)
8104 uint game_get_cd_used_space(char *path)
8108 char use_path[512] = "";
8109 char sub_path[512] = "";
8110 WIN32_FIND_DATA find;
8113 // recurse through all files and directories
8114 strcpy(use_path, path);
8115 strcat(use_path, "*.*");
8116 find_handle = FindFirstFile(use_path, &find);
8119 if(find_handle == INVALID_HANDLE_VALUE){
8125 // subdirectory. make sure to ignore . and ..
8126 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8128 strcpy(sub_path, path);
8129 strcat(sub_path, find.cFileName);
8130 strcat(sub_path, "\\");
8131 total += game_get_cd_used_space(sub_path);
8133 total += (uint)find.nFileSizeLow;
8135 } while(FindNextFile(find_handle, &find));
8138 FindClose(find_handle);
8150 // if volume_name is non-null, the CD name must match that
8151 int find_freespace_cd(char *volume_name)
8154 char oldpath[MAX_PATH];
8158 int volume_match = 0;
8162 GetCurrentDirectory(MAX_PATH, oldpath);
8164 for (i = 0; i < 26; i++)
8170 path[0] = (char)('A'+i);
8171 if (GetDriveType(path) == DRIVE_CDROM) {
8173 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8174 nprintf(("CD", "CD volume: %s\n", volume));
8176 // check for any CD volume
8177 int volume1_present = 0;
8178 int volume2_present = 0;
8179 int volume3_present = 0;
8181 char full_check[512] = "";
8183 // look for setup.exe
8184 strcpy(full_check, path);
8185 strcat(full_check, "setup.exe");
8186 find_handle = _findfirst(full_check, &find);
8187 if(find_handle != -1){
8188 volume1_present = 1;
8189 _findclose(find_handle);
8192 // look for intro.mve
8193 strcpy(full_check, path);
8194 strcat(full_check, "intro.mve");
8195 find_handle = _findfirst(full_check, &find);
8196 if(find_handle != -1){
8197 volume2_present = 1;
8198 _findclose(find_handle);
8201 // look for endpart1.mve
8202 strcpy(full_check, path);
8203 strcat(full_check, "endpart1.mve");
8204 find_handle = _findfirst(full_check, &find);
8205 if(find_handle != -1){
8206 volume3_present = 1;
8207 _findclose(find_handle);
8210 // see if we have the specific CD we're looking for
8211 if ( volume_name ) {
8213 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8217 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8221 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8225 if ( volume1_present || volume2_present || volume3_present ) {
8230 // 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
8231 if ( volume_match ){
8233 // 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
8234 if(volume2_present || volume3_present) {
8235 // first step - check to make sure its a cdrom
8236 if(GetDriveType(path) != DRIVE_CDROM){
8240 #if !defined(OEM_BUILD)
8241 // oem not on 80 min cds, so dont check tha size
8243 uint used_space = game_get_cd_used_space(path);
8244 if(used_space < CD_SIZE_72_MINUTE_MAX){
8247 #endif // !defined(OEM_BUILD)
8255 #endif // RELEASE_REAL
8261 SetCurrentDirectory(oldpath);
8270 int set_cdrom_path(int drive_num)
8274 if (drive_num < 0) { //no CD
8276 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8279 strcpy(Game_CDROM_dir,""); //set directory
8283 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8299 i = find_freespace_cd();
8301 rval = set_cdrom_path(i);
8305 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8307 nprintf(("CD", "FreeSpace CD not found\n"));
8315 int Last_cd_label_found = 0;
8316 char Last_cd_label[256];
8318 int game_cd_changed()
8325 if ( strlen(Game_CDROM_dir) == 0 ) {
8329 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8331 if ( found != Last_cd_label_found ) {
8332 Last_cd_label_found = found;
8334 mprintf(( "CD '%s' was inserted\n", label ));
8337 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8341 if ( Last_cd_label_found ) {
8342 if ( !stricmp( Last_cd_label, label )) {
8343 //mprintf(( "CD didn't change\n" ));
8345 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8349 // none found before, none found now.
8350 //mprintf(( "still no CD...\n" ));
8354 Last_cd_label_found = found;
8356 strcpy( Last_cd_label, label );
8358 strcpy( Last_cd_label, "" );
8369 // check if _any_ FreeSpace2 CDs are in the drive
8370 // return: 1 => CD now in drive
8371 // 0 => Could not find CD, they refuse to put it in the drive
8372 int game_do_cd_check(char *volume_name)
8374 #if !defined(GAME_CD_CHECK)
8380 int num_attempts = 0;
8381 int refresh_files = 0;
8383 int path_set_ok, popup_rval;
8385 cd_drive_num = find_freespace_cd(volume_name);
8386 path_set_ok = set_cdrom_path(cd_drive_num);
8387 if ( path_set_ok ) {
8389 if ( refresh_files ) {
8401 // no CD found, so prompt user
8402 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8404 if ( popup_rval != 1 ) {
8409 if ( num_attempts++ > 5 ) {
8420 // check if _any_ FreeSpace2 CDs are in the drive
8421 // return: 1 => CD now in drive
8422 // 0 => Could not find CD, they refuse to put it in the drive
8423 int game_do_cd_check_specific(char *volume_name, int cdnum)
8428 int num_attempts = 0;
8429 int refresh_files = 0;
8431 int path_set_ok, popup_rval;
8433 cd_drive_num = find_freespace_cd(volume_name);
8434 path_set_ok = set_cdrom_path(cd_drive_num);
8435 if ( path_set_ok ) {
8437 if ( refresh_files ) {
8448 // no CD found, so prompt user
8449 #if defined(DVD_MESSAGE_HACK)
8450 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8452 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8455 if ( popup_rval != 1 ) {
8460 if ( num_attempts++ > 5 ) {
8470 // only need to do this in RELEASE_REAL
8471 int game_do_cd_mission_check(char *filename)
8477 fs_builtin_mission *m = game_find_builtin_mission(filename);
8479 // check for changed CD
8480 if(game_cd_changed()){
8485 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8489 // not builtin, so do a general check (any FS2 CD will do)
8491 return game_do_cd_check();
8494 // does not have any CD requirement, do a general check
8495 if(strlen(m->cd_volume) <= 0){
8496 return game_do_cd_check();
8500 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8502 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8504 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8507 return game_do_cd_check();
8510 // did we find the cd?
8511 if(find_freespace_cd(m->cd_volume) >= 0){
8515 // make sure the volume exists
8516 int num_attempts = 0;
8517 int refresh_files = 0;
8519 int path_set_ok, popup_rval;
8521 cd_drive_num = find_freespace_cd(m->cd_volume);
8522 path_set_ok = set_cdrom_path(cd_drive_num);
8523 if ( path_set_ok ) {
8525 if ( refresh_files ) {
8532 // no CD found, so prompt user
8533 #if defined(DVD_MESSAGE_HACK)
8534 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8536 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8540 if ( popup_rval != 1 ) {
8545 if ( num_attempts++ > 5 ) {
8557 // ----------------------------------------------------------------
8559 // CDROM detection code END
8561 // ----------------------------------------------------------------
8563 // ----------------------------------------------------------------
8564 // SHIPS TBL VERIFICATION STUFF
8567 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8568 #define NUM_SHIPS_TBL_CHECKSUMS 1
8571 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8572 1696074201, // FS2 demo
8576 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8577 -463907578, // US - beta 1
8578 1696074201, // FS2 demo
8581 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8582 // -1022810006, // 1.0 FULL
8583 -1254285366 // 1.2 FULL (German)
8587 void verify_ships_tbl()
8591 Game_ships_tbl_valid = 1;
8597 // detect if the packfile exists
8598 CFILE *detect = cfopen("ships.tbl", "rb");
8599 Game_ships_tbl_valid = 0;
8603 Game_ships_tbl_valid = 0;
8607 // get the long checksum of the file
8609 cfseek(detect, 0, SEEK_SET);
8610 cf_chksum_long(detect, &file_checksum);
8614 // now compare the checksum/filesize against known #'s
8615 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8616 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8617 Game_ships_tbl_valid = 1;
8624 DCF(shipspew, "display the checksum for the current ships.tbl")
8627 CFILE *detect = cfopen("ships.tbl", "rb");
8628 // get the long checksum of the file
8630 cfseek(detect, 0, SEEK_SET);
8631 cf_chksum_long(detect, &file_checksum);
8634 dc_printf("%d", file_checksum);
8637 // ----------------------------------------------------------------
8638 // WEAPONS TBL VERIFICATION STUFF
8641 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8642 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8645 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8646 -266420030, // demo 1
8650 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8651 141718090, // US - beta 1
8652 -266420030, // demo 1
8655 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8656 // 399297860, // 1.0 FULL
8657 -553984927 // 1.2 FULL (german)
8661 void verify_weapons_tbl()
8665 Game_weapons_tbl_valid = 1;
8671 // detect if the packfile exists
8672 CFILE *detect = cfopen("weapons.tbl", "rb");
8673 Game_weapons_tbl_valid = 0;
8677 Game_weapons_tbl_valid = 0;
8681 // get the long checksum of the file
8683 cfseek(detect, 0, SEEK_SET);
8684 cf_chksum_long(detect, &file_checksum);
8688 // now compare the checksum/filesize against known #'s
8689 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8690 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8691 Game_weapons_tbl_valid = 1;
8698 DCF(wepspew, "display the checksum for the current weapons.tbl")
8701 CFILE *detect = cfopen("weapons.tbl", "rb");
8702 // get the long checksum of the file
8704 cfseek(detect, 0, SEEK_SET);
8705 cf_chksum_long(detect, &file_checksum);
8708 dc_printf("%d", file_checksum);
8711 // if the game is running using hacked data
8712 int game_hacked_data()
8715 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8723 void display_title_screen()
8725 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8726 ///int title_bitmap;
8729 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8730 if (title_bitmap == -1) {
8736 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8737 extern void d3d_start_frame();
8743 gr_set_bitmap(title_bitmap);
8750 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8751 extern void d3d_stop_frame();
8759 bm_unload(title_bitmap);
8760 #endif // FS2_DEMO || OEM_BUILD
8763 // return true if the game is running with "low memory", which is less than 48MB
8764 bool game_using_low_mem()
8766 if (Use_low_mem == 0) {