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.19 2002/06/17 06:33:08 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.18 2002/06/16 04:46:33 relnev
22 * set up correct checksums for demo
24 * Revision 1.17 2002/06/09 04:41:17 relnev
25 * added copyright header
27 * Revision 1.16 2002/06/09 03:16:04 relnev
30 * removed unneeded asm, old sdl 2d setup.
32 * fixed crash caused by opengl_get_region.
34 * Revision 1.15 2002/06/05 08:05:28 relnev
35 * stub/warning removal.
37 * reworked the sound code.
39 * Revision 1.14 2002/06/05 04:03:32 relnev
40 * finished cfilesystem.
42 * removed some old code.
44 * fixed mouse save off-by-one.
48 * Revision 1.13 2002/06/02 04:26:34 relnev
51 * Revision 1.12 2002/06/02 00:31:35 relnev
52 * implemented osregistry
54 * Revision 1.11 2002/06/01 09:00:34 relnev
55 * silly debug memmanager
57 * Revision 1.10 2002/06/01 07:12:32 relnev
58 * a few NDEBUG updates.
60 * removed a few warnings.
62 * Revision 1.9 2002/05/31 03:05:59 relnev
65 * Revision 1.8 2002/05/29 02:52:32 theoddone33
66 * Enable OpenGL renderer
68 * Revision 1.7 2002/05/28 08:52:03 relnev
69 * implemented two assembly stubs.
71 * cleaned up a few warnings.
73 * added a little demo hackery to make it progress a little farther.
75 * Revision 1.6 2002/05/28 06:28:20 theoddone33
76 * Filesystem mods, actually reads some data files now
78 * Revision 1.5 2002/05/28 04:07:28 theoddone33
79 * New graphics stubbing arrangement
81 * Revision 1.4 2002/05/27 22:46:52 theoddone33
82 * Remove more undefined symbols
84 * Revision 1.3 2002/05/26 23:31:18 relnev
85 * added a few files that needed to be compiled
87 * freespace.cpp: now compiles
89 * Revision 1.2 2002/05/07 03:16:44 theoddone33
90 * The Great Newline Fix
92 * Revision 1.1.1.1 2002/05/03 03:28:09 root
96 * 201 6/16/00 3:15p Jefff
97 * sim of the year dvd version changes, a few german soty localization
100 * 200 11/03/99 11:06a Jefff
103 * 199 10/26/99 5:07p Jamest
104 * fixed jeffs dumb debug code
106 * 198 10/25/99 5:53p Jefff
107 * call control_config_common_init() on startup
109 * 197 10/14/99 10:18a Daveb
110 * Fixed incorrect CD checking problem on standalone server.
112 * 196 10/13/99 9:22a Daveb
113 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
114 * related to movies. Fixed launcher spawning from PXO screen.
116 * 195 10/06/99 11:05a Jefff
117 * new oem upsell 3 hotspot coords
119 * 194 10/06/99 10:31a Jefff
122 * 193 10/01/99 9:10a Daveb
125 * 192 9/15/99 4:57a Dave
126 * Updated ships.tbl checksum
128 * 191 9/15/99 3:58a Dave
129 * Removed framerate warning at all times.
131 * 190 9/15/99 3:16a Dave
132 * Remove mt-011.fs2 from the builtin mission list.
134 * 189 9/15/99 1:45a Dave
135 * Don't init joystick on standalone. Fixed campaign mode on standalone.
136 * Fixed no-score-report problem in TvT
138 * 188 9/14/99 6:08a Dave
139 * Updated (final) single, multi, and campaign list.
141 * 187 9/14/99 3:26a Dave
142 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
143 * respawn-too-early problem. Made a few crash points safe.
145 * 186 9/13/99 4:52p Dave
148 * 185 9/12/99 8:09p Dave
149 * Fixed problem where skip-training button would cause mission messages
150 * not to get paged out for the current mission.
152 * 184 9/10/99 11:53a Dave
153 * Shutdown graphics before sound to eliminate apparent lockups when
154 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
156 * 183 9/09/99 11:40p Dave
157 * Handle an Assert() in beam code. Added supernova sounds. Play the right
158 * 2 end movies properly, based upon what the player did in the mission.
160 * 182 9/08/99 10:29p Dave
161 * Make beam sound pausing and unpausing much safer.
163 * 181 9/08/99 10:01p Dave
164 * Make sure game won't run in a drive's root directory. Make sure
165 * standalone routes suqad war messages properly to the host.
167 * 180 9/08/99 3:22p Dave
168 * Updated builtin mission list.
170 * 179 9/08/99 12:01p Jefff
171 * fixed Game_builtin_mission_list typo on Training-2.fs2
173 * 178 9/08/99 9:48a Andsager
174 * Add force feedback for engine wash.
176 * 177 9/07/99 4:01p Dave
177 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
178 * does everything properly (setting up address when binding). Remove
179 * black rectangle background from UI_INPUTBOX.
181 * 176 9/13/99 2:40a Dave
182 * Comment in full 80 minute CD check for RELEASE_REAL builds.
184 * 175 9/06/99 6:38p Dave
185 * Improved CD detection code.
187 * 174 9/06/99 1:30a Dave
188 * Intermediate checkin. Started on enforcing CD-in-drive to play the
191 * 173 9/06/99 1:16a Dave
192 * Make sure the user sees the intro movie.
194 * 172 9/04/99 8:00p Dave
195 * Fixed up 1024 and 32 bit movie support.
197 * 171 9/03/99 1:32a Dave
198 * CD checking by act. Added support to play 2 cutscenes in a row
199 * seamlessly. Fixed super low level cfile bug related to files in the
200 * root directory of a CD. Added cheat code to set campaign mission # in
203 * 170 9/01/99 10:49p Dave
204 * Added nice SquadWar checkbox to the client join wait screen.
206 * 169 9/01/99 10:14a Dave
209 * 168 8/29/99 4:51p Dave
210 * Fixed damaged checkin.
212 * 167 8/29/99 4:18p Andsager
213 * New "burst" limit for friendly damage. Also credit more damage done
214 * against large friendly ships.
216 * 166 8/27/99 6:38p Alanl
217 * crush the blasted repeating messages bug
219 * 164 8/26/99 9:09p Dave
220 * Force framerate check in everything but a RELEASE_REAL build.
222 * 163 8/26/99 9:45a Dave
223 * First pass at easter eggs and cheats.
225 * 162 8/24/99 8:55p Dave
226 * Make sure nondimming pixels work properly in tech menu.
228 * 161 8/24/99 1:49a Dave
229 * Fixed client-side afterburner stuttering. Added checkbox for no version
230 * checking on PXO join. Made button info passing more friendly between
233 * 160 8/22/99 5:53p Dave
234 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
235 * instead of ship designations for multiplayer players.
237 * 159 8/22/99 1:19p Dave
238 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
239 * which d3d cards are detected.
241 * 158 8/20/99 2:09p Dave
242 * PXO banner cycling.
244 * 157 8/19/99 10:59a Dave
245 * Packet loss detection.
247 * 156 8/19/99 10:12a Alanl
248 * preload mission-specific messages on machines greater than 48MB
250 * 155 8/16/99 4:04p Dave
251 * Big honking checkin.
253 * 154 8/11/99 5:54p Dave
254 * Fixed collision problem. Fixed standalone ghost problem.
256 * 153 8/10/99 7:59p Jefff
259 * 152 8/10/99 6:54p Dave
260 * Mad optimizations. Added paging to the nebula effect.
262 * 151 8/10/99 3:44p Jefff
263 * loads Intelligence information on startup
265 * 150 8/09/99 3:47p Dave
266 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
267 * non-nebula missions.
269 * 149 8/09/99 2:21p Andsager
270 * Fix patching from multiplayer direct to launcher update tab.
272 * 148 8/09/99 10:36a Dave
273 * Version info for game.
275 * 147 8/06/99 9:46p Dave
276 * Hopefully final changes for the demo.
278 * 146 8/06/99 3:34p Andsager
279 * Make title version info "(D)" -> "D" show up nicely
281 * 145 8/06/99 2:59p Adamp
282 * Fixed NT launcher/update problem.
284 * 144 8/06/99 1:52p Dave
285 * Bumped up MAX_BITMAPS for the demo.
287 * 143 8/06/99 12:17p Andsager
288 * Demo: down to just 1 demo dog
290 * 142 8/05/99 9:39p Dave
291 * Yet another new checksum.
293 * 141 8/05/99 6:19p Dave
294 * New demo checksums.
296 * 140 8/05/99 5:31p Andsager
297 * Up demo version 1.01
299 * 139 8/05/99 4:22p Andsager
300 * No time limit on upsell screens. Reverse order of display of upsell
303 * 138 8/05/99 4:17p Dave
304 * Tweaks to client interpolation.
306 * 137 8/05/99 3:52p Danw
308 * 136 8/05/99 3:01p Danw
310 * 135 8/05/99 2:43a Anoop
311 * removed duplicate definition.
313 * 134 8/05/99 2:13a Dave
316 * 133 8/05/99 2:05a Dave
319 * 132 8/05/99 1:22a Andsager
322 * 131 8/04/99 9:51p Andsager
323 * Add title screen to demo
325 * 130 8/04/99 6:47p Jefff
326 * fixed link error resulting from #ifdefs
328 * 129 8/04/99 6:26p Dave
329 * Updated ship tbl checksum.
331 * 128 8/04/99 5:40p Andsager
332 * Add multiple demo dogs
334 * 127 8/04/99 5:36p Andsager
335 * Show upsell screens at end of demo campaign before returning to main
338 * 126 8/04/99 11:42a Danw
339 * tone down EAX reverb
341 * 125 8/04/99 11:23a Dave
342 * Updated demo checksums.
344 * 124 8/03/99 11:02p Dave
345 * Maybe fixed sync problems in multiplayer.
347 * 123 8/03/99 6:21p Jefff
350 * 122 8/03/99 3:44p Andsager
351 * Launch laucher if trying to run FS without first having configured
354 * 121 8/03/99 12:45p Dave
357 * 120 8/02/99 9:13p Dave
360 * 119 7/30/99 10:31p Dave
361 * Added comm menu to the configurable hud files.
363 * 118 7/30/99 5:17p Andsager
364 * first fs2demo checksums
366 * 117 7/29/99 3:09p Anoop
368 * 116 7/29/99 12:05a Dave
369 * Nebula speed optimizations.
371 * 115 7/27/99 8:59a Andsager
372 * Make major, minor version consistent for all builds. Only show major
373 * and minor for launcher update window.
375 * 114 7/26/99 5:50p Dave
376 * Revised ingame join. Better? We'll see....
378 * 113 7/26/99 5:27p Andsager
379 * Add training mission as builtin to demo build
381 * 112 7/24/99 1:54p Dave
382 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
385 * 111 7/22/99 4:00p Dave
386 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
388 * 110 7/21/99 8:10p Dave
389 * First run of supernova effect.
391 * 109 7/20/99 1:49p Dave
392 * Peter Drake build. Fixed some release build warnings.
394 * 108 7/19/99 2:26p Andsager
395 * set demo multiplayer missions
397 * 107 7/18/99 5:19p Dave
398 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
400 * 106 7/16/99 1:50p Dave
401 * 8 bit aabitmaps. yay.
403 * 105 7/15/99 3:07p Dave
404 * 32 bit detection support. Mouse coord commandline.
406 * 104 7/15/99 2:13p Dave
407 * Added 32 bit detection.
409 * 103 7/15/99 9:20a Andsager
410 * FS2_DEMO initial checkin
412 * 102 7/14/99 11:02a Dave
413 * Skill level default back to easy. Blech.
415 * 101 7/09/99 5:54p Dave
416 * Seperated cruiser types into individual types. Added tons of new
417 * briefing icons. Campaign screen.
419 * 100 7/08/99 4:43p Andsager
420 * New check for sparky_hi and print if not found.
422 * 99 7/08/99 10:53a Dave
423 * New multiplayer interpolation scheme. Not 100% done yet, but still
424 * better than the old way.
426 * 98 7/06/99 4:24p Dave
427 * Mid-level checkin. Starting on some potentially cool multiplayer
430 * 97 7/06/99 3:35p Andsager
431 * Allow movie to play before red alert mission.
433 * 96 7/03/99 5:50p Dave
434 * Make rotated bitmaps draw properly in padlock views.
436 * 95 7/02/99 9:55p Dave
437 * Player engine wash sound.
439 * 94 7/02/99 4:30p Dave
440 * Much more sophisticated lightning support.
442 * 93 6/29/99 7:52p Dave
443 * Put in exception handling in FS2.
445 * 92 6/22/99 9:37p Dave
446 * Put in pof spewing.
448 * 91 6/16/99 4:06p Dave
449 * New pilot info popup. Added new draw-bitmap-as-poly function.
451 * 90 6/15/99 1:56p Andsager
452 * For release builds, allow start up in high res only with
455 * 89 6/15/99 9:34a Dave
456 * Fixed key checking in single threaded version of the stamp notification
459 * 88 6/09/99 2:55p Andsager
460 * Allow multiple asteroid subtypes (of large, medium, small) and follow
463 * 87 6/08/99 1:14a Dave
464 * Multi colored hud test.
466 * 86 6/04/99 9:52a Dave
467 * Fixed some rendering problems.
469 * 85 6/03/99 10:15p Dave
470 * Put in temporary main hall screen.
472 * 84 6/02/99 6:18p Dave
473 * Fixed TNT lockup problems! Wheeeee!
475 * 83 6/01/99 3:52p Dave
476 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
477 * dead popup, pxo find player popup, pxo private room popup.
479 * 82 5/26/99 1:28p Jasenw
480 * changed coords for loading ani
482 * 81 5/26/99 11:46a Dave
483 * Added ship-blasting lighting and made the randomization of lighting
484 * much more customizable.
486 * 80 5/24/99 5:45p Dave
487 * Added detail levels to the nebula, with a decent speedup. Split nebula
488 * lightning into its own section.
506 #include "systemvars.h"
511 #include "starfield.h"
512 #include "lighting.h"
517 #include "fireballs.h"
521 #include "floating.h"
522 #include "gamesequence.h"
524 #include "optionsmenu.h"
525 #include "playermenu.h"
526 #include "trainingmenu.h"
527 #include "techmenu.h"
530 #include "hudmessage.h"
532 #include "missiongoals.h"
533 #include "missionparse.h"
538 #include "multiutil.h"
539 #include "multimsgs.h"
543 #include "freespace.h"
544 #include "managepilot.h"
546 #include "contexthelp.h"
549 #include "missionbrief.h"
550 #include "missiondebrief.h"
552 #include "missionshipchoice.h"
554 #include "hudconfig.h"
555 #include "controlsconfig.h"
556 #include "missionmessage.h"
557 #include "missiontraining.h"
559 #include "hudtarget.h"
563 #include "eventmusic.h"
564 #include "animplay.h"
565 #include "missionweaponchoice.h"
566 #include "missionlog.h"
567 #include "audiostr.h"
569 #include "missioncampaign.h"
571 #include "missionhotkey.h"
572 #include "objectsnd.h"
573 #include "cmeasure.h"
575 #include "linklist.h"
576 #include "shockwave.h"
577 #include "afterburner.h"
582 #include "stand_gui.h"
583 #include "pcxutils.h"
584 #include "hudtargetbox.h"
585 #include "multi_xfer.h"
586 #include "hudescort.h"
587 #include "multiutil.h"
590 #include "multiteamselect.h"
593 #include "readyroom.h"
594 #include "mainhallmenu.h"
595 #include "multilag.h"
597 #include "particle.h"
599 #include "multi_ingame.h"
600 #include "snazzyui.h"
601 #include "asteroid.h"
602 #include "popupdead.h"
603 #include "multi_voice.h"
604 #include "missioncmdbrief.h"
605 #include "redalert.h"
606 #include "gameplayhelp.h"
607 #include "multilag.h"
608 #include "staticrand.h"
609 #include "multi_pmsg.h"
610 #include "levelpaging.h"
611 #include "observer.h"
612 #include "multi_pause.h"
613 #include "multi_endgame.h"
614 #include "cutscenes.h"
615 #include "multi_respawn.h"
616 // #include "movie.h"
617 #include "multi_obj.h"
618 #include "multi_log.h"
620 #include "localize.h"
621 #include "osregistry.h"
622 #include "barracks.h"
623 #include "missionpause.h"
625 #include "alphacolors.h"
626 #include "objcollide.h"
629 #include "neblightning.h"
630 #include "shipcontrails.h"
633 #include "multi_dogfight.h"
634 #include "multi_rate.h"
635 #include "muzzleflash.h"
639 #include "mainhalltemp.h"
640 #include "exceptionhandler.h"
644 #include "supernova.h"
645 #include "hudshield.h"
646 // #include "names.h"
648 #include "missionloopbrief.h"
652 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
658 // 1.00.04 5/26/98 MWA -- going final (12 pm)
659 // 1.00.03 5/26/98 MWA -- going final (3 am)
660 // 1.00.02 5/25/98 MWA -- going final
661 // 1.00.01 5/25/98 MWA -- going final
662 // 0.90 5/21/98 MWA -- getting ready for final.
663 // 0.10 4/9/98. Set by MK.
665 // Demo version: (obsolete since DEMO codebase split from tree)
666 // 0.03 4/10/98 AL. Interplay rev
667 // 0.02 4/8/98 MK. Increased when this system was modified.
668 // 0.01 4/7/98? AL. First release to Interplay QA.
671 // 1.00 5/28/98 AL. First release to Interplay QA.
673 void game_level_init(int seed = -1);
674 void game_post_level_init();
675 void game_do_frame();
676 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
677 void game_reset_time();
678 void game_show_framerate(); // draws framerate in lower right corner
680 int Game_no_clear = 0;
682 int Pofview_running = 0;
683 int Nebedit_running = 0;
685 typedef struct big_expl_flash {
686 float max_flash_intensity; // max intensity
687 float cur_flash_intensity; // cur intensity
688 int flash_start; // start time
691 #define FRAME_FILTER 16
693 #define DEFAULT_SKILL_LEVEL 1
694 int Game_skill_level = DEFAULT_SKILL_LEVEL;
696 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
697 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
699 #define EXE_FNAME ("fs2.exe")
700 #define LAUNCHER_FNAME ("freespace2.exe")
702 // JAS: Code for warphole camera.
703 // Needs to be cleaned up.
704 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
705 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
706 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
707 matrix Camera_orient = IDENTITY_MATRIX;
708 float Camera_damping = 1.0f;
709 float Camera_time = 0.0f;
710 float Warpout_time = 0.0f;
711 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
712 int Warpout_sound = -1;
714 int Use_joy_mouse = 0;
715 int Use_palette_flash = 1;
717 int Use_fullscreen_at_startup = 0;
719 int Show_area_effect = 0;
720 object *Last_view_target = NULL;
722 int dogfight_blown = 0;
725 float frametimes[FRAME_FILTER];
726 float frametotal = 0.0f;
730 int Show_framerate = 0;
732 int Show_framerate = 1;
735 int Framerate_cap = 120;
738 int Show_target_debug_info = 0;
739 int Show_target_weapons = 0;
743 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
746 int Debug_octant = -1;
748 fix Game_time_compression = F1_0;
750 // if the ships.tbl the player has is valid
751 int Game_ships_tbl_valid = 0;
753 // if the weapons.tbl the player has is valid
754 int Game_weapons_tbl_valid = 0;
758 extern int Player_attacking_enabled;
762 int Pre_player_entry;
764 int Fred_running = 0;
765 char Game_current_mission_filename[MAX_FILENAME_LEN];
766 int game_single_step = 0;
767 int last_single_step=0;
769 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
770 extern int MSG_WINDOW_Y_START;
771 extern int MSG_WINDOW_HEIGHT;
773 int game_zbuffer = 1;
774 //static int Game_music_paused;
775 static int Game_paused;
779 #define EXPIRE_BAD_CHECKSUM 1
780 #define EXPIRE_BAD_TIME 2
782 extern void ssm_init();
783 extern void ssm_level_init();
784 extern void ssm_process();
786 // static variable to contain the time this version was built
787 // commented out for now until
788 // I figure out how to get the username into the file
789 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
791 // defines and variables used for dumping frame for making trailers.
793 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
794 int Debug_dump_trigger = 0;
795 int Debug_dump_frame_count;
796 int Debug_dump_frame_num = 0;
797 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
800 // amount of time to wait after the player has died before we display the death died popup
801 #define PLAYER_DIED_POPUP_WAIT 2500
802 int Player_died_popup_wait = -1;
803 int Player_multi_died_check = -1;
805 // builtin mission list stuff
807 int Game_builtin_mission_count = 6;
808 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
809 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
810 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
811 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
812 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
813 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
814 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
816 #elif defined(PD_BUILD)
817 int Game_builtin_mission_count = 4;
818 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
819 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
820 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
821 { "sm1-01", (FSB_FROM_VOLITION), "" },
822 { "sm1-05", (FSB_FROM_VOLITION), "" },
824 #elif defined(MULTIPLAYER_BETA)
825 int Game_builtin_mission_count = 17;
826 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
828 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
829 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
830 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
831 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
832 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
833 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
834 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
835 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
838 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
841 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
842 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
843 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
844 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
846 #elif defined(OEM_BUILD)
847 int Game_builtin_mission_count = 17;
848 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
849 // oem version - act 1 only
850 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
853 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
854 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
855 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
856 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
857 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
858 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
859 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
860 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
861 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
862 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
863 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
866 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
871 int Game_builtin_mission_count = 92;
872 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
873 // single player campaign
874 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
877 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
878 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
879 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
880 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
881 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
882 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
883 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
884 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
885 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
886 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
887 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
899 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
900 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
901 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
902 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
903 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
904 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
905 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
906 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
907 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
911 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
912 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 // multiplayer missions
926 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
927 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
928 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
932 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
933 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
938 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
939 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
968 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
969 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
980 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
981 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
982 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
983 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
988 // Internal function prototypes
989 void game_maybe_draw_mouse(float frametime);
990 void init_animating_pointer();
991 void load_animating_pointer(char *filename, int dx, int dy);
992 void unload_animating_pointer();
993 void game_do_training_checks();
994 void game_shutdown(void);
995 void game_show_event_debug(float frametime);
996 void game_event_debug_init();
998 void demo_upsell_show_screens();
999 void game_start_subspace_ambient_sound();
1000 void game_stop_subspace_ambient_sound();
1001 void verify_ships_tbl();
1002 void verify_weapons_tbl();
1003 void display_title_screen();
1005 // loading background filenames
1006 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1007 "LoadingBG", // GR_640
1008 "2_LoadingBG" // GR_1024
1012 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1013 "Loading.ani", // GR_640
1014 "2_Loading.ani" // GR_1024
1017 #if defined(FS2_DEMO)
1018 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1022 #elif defined(OEM_BUILD)
1023 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1030 char Game_CDROM_dir[MAX_PATH_LEN];
1033 // How much RAM is on this machine. Set in WinMain
1034 uint Freespace_total_ram = 0;
1037 float Game_flash_red = 0.0f;
1038 float Game_flash_green = 0.0f;
1039 float Game_flash_blue = 0.0f;
1040 float Sun_spot = 0.0f;
1041 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1043 // game shudder stuff (in ms)
1044 int Game_shudder_time = -1;
1045 int Game_shudder_total = 0;
1046 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1049 sound_env Game_sound_env;
1050 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1051 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1053 int Game_sound_env_update_timestamp;
1055 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1058 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1060 fs_builtin_mission *game_find_builtin_mission(char *filename)
1064 // look through all existing builtin missions
1065 for(idx=0; idx<Game_builtin_mission_count; idx++){
1066 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1067 return &Game_builtin_mission_list[idx];
1075 int game_get_default_skill_level()
1077 return DEFAULT_SKILL_LEVEL;
1081 void game_flash_reset()
1083 Game_flash_red = 0.0f;
1084 Game_flash_green = 0.0f;
1085 Game_flash_blue = 0.0f;
1087 Big_expl_flash.max_flash_intensity = 0.0f;
1088 Big_expl_flash.cur_flash_intensity = 0.0f;
1089 Big_expl_flash.flash_start = 0;
1092 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1093 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1095 void game_framerate_check_init()
1097 // zero critical time
1098 Gf_critical_time = 0.0f;
1101 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1102 // if this is a glide card
1103 if(gr_screen.mode == GR_GLIDE){
1105 extern GrHwConfiguration hwconfig;
1108 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1109 Gf_critical = 15.0f;
1113 Gf_critical = 10.0f;
1118 Gf_critical = 15.0f;
1121 // d3d. only care about good cards here I guess (TNT)
1123 Gf_critical = 15.0f;
1126 // if this is a glide card
1127 if(gr_screen.mode == GR_GLIDE){
1129 extern GrHwConfiguration hwconfig;
1132 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1133 Gf_critical = 25.0f;
1137 Gf_critical = 20.0f;
1142 Gf_critical = 25.0f;
1145 // d3d. only care about good cards here I guess (TNT)
1147 Gf_critical = 25.0f;
1152 extern float Framerate;
1153 void game_framerate_check()
1157 // if the current framerate is above the critical level, add frametime
1158 if(Framerate >= Gf_critical){
1159 Gf_critical_time += flFrametime;
1162 if(!Show_framerate){
1166 // display if we're above the critical framerate
1167 if(Framerate < Gf_critical){
1168 gr_set_color_fast(&Color_bright_red);
1169 gr_string(200, y_start, "Framerate warning");
1174 // display our current pct of good frametime
1175 if(f2fl(Missiontime) >= 0.0f){
1176 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1179 gr_set_color_fast(&Color_bright_green);
1181 gr_set_color_fast(&Color_bright_red);
1184 gr_printf(200, y_start, "%d%%", (int)pct);
1191 // Adds a flash effect. These can be positive or negative.
1192 // The range will get capped at around -1 to 1, so stick
1193 // with a range like that.
1194 void game_flash( float r, float g, float b )
1196 Game_flash_red += r;
1197 Game_flash_green += g;
1198 Game_flash_blue += b;
1200 if ( Game_flash_red < -1.0f ) {
1201 Game_flash_red = -1.0f;
1202 } else if ( Game_flash_red > 1.0f ) {
1203 Game_flash_red = 1.0f;
1206 if ( Game_flash_green < -1.0f ) {
1207 Game_flash_green = -1.0f;
1208 } else if ( Game_flash_green > 1.0f ) {
1209 Game_flash_green = 1.0f;
1212 if ( Game_flash_blue < -1.0f ) {
1213 Game_flash_blue = -1.0f;
1214 } else if ( Game_flash_blue > 1.0f ) {
1215 Game_flash_blue = 1.0f;
1220 // Adds a flash for Big Ship explosions
1221 // cap range from 0 to 1
1222 void big_explosion_flash(float flash)
1224 Big_expl_flash.flash_start = timestamp(1);
1228 } else if (flash < 0.0f) {
1232 Big_expl_flash.max_flash_intensity = flash;
1233 Big_expl_flash.cur_flash_intensity = 0.0f;
1236 // Amount to diminish palette towards normal, per second.
1237 #define DIMINISH_RATE 0.75f
1238 #define SUN_DIMINISH_RATE 6.00f
1242 float sn_glare_scale = 1.7f;
1245 dc_get_arg(ARG_FLOAT);
1246 sn_glare_scale = Dc_arg_float;
1249 float Supernova_last_glare = 0.0f;
1250 void game_sunspot_process(float frametime)
1254 float Sun_spot_goal = 0.0f;
1257 sn_stage = supernova_active();
1259 // sunspot differently based on supernova stage
1261 // approaching. player still in control
1264 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1267 light_get_global_dir(&light_dir, 0);
1269 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1272 // scale it some more
1273 dot = dot * (0.5f + (pct * 0.5f));
1276 Sun_spot_goal += (dot * sn_glare_scale);
1279 // draw the sun glow
1280 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1281 // draw the glow for this sun
1282 stars_draw_sun_glow(0);
1285 Supernova_last_glare = Sun_spot_goal;
1288 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1291 Sun_spot_goal = 0.9f;
1292 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1294 if(Sun_spot_goal > 1.0f){
1295 Sun_spot_goal = 1.0f;
1298 Sun_spot_goal *= sn_glare_scale;
1299 Supernova_last_glare = Sun_spot_goal;
1302 // fade to white. display dead popup
1305 Supernova_last_glare += (2.0f * flFrametime);
1306 if(Supernova_last_glare > 2.0f){
1307 Supernova_last_glare = 2.0f;
1310 Sun_spot_goal = Supernova_last_glare;
1317 // check sunspots for all suns
1318 n_lights = light_get_global_count();
1321 for(idx=0; idx<n_lights; idx++){
1322 //(vector *eye_pos, matrix *eye_orient)
1323 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1326 light_get_global_dir(&light_dir, idx);
1328 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1330 Sun_spot_goal += (float)pow(dot,85.0f);
1332 // draw the glow for this sun
1333 stars_draw_sun_glow(idx);
1335 Sun_spot_goal = 0.0f;
1341 Sun_spot_goal = 0.0f;
1345 float dec_amount = frametime*SUN_DIMINISH_RATE;
1347 if ( Sun_spot < Sun_spot_goal ) {
1348 Sun_spot += dec_amount;
1349 if ( Sun_spot > Sun_spot_goal ) {
1350 Sun_spot = Sun_spot_goal;
1352 } else if ( Sun_spot > Sun_spot_goal ) {
1353 Sun_spot -= dec_amount;
1354 if ( Sun_spot < Sun_spot_goal ) {
1355 Sun_spot = Sun_spot_goal;
1361 // Call once a frame to diminish the
1362 // flash effect to 0.
1363 void game_flash_diminish(float frametime)
1365 float dec_amount = frametime*DIMINISH_RATE;
1367 if ( Game_flash_red > 0.0f ) {
1368 Game_flash_red -= dec_amount;
1369 if ( Game_flash_red < 0.0f )
1370 Game_flash_red = 0.0f;
1372 Game_flash_red += dec_amount;
1373 if ( Game_flash_red > 0.0f )
1374 Game_flash_red = 0.0f;
1377 if ( Game_flash_green > 0.0f ) {
1378 Game_flash_green -= dec_amount;
1379 if ( Game_flash_green < 0.0f )
1380 Game_flash_green = 0.0f;
1382 Game_flash_green += dec_amount;
1383 if ( Game_flash_green > 0.0f )
1384 Game_flash_green = 0.0f;
1387 if ( Game_flash_blue > 0.0f ) {
1388 Game_flash_blue -= dec_amount;
1389 if ( Game_flash_blue < 0.0f )
1390 Game_flash_blue = 0.0f;
1392 Game_flash_blue += dec_amount;
1393 if ( Game_flash_blue > 0.0f )
1394 Game_flash_blue = 0.0f;
1397 // update big_explosion_cur_flash
1398 #define TIME_UP 1500
1399 #define TIME_DOWN 2500
1400 int duration = TIME_UP + TIME_DOWN;
1401 int time = timestamp_until(Big_expl_flash.flash_start);
1402 if (time > -duration) {
1404 if (time < TIME_UP) {
1405 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1408 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1412 if ( Use_palette_flash ) {
1414 // static int or=0, og=0, ob=0;
1416 // Change the 200 to change the color range of colors.
1417 r = fl2i( Game_flash_red*128.0f );
1418 g = fl2i( Game_flash_green*128.0f );
1419 b = fl2i( Game_flash_blue*128.0f );
1421 if ( Sun_spot > 0.0f ) {
1422 r += fl2i(Sun_spot*128.0f);
1423 g += fl2i(Sun_spot*128.0f);
1424 b += fl2i(Sun_spot*128.0f);
1427 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1428 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1429 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1430 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1433 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1434 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1435 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1437 if ( (r!=0) || (g!=0) || (b!=0) ) {
1438 gr_flash( r, g, b );
1440 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1451 void game_level_close()
1453 // De-Initialize the game subsystems
1454 message_mission_shutdown();
1455 event_music_level_close();
1456 game_stop_looped_sounds();
1458 obj_snd_level_close(); // uninit object-linked persistant sounds
1459 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1460 anim_level_close(); // stop and clean up any anim instances
1461 shockwave_level_close();
1462 fireball_level_close();
1464 mission_event_shutdown();
1465 asteroid_level_close();
1466 model_cache_reset(); // Reset/free all the model caching stuff
1467 flak_level_close(); // unload flak stuff
1468 neb2_level_close(); // shutdown gaseous nebula stuff
1471 mflash_level_close();
1473 audiostream_unpause_all();
1478 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1479 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1480 void game_level_init(int seed)
1482 // seed the random number generator
1484 // if no seed was passed, seed the generator either from the time value, or from the
1485 // netgame security flags -- ensures that all players in multiplayer game will have the
1486 // same randon number sequence (with static rand functions)
1487 if ( Game_mode & GM_NORMAL ) {
1488 Game_level_seed = time(NULL);
1490 Game_level_seed = Netgame.security;
1493 // mwa 9/17/98 -- maybe this assert isn't needed????
1494 Assert( !(Game_mode & GM_MULTIPLAYER) );
1495 Game_level_seed = seed;
1497 srand( Game_level_seed );
1499 // semirand function needs to get re-initted every time in multiplayer
1500 if ( Game_mode & GM_MULTIPLAYER ){
1506 Key_normal_game = (Game_mode & GM_NORMAL);
1509 Game_shudder_time = -1;
1511 // Initialize the game subsystems
1512 // timestamp_reset(); // Must be inited before everything else
1514 game_reset_time(); // resets time, and resets saved time too
1516 obj_init(); // Must be inited before the other systems
1517 model_free_all(); // Free all existing models
1518 mission_brief_common_init(); // Free all existing briefing/debriefing text
1519 weapon_level_init();
1520 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1522 player_level_init();
1523 shipfx_flash_init(); // Init the ship gun flash system.
1524 game_flash_reset(); // Reset the flash effect
1525 particle_init(); // Reset the particle system
1529 shield_hit_init(); // Initialize system for showing shield hits
1530 radar_mission_init();
1531 mission_init_goals();
1534 obj_snd_level_init(); // init object-linked persistant sounds
1536 shockwave_level_init();
1537 afterburner_level_init();
1538 scoring_level_init( &Player->stats );
1540 asteroid_level_init();
1541 control_config_clear_used_status();
1542 collide_ship_ship_sounds_init();
1544 Pre_player_entry = 1; // Means the player has not yet entered.
1545 Entry_delay_time = 0; // Could get overwritten in mission read.
1546 fireball_preload(); // page in warphole bitmaps
1548 flak_level_init(); // initialize flak - bitmaps, etc
1549 ct_level_init(); // initialize ships contrails, etc
1550 awacs_level_init(); // initialize AWACS
1551 beam_level_init(); // initialize beam weapons
1552 mflash_level_init();
1554 supernova_level_init();
1556 // multiplayer dogfight hack
1559 shipfx_engine_wash_level_init();
1563 Last_view_target = NULL;
1568 // campaign wasn't ended
1569 Campaign_ended_in_mission = 0;
1572 // called when a mission is over -- does server specific stuff.
1573 void freespace_stop_mission()
1576 Game_mode &= ~GM_IN_MISSION;
1579 // called at frame interval to process networking stuff
1580 void game_do_networking()
1582 Assert( Net_player != NULL );
1583 if (!(Game_mode & GM_MULTIPLAYER)){
1587 // see if this player should be reading/writing data. Bit is set when at join
1588 // screen onward until quits back to main menu.
1589 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1593 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1596 multi_pause_do_frame();
1601 // Loads the best palette for this level, based
1602 // on nebula color and hud color. You could just call palette_load_table with
1603 // the appropriate filename, but who wants to do that.
1604 void game_load_palette()
1606 char palette_filename[1024];
1608 // We only use 3 hud colors right now
1609 // Assert( HUD_config.color >= 0 );
1610 // Assert( HUD_config.color <= 2 );
1612 Assert( Mission_palette >= 0 );
1613 Assert( Mission_palette <= 98 );
1615 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1616 strcpy( palette_filename, NOX("gamepalette-subspace") );
1618 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1621 mprintf(( "Loading palette %s\n", palette_filename ));
1623 // palette_load_table(palette_filename);
1626 void game_post_level_init()
1628 // Stuff which gets called after mission is loaded. Because player isn't created until
1629 // after mission loads, some things must get initted after the level loads
1631 model_level_post_init();
1634 hud_setup_escort_list();
1635 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1641 game_event_debug_init();
1644 training_mission_init();
1645 asteroid_create_all();
1647 game_framerate_check_init();
1651 // An estimate as to how high the count passed to game_loading_callback will go.
1652 // This is just a guess, it seems to always be about the same. The count is
1653 // proportional to the code being executed, not the time, so this works good
1654 // for a bar, assuming the code does about the same thing each time you
1655 // load a level. You can find this value by looking at the return value
1656 // of game_busy_callback(NULL), which I conveniently print out to the
1657 // debug output window with the '=== ENDING LOAD ==' stuff.
1658 //#define COUNT_ESTIMATE 3706
1659 #define COUNT_ESTIMATE 1111
1661 int Game_loading_callback_inited = 0;
1663 int Game_loading_background = -1;
1664 anim * Game_loading_ani = NULL;
1665 anim_instance *Game_loading_ani_instance;
1666 int Game_loading_frame=-1;
1668 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1677 // This gets called 10x per second and count is the number of times
1678 // game_busy() has been called since the current callback function
1680 void game_loading_callback(int count)
1682 game_do_networking();
1684 Assert( Game_loading_callback_inited==1 );
1685 Assert( Game_loading_ani != NULL );
1687 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1688 if ( framenum > Game_loading_ani->total_frames-1 ) {
1689 framenum = Game_loading_ani->total_frames-1;
1690 } else if ( framenum < 0 ) {
1695 while ( Game_loading_frame < framenum ) {
1696 Game_loading_frame++;
1697 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1701 if ( cbitmap > -1 ) {
1702 if ( Game_loading_background > -1 ) {
1703 gr_set_bitmap( Game_loading_background );
1707 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1708 gr_set_bitmap( cbitmap );
1709 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1711 bm_release(cbitmap);
1717 void game_loading_callback_init()
1719 Assert( Game_loading_callback_inited==0 );
1721 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1722 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1725 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1726 Assert( Game_loading_ani != NULL );
1727 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1728 Assert( Game_loading_ani_instance != NULL );
1729 Game_loading_frame = -1;
1731 Game_loading_callback_inited = 1;
1733 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1738 void game_loading_callback_close()
1740 Assert( Game_loading_callback_inited==1 );
1742 // Make sure bar shows all the way over.
1743 game_loading_callback(COUNT_ESTIMATE);
1745 int real_count = game_busy_callback( NULL );
1748 Game_loading_callback_inited = 0;
1751 mprintf(( "=================== ENDING LOAD ================\n" ));
1752 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1753 mprintf(( "================================================\n" ));
1755 // to remove warnings in release build
1759 free_anim_instance(Game_loading_ani_instance);
1760 Game_loading_ani_instance = NULL;
1761 anim_free(Game_loading_ani);
1762 Game_loading_ani = NULL;
1764 bm_release( Game_loading_background );
1765 common_free_interface_palette(); // restore game palette
1766 Game_loading_background = -1;
1768 gr_set_font( FONT1 );
1771 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1773 void game_maybe_update_sound_environment()
1775 // do nothing for now
1778 // Assign the sound environment for the game, based on the current mission
1780 void game_assign_sound_environment()
1783 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1784 Game_sound_env.id = SND_ENV_DRUGGED;
1785 Game_sound_env.volume = 0.800f;
1786 Game_sound_env.damping = 1.188f;
1787 Game_sound_env.decay = 6.392f;
1789 } else if (Num_asteroids > 30) {
1790 Game_sound_env.id = SND_ENV_AUDITORIUM;
1791 Game_sound_env.volume = 0.603f;
1792 Game_sound_env.damping = 0.5f;
1793 Game_sound_env.decay = 4.279f;
1796 Game_sound_env = Game_default_sound_env;
1800 Game_sound_env = Game_default_sound_env;
1801 Game_sound_env_update_timestamp = timestamp(1);
1804 // function which gets called before actually entering the mission. It is broken down into a funciton
1805 // since it will get called in one place from a single player game and from another place for
1806 // a multiplayer game
1807 void freespace_mission_load_stuff()
1809 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1810 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1811 if(!(Game_mode & GM_STANDALONE_SERVER)){
1813 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1815 game_loading_callback_init();
1817 event_music_level_init(); // preloads the first 2 seconds for each event music track
1820 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1823 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1826 ship_assign_sound_all(); // assign engine sounds to ships
1827 game_assign_sound_environment(); // assign the sound environment for this mission
1830 // call function in missionparse.cpp to fixup player/ai stuff.
1831 mission_parse_fixup_players();
1834 // Load in all the bitmaps for this level
1839 game_loading_callback_close();
1841 // the only thing we need to call on the standalone for now.
1843 // call function in missionparse.cpp to fixup player/ai stuff.
1844 mission_parse_fixup_players();
1846 // Load in all the bitmaps for this level
1852 uint load_mission_load;
1853 uint load_post_level_init;
1854 uint load_mission_stuff;
1856 // tells the server to load the mission and initialize structures
1857 int game_start_mission()
1859 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1861 load_gl_init = time(NULL);
1863 load_gl_init = time(NULL) - load_gl_init;
1865 if (Game_mode & GM_MULTIPLAYER) {
1866 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1868 // clear multiplayer stats
1869 init_multiplayer_stats();
1872 load_mission_load = time(NULL);
1873 if (mission_load()) {
1874 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1875 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1876 gameseq_post_event(GS_EVENT_MAIN_MENU);
1878 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1883 load_mission_load = time(NULL) - load_mission_load;
1885 // If this is a red alert mission in campaign mode, bash wingman status
1886 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1887 red_alert_bash_wingman_status();
1890 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1891 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1892 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1893 // game_load_palette();
1896 load_post_level_init = time(NULL);
1897 game_post_level_init();
1898 load_post_level_init = time(NULL) - load_post_level_init;
1902 void Do_model_timings_test();
1903 Do_model_timings_test();
1907 load_mission_stuff = time(NULL);
1908 freespace_mission_load_stuff();
1909 load_mission_stuff = time(NULL) - load_mission_stuff;
1914 int Interface_framerate = 0;
1917 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1918 DCF_BOOL( show_framerate, Show_framerate )
1919 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1920 DCF_BOOL( show_target_weapons, Show_target_weapons )
1921 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1922 DCF_BOOL( sound, Sound_enabled )
1923 DCF_BOOL( zbuffer, game_zbuffer )
1924 DCF_BOOL( shield_system, New_shield_system )
1925 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1926 DCF_BOOL( player_attacking, Player_attacking_enabled )
1927 DCF_BOOL( show_waypoints, Show_waypoints )
1928 DCF_BOOL( show_area_effect, Show_area_effect )
1929 DCF_BOOL( show_net_stats, Show_net_stats )
1930 DCF_BOOL( log, Log_debug_output_to_file )
1931 DCF_BOOL( training_msg_method, Training_msg_method )
1932 DCF_BOOL( show_player_pos, Show_player_pos )
1933 DCF_BOOL(i_framerate, Interface_framerate )
1935 DCF(show_mem,"Toggles showing mem usage")
1938 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1939 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1940 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1941 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1947 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1949 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1950 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1954 DCF(show_cpu,"Toggles showing cpu usage")
1957 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1958 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1959 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1960 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1966 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1968 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1969 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1976 // AL 4-8-98: always allow players to display their framerate
1979 DCF_BOOL( show_framerate, Show_framerate )
1986 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1989 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1990 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1991 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1992 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1994 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" );
1995 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
1997 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2000 DCF(palette_flash,"Toggles palette flash effect on/off")
2003 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2004 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2005 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2006 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2008 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2009 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2012 int Use_low_mem = 0;
2014 DCF(low_mem,"Uses low memory settings regardless of RAM")
2017 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2018 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2019 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2020 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2022 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2023 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2025 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2031 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2034 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2035 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2036 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2037 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2039 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2040 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2041 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2045 int Framerate_delay = 0;
2047 float Freespace_gamma = 1.0f;
2049 DCF(gamma,"Sets Gamma factor")
2052 dc_get_arg(ARG_FLOAT|ARG_NONE);
2053 if ( Dc_arg_type & ARG_FLOAT ) {
2054 Freespace_gamma = Dc_arg_float;
2056 dc_printf( "Gamma reset to 1.0f\n" );
2057 Freespace_gamma = 1.0f;
2059 if ( Freespace_gamma < 0.1f ) {
2060 Freespace_gamma = 0.1f;
2061 } else if ( Freespace_gamma > 5.0f ) {
2062 Freespace_gamma = 5.0f;
2064 gr_set_gamma(Freespace_gamma);
2066 char tmp_gamma_string[32];
2067 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2068 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2072 dc_printf( "Usage: gamma <float>\n" );
2073 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2074 Dc_status = 0; // don't print status if help is printed. Too messy.
2078 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2087 Game_current_mission_filename[0] = 0;
2089 // seed the random number generator
2090 Game_init_seed = time(NULL);
2091 srand( Game_init_seed );
2093 Framerate_delay = 0;
2099 extern void bm_init();
2105 // Initialize the timer before the os
2113 GetCurrentDirectory(1024, whee);
2116 getcwd (whee, 1024);
2119 strcat(whee, EXE_FNAME);
2121 //Initialize the libraries
2122 s1 = timer_get_milliseconds();
2123 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2126 e1 = timer_get_milliseconds();
2128 // time a bunch of cfopens
2130 s2 = timer_get_milliseconds();
2132 for(int idx=0; idx<10000; idx++){
2133 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2138 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2140 e2 = timer_get_milliseconds();
2143 if (Is_standalone) {
2144 std_init_standalone();
2146 os_init( Osreg_class_name, Osreg_app_name );
2147 os_set_title(Osreg_title);
2150 // initialize localization module. Make sure this is down AFTER initialzing OS.
2151 // int t1 = timer_get_milliseconds();
2154 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2156 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2159 // verify that he has a valid weapons.tbl
2160 verify_weapons_tbl();
2162 // Output version numbers to registry for auto patching purposes
2163 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2164 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2165 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2167 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2168 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2169 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2172 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2176 Asteroids_enabled = 1;
2179 /////////////////////////////
2181 /////////////////////////////
2186 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2187 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2189 if (!stricmp(ptr, NOX("no sound"))) {
2190 Cmdline_freespace_no_sound = 1;
2192 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2194 } else if (!stricmp(ptr, NOX("EAX"))) {
2199 if (!Is_standalone) {
2200 snd_init(use_a3d, use_eax);
2202 /////////////////////////////
2204 /////////////////////////////
2206 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2209 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);
2211 // fire up the UpdateLauncher executable
2213 PROCESS_INFORMATION pi;
2215 memset( &si, 0, sizeof(STARTUPINFO) );
2218 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2219 NULL, // pointer to command line string
2220 NULL, // pointer to process security attributes
2221 NULL, // pointer to thread security attributes
2222 FALSE, // handle inheritance flag
2223 CREATE_DEFAULT_ERROR_MODE, // creation flags
2224 NULL, // pointer to new environment block
2225 NULL, // pointer to current directory name
2226 &si, // pointer to STARTUPINFO
2227 &pi // pointer to PROCESS_INFORMATION
2230 // If the Launcher could not be started up, let the user know
2232 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2241 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2243 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);
2251 // check for hi res pack file
2252 int has_sparky_hi = 0;
2254 // check if sparky_hi exists -- access mode 0 means does file exist
2257 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2260 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2263 // see if we've got 32 bit in the string
2264 if(strstr(ptr, "32 bit")){
2271 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2273 // always 640 for E3
2274 gr_init(GR_640, GR_GLIDE);
2276 // regular or hi-res ?
2278 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2280 if(strstr(ptr, NOX("(1024x768)"))){
2282 gr_init(GR_1024, GR_GLIDE);
2284 gr_init(GR_640, GR_GLIDE);
2287 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2289 // always 640 for E3
2291 gr_init(GR_640, GR_DIRECT3D, depth);
2293 // regular or hi-res ?
2295 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2297 if(strstr(ptr, NOX("(1024x768)"))){
2301 gr_init(GR_1024, GR_DIRECT3D, depth);
2305 gr_init(GR_640, GR_DIRECT3D, depth);
2311 if ( Use_fullscreen_at_startup && !Is_standalone) {
2312 gr_init(GR_640, GR_DIRECTDRAW);
2314 gr_init(GR_640, GR_SOFTWARE);
2317 if ( !Is_standalone ) {
2318 gr_init(GR_640, GR_DIRECTDRAW);
2320 gr_init(GR_640, GR_SOFTWARE);
2325 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2326 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2327 gr_init(GR_1024, GR_OPENGL);
2329 gr_init(GR_640, GR_OPENGL);
2333 gr_init(GR_640, GR_SOFTWARE);
2338 extern int Gr_inited;
2339 if(trying_d3d && !Gr_inited){
2341 extern char Device_init_error[512];
2342 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2351 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2352 Freespace_gamma = (float)atof(ptr);
2353 if ( Freespace_gamma == 0.0f ) {
2354 Freespace_gamma = 1.80f;
2355 } else if ( Freespace_gamma < 0.1f ) {
2356 Freespace_gamma = 0.1f;
2357 } else if ( Freespace_gamma > 5.0f ) {
2358 Freespace_gamma = 5.0f;
2360 char tmp_gamma_string[32];
2361 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2362 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2364 gr_set_gamma(Freespace_gamma);
2366 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2369 display_title_screen();
2373 // attempt to load up master tracker registry info (login and password)
2374 Multi_tracker_id = -1;
2376 // pxo login and password
2377 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2379 nprintf(("Network","Error reading in PXO login data\n"));
2380 strcpy(Multi_tracker_login,"");
2382 strcpy(Multi_tracker_login,ptr);
2384 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2386 nprintf(("Network","Error reading PXO password\n"));
2387 strcpy(Multi_tracker_passwd,"");
2389 strcpy(Multi_tracker_passwd,ptr);
2392 // pxo squad name and password
2393 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2395 nprintf(("Network","Error reading in PXO squad name\n"));
2396 strcpy(Multi_tracker_squad_name, "");
2398 strcpy(Multi_tracker_squad_name, ptr);
2401 // If less than 48MB of RAM, use low memory model.
2404 (Freespace_total_ram < 48*1024*1024) ||
2407 mprintf(( "Using normal memory settings...\n" ));
2408 bm_set_low_mem(1); // Use every other frame of bitmaps
2410 mprintf(( "Using high memory settings...\n" ));
2411 bm_set_low_mem(0); // Use all frames of bitmaps
2414 // load non-darkening pixel defs
2415 palman_load_pixels();
2417 // hud shield icon stuff
2418 hud_shield_game_init();
2420 control_config_common_init(); // sets up localization stuff in the control config
2426 gamesnd_parse_soundstbl();
2431 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2436 player_controls_init();
2439 //if(!Is_standalone){
2447 ship_init(); // read in ships.tbl
2449 mission_campaign_init(); // load in the default campaign
2451 // navmap_init(); // init the navigation map system
2452 context_help_init();
2453 techroom_intel_init(); // parse species.tbl, load intel info
2455 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2456 init_animating_pointer();
2458 mission_brief_common_init(); // Mark all the briefing structures as empty.
2459 gr_font_init(); // loads up all fonts
2461 neb2_init(); // fullneb stuff
2465 player_tips_init(); // helpful tips
2468 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2469 pilot_load_pic_list();
2470 pilot_load_squad_pic_list();
2472 load_animating_pointer(NOX("cursor"), 0, 0);
2474 // initialize alpha colors
2475 alpha_colors_init();
2478 // Game_music_paused = 0;
2485 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2486 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2488 mprintf(("cfile_init() took %d\n", e1 - s1));
2489 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2492 char transfer_text[128];
2494 float Start_time = 0.0f;
2496 float Framerate = 0.0f;
2498 float Timing_total = 0.0f;
2499 float Timing_render2 = 0.0f;
2500 float Timing_render3 = 0.0f;
2501 float Timing_flip = 0.0f;
2502 float Timing_clear = 0.0f;
2504 MONITOR(NumPolysDrawn);
2510 void game_get_framerate()
2512 char text[128] = "";
2514 if ( frame_int == -1 ) {
2516 for (i=0; i<FRAME_FILTER; i++ ) {
2517 frametimes[i] = 0.0f;
2522 frametotal -= frametimes[frame_int];
2523 frametotal += flFrametime;
2524 frametimes[frame_int] = flFrametime;
2525 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2527 if ( frametotal != 0.0 ) {
2528 if ( Framecount >= FRAME_FILTER )
2529 Framerate = FRAME_FILTER / frametotal;
2531 Framerate = Framecount / frametotal;
2532 sprintf( text, NOX("FPS: %.1f"), Framerate );
2534 sprintf( text, NOX("FPS: ?") );
2538 if (Show_framerate) {
2539 gr_set_color_fast(&HUD_color_debug);
2540 gr_string( 570, 2, text );
2544 void game_show_framerate()
2548 cur_time = f2fl(timer_get_approx_seconds());
2549 if (cur_time - Start_time > 30.0f) {
2550 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2551 Start_time += 1000.0f;
2554 //mprintf(( "%s\n", text ));
2557 if ( Debug_dump_frames )
2561 // possibly show control checking info
2562 control_check_indicate();
2564 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2565 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2566 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2567 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2570 if ( Show_cpu == 1 ) {
2575 dy = gr_get_font_height() + 1;
2577 gr_set_color_fast(&HUD_color_debug);
2581 extern int D3D_textures_in;
2582 extern int D3D_textures_in_frame;
2583 extern int Glide_textures_in;
2584 extern int Glide_textures_in_frame;
2585 extern int Glide_explosion_vram;
2586 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2588 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2590 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2594 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2596 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2598 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2600 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2602 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2607 extern int Num_pairs; // Number of object pairs that were checked.
2608 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2611 extern int Num_pairs_checked; // What percent of object pairs were checked.
2612 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2614 Num_pairs_checked = 0;
2618 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2621 if ( Timing_total > 0.01f ) {
2622 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2624 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2626 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2628 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2630 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2640 dy = gr_get_font_height() + 1;
2642 gr_set_color_fast(&HUD_color_debug);
2645 extern int TotalRam;
2646 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2651 extern int Model_ram;
2652 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2656 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2658 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2660 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2664 extern int D3D_textures_in;
2665 extern int Glide_textures_in;
2666 extern int Glide_textures_in_frame;
2667 extern int Glide_explosion_vram;
2668 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2670 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2672 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2679 if ( Show_player_pos ) {
2683 gr_printf(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.xyz.x), fl2i(Player_obj->pos.xyz.y), fl2i(Player_obj->pos.xyz.z));
2686 MONITOR_INC(NumPolys, modelstats_num_polys);
2687 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2688 MONITOR_INC(NumVerts, modelstats_num_verts );
2690 modelstats_num_polys = 0;
2691 modelstats_num_polys_drawn = 0;
2692 modelstats_num_verts = 0;
2693 modelstats_num_sortnorms = 0;
2697 void game_show_standalone_framerate()
2699 float frame_rate=30.0f;
2700 if ( frame_int == -1 ) {
2702 for (i=0; i<FRAME_FILTER; i++ ) {
2703 frametimes[i] = 0.0f;
2708 frametotal -= frametimes[frame_int];
2709 frametotal += flFrametime;
2710 frametimes[frame_int] = flFrametime;
2711 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2713 if ( frametotal != 0.0 ) {
2714 if ( Framecount >= FRAME_FILTER ){
2715 frame_rate = FRAME_FILTER / frametotal;
2717 frame_rate = Framecount / frametotal;
2720 std_set_standalone_fps(frame_rate);
2724 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2725 void game_show_time_left()
2729 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2730 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2731 // checking how much time is left
2733 if ( Mission_end_time == -1 ){
2737 diff = f2i(Mission_end_time - Missiontime);
2738 // be sure to bash to 0. diff could be negative on frame that we quit mission
2743 hud_set_default_color();
2744 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2747 //========================================================================================
2748 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2749 //========================================================================================
2753 DCF(ai_pause,"Pauses ai")
2756 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2757 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2758 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2759 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2762 obj_init_all_ships_physics();
2765 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2766 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2769 DCF(single_step,"Single steps the game")
2772 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2773 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2774 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2775 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2777 last_single_step = 0; // Make so single step waits a frame before stepping
2780 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2781 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2784 DCF_BOOL(physics_pause, physics_paused)
2785 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2786 DCF_BOOL(ai_firing, Ai_firing_enabled )
2788 // Create some simple aliases to these commands...
2789 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2790 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2791 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2792 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2793 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2796 //========================================================================================
2797 //========================================================================================
2800 void game_training_pause_do()
2804 key = game_check_key();
2806 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2813 void game_increase_skill_level()
2816 if (Game_skill_level >= NUM_SKILL_LEVELS){
2817 Game_skill_level = 0;
2821 int Player_died_time;
2823 int View_percent = 100;
2826 DCF(view, "Sets the percent of the 3d view to render.")
2829 dc_get_arg(ARG_INT);
2830 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2831 View_percent = Dc_arg_int;
2833 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2839 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2843 dc_printf("View is set to %d%%\n", View_percent );
2848 // Set the clip region for the 3d rendering window
2849 void game_set_view_clip()
2851 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2852 // Set the clip region for the letterbox "dead view"
2853 int yborder = gr_screen.max_h/4;
2855 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2856 // J.S. I've changed my ways!! See the new "no constants" code!!!
2857 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2859 // Set the clip region for normal view
2860 if ( View_percent >= 100 ) {
2863 int xborder, yborder;
2865 if ( View_percent < 5 ) {
2869 float fp = i2fl(View_percent)/100.0f;
2870 int fi = fl2i(fl_sqrt(fp)*100.0f);
2871 if ( fi > 100 ) fi=100;
2873 xborder = ( gr_screen.max_w*(100-fi) )/200;
2874 yborder = ( gr_screen.max_h*(100-fi) )/200;
2876 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2882 void show_debug_stuff()
2885 int laser_count = 0, missile_count = 0;
2887 for (i=0; i<MAX_OBJECTS; i++) {
2888 if (Objects[i].type == OBJ_WEAPON){
2889 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2891 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2897 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2900 extern int Tool_enabled;
2905 int tst_bitmap = -1;
2907 float tst_offset, tst_offset_total;
2910 void game_tst_frame_pre()
2918 g3_rotate_vertex(&v, &tst_pos);
2919 g3_project_vertex(&v);
2922 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2926 // big ship? always tst
2928 // within 3000 meters
2929 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2933 // within 300 meters
2934 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2941 void game_tst_frame()
2951 tst_time = time(NULL);
2953 // load the tst bitmap
2954 switch((int)frand_range(0.0f, 3.0)){
2956 tst_bitmap = bm_load("ig_jim");
2958 mprintf(("TST 0\n"));
2962 tst_bitmap = bm_load("ig_kan");
2964 mprintf(("TST 1\n"));
2968 tst_bitmap = bm_load("ig_jim");
2970 mprintf(("TST 2\n"));
2974 tst_bitmap = bm_load("ig_kan");
2976 mprintf(("TST 3\n"));
2985 // get the tst bitmap dimensions
2987 bm_get_info(tst_bitmap, &w, &h);
2990 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2992 snd_play(&Snds[SND_VASUDAN_BUP]);
2994 // tst x and direction
2998 tst_offset_total = (float)w;
2999 tst_offset = (float)w;
3001 tst_x = (float)gr_screen.max_w;
3002 tst_offset_total = (float)-w;
3003 tst_offset = (float)w;
3011 float diff = (tst_offset_total / 0.5f) * flFrametime;
3017 tst_offset -= fl_abs(diff);
3018 } else if(tst_mode == 2){
3021 tst_offset -= fl_abs(diff);
3025 gr_set_bitmap(tst_bitmap);
3026 gr_bitmap((int)tst_x, (int)tst_y);
3029 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3033 // if we passed the switch point
3034 if(tst_offset <= 0.0f){
3039 tst_stamp = timestamp(1000);
3040 tst_offset = fl_abs(tst_offset_total);
3051 void game_tst_mark(object *objp, ship *shipp)
3060 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3063 sip = &Ship_info[shipp->ship_info_index];
3070 tst_pos = objp->pos;
3071 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3077 extern void render_shields();
3079 void player_repair_frame(float frametime)
3081 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3083 for(idx=0;idx<MAX_PLAYERS;idx++){
3086 np = &Net_players[idx];
3088 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)){
3090 // don't rearm/repair if the player is dead or dying/departing
3091 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3092 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3097 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3098 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3104 #define NUM_FRAMES_TEST 300
3105 #define NUM_MIXED_SOUNDS 16
3106 void do_timing_test(float flFrametime)
3108 static int framecount = 0;
3109 static int test_running = 0;
3110 static float test_time = 0.0f;
3112 static int snds[NUM_MIXED_SOUNDS];
3115 if ( test_running ) {
3117 test_time += flFrametime;
3118 if ( framecount >= NUM_FRAMES_TEST ) {
3120 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3121 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3126 if ( Test_begin == 1 ) {
3132 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3135 // start looping digital sounds
3136 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3137 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3144 DCF(dcf_fov, "Change the field of view")
3147 dc_get_arg(ARG_FLOAT|ARG_NONE);
3148 if ( Dc_arg_type & ARG_NONE ) {
3149 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3150 dc_printf( "Zoom factor reset\n" );
3152 if ( Dc_arg_type & ARG_FLOAT ) {
3153 if (Dc_arg_float < 0.25f) {
3154 Viewer_zoom = 0.25f;
3155 dc_printf("Zoom factor pinned at 0.25.\n");
3156 } else if (Dc_arg_float > 1.25f) {
3157 Viewer_zoom = 1.25f;
3158 dc_printf("Zoom factor pinned at 1.25.\n");
3160 Viewer_zoom = Dc_arg_float;
3166 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3169 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3173 DCF(framerate_cap, "Sets the framerate cap")
3176 dc_get_arg(ARG_INT);
3177 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3178 Framerate_cap = Dc_arg_int;
3180 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3186 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3187 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3188 dc_printf("[n] must be from 1 to 120.\n");
3192 if ( Framerate_cap )
3193 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3195 dc_printf("There is no framerate cap currently active.\n");
3199 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3200 int Show_viewing_from_self = 0;
3202 void say_view_target()
3204 object *view_target;
3206 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3207 view_target = &Objects[Player_ai->target_objnum];
3209 view_target = Player_obj;
3211 if (Game_mode & GM_DEAD) {
3212 if (Player_ai->target_objnum != -1)
3213 view_target = &Objects[Player_ai->target_objnum];
3216 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3217 if (view_target != Player_obj){
3219 char *view_target_name = NULL;
3220 switch(Objects[Player_ai->target_objnum].type) {
3222 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3225 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3226 Viewer_mode &= ~VM_OTHER_SHIP;
3228 case OBJ_JUMP_NODE: {
3229 char jump_node_name[128];
3230 strcpy(jump_node_name, XSTR( "jump node", 184));
3231 view_target_name = jump_node_name;
3232 Viewer_mode &= ~VM_OTHER_SHIP;
3241 if ( view_target_name ) {
3242 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3243 Show_viewing_from_self = 1;
3246 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3247 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3248 Show_viewing_from_self = 1;
3250 if (Show_viewing_from_self)
3251 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3256 Last_view_target = view_target;
3260 float Game_hit_x = 0.0f;
3261 float Game_hit_y = 0.0f;
3263 // Reset at the beginning of each frame
3264 void game_whack_reset()
3270 // Apply a 2d whack to the player
3271 void game_whack_apply( float x, float y )
3273 // Do some force feedback
3274 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3280 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3283 // call to apply a "shudder"
3284 void game_shudder_apply(int time, float intensity)
3286 Game_shudder_time = timestamp(time);
3287 Game_shudder_total = time;
3288 Game_shudder_intensity = intensity;
3291 #define FF_SCALE 10000
3292 void apply_hud_shake(matrix *eye_orient)
3294 if (Viewer_obj == Player_obj) {
3295 physics_info *pi = &Player_obj->phys_info;
3303 // Make eye shake due to afterburner
3304 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3307 dtime = timestamp_until(pi->afterburner_decay);
3311 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3312 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3315 // Make eye shake due to engine wash
3317 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3320 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3321 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3323 // get the intensity
3324 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3328 vm_vec_rand_vec_quick(&rand_vec);
3331 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3335 // make hud shake due to shuddering
3336 if(Game_shudder_time != -1){
3337 // if the timestamp has elapsed
3338 if(timestamp_elapsed(Game_shudder_time)){
3339 Game_shudder_time = -1;
3341 // otherwise apply some shudder
3345 dtime = timestamp_until(Game_shudder_time);
3349 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));
3350 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));
3355 vm_angles_2_matrix(&tm, &tangles);
3356 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3357 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3358 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3359 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3364 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3366 // Player's velocity just before he blew up. Used to keep camera target moving.
3367 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3369 // Set eye_pos and eye_orient based on view mode.
3370 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3374 static int last_Viewer_mode = 0;
3375 static int last_Game_mode = 0;
3376 static int last_Viewer_objnum = -1;
3378 // This code is supposed to detect camera "cuts"... like going between
3381 // determine if we need to regenerate the nebula
3382 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3383 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3384 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3385 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3386 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3387 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3388 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3389 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3390 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3393 // regenerate the nebula
3397 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3398 //mprintf(( "************** Camera cut! ************\n" ));
3399 last_Viewer_mode = Viewer_mode;
3400 last_Game_mode = Game_mode;
3402 // Camera moved. Tell stars & debris to not do blurring.
3408 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3409 player_display_packlock_view();
3412 game_set_view_clip();
3414 if (Game_mode & GM_DEAD) {
3415 vector vec_to_deader, view_pos;
3418 Viewer_mode |= VM_DEAD_VIEW;
3420 if (Player_ai->target_objnum != -1) {
3421 int view_from_player = 1;
3423 if (Viewer_mode & VM_OTHER_SHIP) {
3424 // View from target.
3425 Viewer_obj = &Objects[Player_ai->target_objnum];
3427 last_Viewer_objnum = Player_ai->target_objnum;
3429 if ( Viewer_obj->type == OBJ_SHIP ) {
3430 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3431 view_from_player = 0;
3434 last_Viewer_objnum = -1;
3437 if ( view_from_player ) {
3438 // View target from player ship.
3440 *eye_pos = Player_obj->pos;
3441 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3442 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3445 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3447 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3448 dist += flFrametime * 16.0f;
3450 vm_vec_scale(&vec_to_deader, -dist);
3451 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3453 view_pos = Player_obj->pos;
3455 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3456 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3457 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3458 Dead_player_last_vel = Player_obj->phys_info.vel;
3459 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.xyz.x, Player_obj->phys_info.vel.xyz.y, Player_obj->phys_info.vel.xyz.z));
3460 } else if (Player_ai->target_objnum != -1) {
3461 view_pos = Objects[Player_ai->target_objnum].pos;
3463 // Make camera follow explosion, but gradually slow down.
3464 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3465 view_pos = Player_obj->pos;
3466 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3467 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3470 *eye_pos = Dead_camera_pos;
3472 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3474 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3479 // if supernova shockwave
3480 if(supernova_camera_cut()){
3484 // call it dead view
3485 Viewer_mode |= VM_DEAD_VIEW;
3487 // set eye pos and orient
3488 supernova_set_view(eye_pos, eye_orient);
3490 // If already blown up, these other modes can override.
3491 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3492 Viewer_mode &= ~VM_DEAD_VIEW;
3494 Viewer_obj = Player_obj;
3496 if (Viewer_mode & VM_OTHER_SHIP) {
3497 if (Player_ai->target_objnum != -1){
3498 Viewer_obj = &Objects[Player_ai->target_objnum];
3499 last_Viewer_objnum = Player_ai->target_objnum;
3501 Viewer_mode &= ~VM_OTHER_SHIP;
3502 last_Viewer_objnum = -1;
3505 last_Viewer_objnum = -1;
3508 if (Viewer_mode & VM_EXTERNAL) {
3511 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3512 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3514 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3516 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3517 vm_vec_normalize(&eye_dir);
3518 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3521 // Modify the orientation based on head orientation.
3522 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3524 } else if ( Viewer_mode & VM_CHASE ) {
3527 if ( Viewer_obj->phys_info.speed < 0.1 )
3528 move_dir = Viewer_obj->orient.v.fvec;
3530 move_dir = Viewer_obj->phys_info.vel;
3531 vm_vec_normalize(&move_dir);
3534 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3535 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3536 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3537 vm_vec_normalize(&eye_dir);
3539 // JAS: I added the following code because if you slew up using
3540 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3541 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3542 // call because the up and the forward vector are the same. I fixed
3543 // it by adding in a fraction of the right vector all the time to the
3545 vector tmp_up = Viewer_obj->orient.v.uvec;
3546 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3548 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3551 // Modify the orientation based on head orientation.
3552 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3553 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3554 *eye_pos = Camera_pos;
3556 ship * shipp = &Ships[Player_obj->instance];
3558 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3559 vm_vec_normalize(&eye_dir);
3560 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3563 // get an eye position based upon the correct type of object
3564 switch(Viewer_obj->type){
3566 // make a call to get the eye point for the player object
3567 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3570 // make a call to get the eye point for the player object
3571 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3577 #ifdef JOHNS_DEBUG_CODE
3578 john_debug_stuff(&eye_pos, &eye_orient);
3584 apply_hud_shake(eye_orient);
3586 // setup neb2 rendering
3587 neb2_render_setup(eye_pos, eye_orient);
3591 extern void ai_debug_render_stuff();
3594 int Game_subspace_effect = 0;
3595 DCF_BOOL( subspace, Game_subspace_effect );
3597 // Does everything needed to render a frame
3598 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3602 g3_start_frame(game_zbuffer);
3603 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3605 // maybe offset the HUD (jitter stuff)
3606 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3607 HUD_set_offsets(Viewer_obj, !dont_offset);
3609 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3610 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3611 // must be done before ships are rendered
3612 if ( MULTIPLAYER_CLIENT ) {
3613 shield_point_multi_setup();
3616 if ( Game_subspace_effect ) {
3617 stars_draw(0,0,0,1);
3619 stars_draw(1,1,1,0);
3622 obj_render_all(obj_render);
3623 beam_render_all(); // render all beam weapons
3624 particle_render_all(); // render particles after everything else.
3625 trail_render_all(); // render missilie trails after everything else.
3626 mflash_render_all(); // render all muzzle flashes
3628 // Why do we not show the shield effect in these modes? Seems ok.
3629 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3633 // render nebula lightning
3636 // render local player nebula
3637 neb2_render_player();
3640 ai_debug_render_stuff();
3643 #ifndef RELEASE_REAL
3644 // game_framerate_check();
3648 extern void snd_spew_debug_info();
3649 snd_spew_debug_info();
3652 //================ END OF 3D RENDERING STUFF ====================
3656 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3657 hud_maybe_clear_head_area();
3658 anim_render_all(0, flFrametime);
3661 extern int Multi_display_netinfo;
3662 if(Multi_display_netinfo){
3663 extern void multi_display_netinfo();
3664 multi_display_netinfo();
3667 game_tst_frame_pre();
3670 do_timing_test(flFrametime);
3674 extern int OO_update_index;
3675 multi_rate_display(OO_update_index, 375, 0);
3680 extern void oo_display();
3687 //#define JOHNS_DEBUG_CODE 1
3689 #ifdef JOHNS_DEBUG_CODE
3690 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3692 //if ( keyd_pressed[KEY_LSHIFT] )
3694 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3696 model_subsystem *turret = tsys->system_info;
3698 if (turret->type == SUBSYSTEM_TURRET ) {
3699 vector v.fvec, v.uvec;
3700 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3702 ship_model_start(tobj);
3704 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3705 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3706 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3708 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3710 ship_model_stop(tobj);
3720 // following function for dumping frames for purposes of building trailers.
3723 // function to toggle state of dumping every frame into PCX when playing the game
3724 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3728 if ( Debug_dump_frames == 0 ) {
3730 Debug_dump_frames = 15;
3731 Debug_dump_trigger = 0;
3732 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3733 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3736 Debug_dump_frames = 0;
3737 Debug_dump_trigger = 0;
3738 gr_dump_frame_stop();
3739 dc_printf( "Frame dumping is now OFF\n" );
3745 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3749 if ( Debug_dump_frames == 0 ) {
3751 Debug_dump_frames = 15;
3752 Debug_dump_trigger = 1;
3753 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3754 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3757 Debug_dump_frames = 0;
3758 Debug_dump_trigger = 0;
3759 gr_dump_frame_stop();
3760 dc_printf( "Frame dumping is now OFF\n" );
3766 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3770 if ( Debug_dump_frames == 0 ) {
3772 Debug_dump_frames = 30;
3773 Debug_dump_trigger = 0;
3774 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3775 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3778 Debug_dump_frames = 0;
3779 Debug_dump_trigger = 0;
3780 gr_dump_frame_stop();
3781 dc_printf( "Frame dumping is now OFF\n" );
3787 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3791 if ( Debug_dump_frames == 0 ) {
3793 Debug_dump_frames = 30;
3794 Debug_dump_trigger = 1;
3795 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3796 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3799 Debug_dump_frames = 0;
3800 Debug_dump_trigger = 0;
3801 gr_dump_frame_stop();
3802 dc_printf( "Triggered frame dumping is now OFF\n" );
3808 void game_maybe_dump_frame()
3810 if ( !Debug_dump_frames ){
3814 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3821 Debug_dump_frame_num++;
3827 extern int Player_dead_state;
3829 // Flip the page and time how long it took.
3830 void game_flip_page_and_time_it()
3834 t1 = timer_get_fixed_seconds();
3836 t2 = timer_get_fixed_seconds();
3838 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3839 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3842 void game_simulation_frame()
3844 // blow ships up in multiplayer dogfight
3845 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){
3846 // blow up all non-player ships
3847 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3850 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3852 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)){
3853 moveup = GET_NEXT(moveup);
3856 shipp = &Ships[Objects[moveup->objnum].instance];
3857 sip = &Ship_info[shipp->ship_info_index];
3859 // only blow up small ships
3860 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3861 // function to simply explode a ship where it is currently at
3862 ship_self_destruct( &Objects[moveup->objnum] );
3865 moveup = GET_NEXT(moveup);
3871 // process AWACS stuff - do this first thing
3874 // single player, set Player hits_this_frame to 0
3875 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3876 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3877 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3881 supernova_process();
3882 if(supernova_active() >= 5){
3886 // fire targeting lasers now so that
3887 // 1 - created this frame
3888 // 2 - collide this frame
3889 // 3 - render this frame
3890 // 4 - ignored and deleted next frame
3891 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3893 ship_process_targeting_lasers();
3895 // do this here so that it works for multiplayer
3897 // get viewer direction
3898 int viewer_direction = PHYSICS_VIEWER_REAR;
3900 if(Viewer_mode == 0){
3901 viewer_direction = PHYSICS_VIEWER_FRONT;
3903 if(Viewer_mode & VM_PADLOCK_UP){
3904 viewer_direction = PHYSICS_VIEWER_UP;
3906 else if(Viewer_mode & VM_PADLOCK_REAR){
3907 viewer_direction = PHYSICS_VIEWER_REAR;
3909 else if(Viewer_mode & VM_PADLOCK_LEFT){
3910 viewer_direction = PHYSICS_VIEWER_LEFT;
3912 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3913 viewer_direction = PHYSICS_VIEWER_RIGHT;
3916 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3918 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3921 #define VM_PADLOCK_UP (1 << 7)
3922 #define VM_PADLOCK_REAR (1 << 8)
3923 #define VM_PADLOCK_LEFT (1 << 9)
3924 #define VM_PADLOCK_RIGHT (1 << 10)
3926 // evaluate mission departures and arrivals before we process all objects.
3927 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3929 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3930 // ships/wing packets.
3931 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3932 mission_parse_eval_stuff();
3935 // if we're an observer, move ourselves seperately from the standard physics
3936 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3937 obj_observer_move(flFrametime);
3940 // move all the objects now
3941 obj_move_all(flFrametime);
3943 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3944 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3945 // ship_check_cargo_all();
3946 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3947 mission_eval_goals();
3951 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3952 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3953 training_check_objectives();
3956 // do all interpolation now
3957 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3958 // client side processing of warping in effect stages
3959 multi_do_client_warp(flFrametime);
3961 // client side movement of an observer
3962 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3963 obj_observer_move(flFrametime);
3966 // move all objects - does interpolation now as well
3967 obj_move_all(flFrametime);
3970 // only process the message queue when the player is "in" the game
3971 if ( !Pre_player_entry ){
3972 message_queue_process(); // process any messages send to the player
3975 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3976 message_maybe_distort(); // maybe distort incoming message if comms damaged
3977 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3978 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3979 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3982 if(!(Game_mode & GM_STANDALONE_SERVER)){
3983 // process some stuff every frame (before frame is rendered)
3984 emp_process_local();
3986 hud_update_frame(); // update hud systems
3988 if (!physics_paused) {
3989 // Move particle system
3990 particle_move_all(flFrametime);
3992 // Move missile trails
3993 trail_move_all(flFrametime);
3995 // process muzzle flashes
3996 mflash_process_all();
3998 // Flash the gun flashes
3999 shipfx_flash_do_frame(flFrametime);
4001 shockwave_move_all(flFrametime); // update all the shockwaves
4004 // subspace missile strikes
4007 obj_snd_do_frame(); // update the object-linked persistant sounds
4008 game_maybe_update_sound_environment();
4009 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4011 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4013 if ( Game_subspace_effect ) {
4014 game_start_subspace_ambient_sound();
4020 // Maybe render and process the dead-popup
4021 void game_maybe_do_dead_popup(float frametime)
4023 if ( popupdead_is_active() ) {
4025 int choice = popupdead_do_frame(frametime);
4027 if ( Game_mode & GM_NORMAL ) {
4031 if(game_do_cd_mission_check(Game_current_mission_filename)){
4032 gameseq_post_event(GS_EVENT_ENTER_GAME);
4034 gameseq_post_event(GS_EVENT_MAIN_MENU);
4039 gameseq_post_event(GS_EVENT_END_GAME);
4044 if(game_do_cd_mission_check(Game_current_mission_filename)){
4045 gameseq_post_event(GS_EVENT_START_GAME);
4047 gameseq_post_event(GS_EVENT_MAIN_MENU);
4051 // this should only happen during a red alert mission
4054 Assert(The_mission.red_alert);
4055 if(!The_mission.red_alert){
4057 if(game_do_cd_mission_check(Game_current_mission_filename)){
4058 gameseq_post_event(GS_EVENT_START_GAME);
4060 gameseq_post_event(GS_EVENT_MAIN_MENU);
4065 // choose the previous mission
4066 mission_campaign_previous_mission();
4068 if(game_do_cd_mission_check(Game_current_mission_filename)){
4069 gameseq_post_event(GS_EVENT_START_GAME);
4071 gameseq_post_event(GS_EVENT_MAIN_MENU);
4082 case POPUPDEAD_DO_MAIN_HALL:
4083 multi_quit_game(PROMPT_NONE,-1);
4086 case POPUPDEAD_DO_RESPAWN:
4087 multi_respawn_normal();
4088 event_music_player_respawn();
4091 case POPUPDEAD_DO_OBSERVER:
4092 multi_respawn_observer();
4093 event_music_player_respawn_as_observer();
4102 if ( leave_popup ) {
4108 // returns true if player is actually in a game_play stats
4109 int game_actually_playing()
4113 state = gameseq_get_state();
4114 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4120 // Draw the 2D HUD gauges
4121 void game_render_hud_2d()
4123 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4127 HUD_render_2d(flFrametime);
4131 // Draw the 3D-dependant HUD gauges
4132 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4134 g3_start_frame(0); // 0 = turn zbuffering off
4135 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4137 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4138 HUD_render_3d(flFrametime);
4142 game_sunspot_process(flFrametime);
4144 // Diminish the palette effect
4145 game_flash_diminish(flFrametime);
4153 int actually_playing;
4154 fix total_time1, total_time2;
4155 fix render2_time1=0, render2_time2=0;
4156 fix render3_time1=0, render3_time2=0;
4157 fix flip_time1=0, flip_time2=0;
4158 fix clear_time1=0, clear_time2=0;
4164 if (Framerate_delay) {
4165 int start_time = timer_get_milliseconds();
4166 while (timer_get_milliseconds() < start_time + Framerate_delay)
4172 demo_do_frame_start();
4174 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4179 // start timing frame
4180 timing_frame_start();
4182 total_time1 = timer_get_fixed_seconds();
4184 // var to hold which state we are in
4185 actually_playing = game_actually_playing();
4187 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4188 if (!(Game_mode & GM_STANDALONE_SERVER)){
4189 Assert( OBJ_INDEX(Player_obj) >= 0 );
4193 if (Missiontime > Entry_delay_time){
4194 Pre_player_entry = 0;
4196 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4199 // Note: These are done even before the player enters, else buffers can overflow.
4200 if (! (Game_mode & GM_STANDALONE_SERVER)){
4204 shield_frame_init();
4206 if ( Player->control_mode != PCM_NORMAL )
4209 if ( !Pre_player_entry && actually_playing ) {
4210 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4212 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4213 game_process_keys();
4215 // don't read flying controls if we're playing a demo back
4216 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4217 read_player_controls( Player_obj, flFrametime);
4221 // if we're not the master, we may have to send the server-critical ship status button_info bits
4222 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4223 multi_maybe_send_ship_status();
4228 // Reset the whack stuff
4231 // These two lines must be outside of Pre_player_entry code,
4232 // otherwise too many lights are added.
4235 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4239 game_simulation_frame();
4241 // if not actually in a game play state, then return. This condition could only be true in
4242 // a multiplayer game.
4243 if ( !actually_playing ) {
4244 Assert( Game_mode & GM_MULTIPLAYER );
4248 if (!Pre_player_entry) {
4249 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4250 clear_time1 = timer_get_fixed_seconds();
4251 // clear the screen to black
4253 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4257 clear_time2 = timer_get_fixed_seconds();
4258 render3_time1 = timer_get_fixed_seconds();
4259 game_render_frame_setup(&eye_pos, &eye_orient);
4260 game_render_frame( &eye_pos, &eye_orient );
4262 // save the eye position and orientation
4263 if ( Game_mode & GM_MULTIPLAYER ) {
4264 Net_player->s_info.eye_pos = eye_pos;
4265 Net_player->s_info.eye_orient = eye_orient;
4268 hud_show_target_model();
4270 // check to see if we should display the death died popup
4271 if(Game_mode & GM_DEAD_BLEW_UP){
4272 if(Game_mode & GM_MULTIPLAYER){
4273 // catch the situation where we're supposed to be warping out on this transition
4274 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4275 gameseq_post_event(GS_EVENT_DEBRIEF);
4276 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4277 Player_died_popup_wait = -1;
4281 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4282 Player_died_popup_wait = -1;
4288 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4289 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4290 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4291 if(!popupdead_is_active()){
4295 Player_multi_died_check = -1;
4299 render3_time2 = timer_get_fixed_seconds();
4300 render2_time1 = timer_get_fixed_seconds();
4303 game_get_framerate();
4304 game_show_framerate();
4306 game_show_time_left();
4308 // Draw the 2D HUD gauges
4309 if(supernova_active() < 3){
4310 game_render_hud_2d();
4313 game_set_view_clip();
4315 // Draw 3D HUD gauges
4316 game_render_hud_3d(&eye_pos, &eye_orient);
4320 render2_time2 = timer_get_fixed_seconds();
4322 // maybe render and process the dead popup
4323 game_maybe_do_dead_popup(flFrametime);
4325 // start timing frame
4326 timing_frame_stop();
4327 // timing_display(30, 10);
4329 // If a regular popup is active, don't flip (popup code flips)
4330 if( !popup_running_state() ){
4331 flip_time1 = timer_get_fixed_seconds();
4332 game_flip_page_and_time_it();
4333 flip_time2 = timer_get_fixed_seconds();
4337 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4340 game_show_standalone_framerate();
4344 game_do_training_checks();
4347 // process lightning (nebula only)
4350 total_time2 = timer_get_fixed_seconds();
4352 // Got some timing numbers
4353 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4354 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4355 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4356 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4357 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4360 demo_do_frame_end();
4362 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4368 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4369 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4370 // died. This resulted in screwed up death sequences.
4372 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4373 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4374 static int timer_paused=0;
4375 #if defined(TIMER_TEST) && !defined(NDEBUG)
4376 static int stop_count,start_count;
4377 static int time_stopped,time_started;
4379 int saved_timestamp_ticker = -1;
4381 void game_reset_time()
4383 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4387 // Last_time = timer_get_fixed_seconds();
4393 void game_stop_time()
4395 if (timer_paused==0) {
4397 time = timer_get_fixed_seconds();
4398 // Save how much time progressed so far in the frame so we can
4399 // use it when we unpause.
4400 Last_delta_time = time - Last_time;
4402 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4403 if (Last_delta_time < 0) {
4404 #if defined(TIMER_TEST) && !defined(NDEBUG)
4405 Int3(); //get Matt!!!!
4407 Last_delta_time = 0;
4409 #if defined(TIMER_TEST) && !defined(NDEBUG)
4410 time_stopped = time;
4413 // Stop the timer_tick stuff...
4414 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4415 saved_timestamp_ticker = timestamp_ticker;
4419 #if defined(TIMER_TEST) && !defined(NDEBUG)
4424 void game_start_time()
4427 Assert(timer_paused >= 0);
4428 if (timer_paused==0) {
4430 time = timer_get_fixed_seconds();
4431 #if defined(TIMER_TEST) && !defined(NDEBUG)
4433 Int3(); //get Matt!!!!
4436 // Take current time, and set it backwards to account for time
4437 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4438 // will be correct when it goes to calculate the frametime next
4440 Last_time = time - Last_delta_time;
4441 #if defined(TIMER_TEST) && !defined(NDEBUG)
4442 time_started = time;
4445 // Restore the timer_tick stuff...
4446 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4447 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4448 timestamp_ticker = saved_timestamp_ticker;
4449 saved_timestamp_ticker = -1;
4452 #if defined(TIMER_TEST) && !defined(NDEBUG)
4458 void game_set_frametime(int state)
4461 float frame_cap_diff;
4463 thistime = timer_get_fixed_seconds();
4465 if ( Last_time == 0 )
4466 Frametime = F1_0 / 30;
4468 Frametime = thistime - Last_time;
4470 // Frametime = F1_0 / 30;
4472 fix debug_frametime = Frametime; // Just used to display frametime.
4474 // If player hasn't entered mission yet, make frame take 1/4 second.
4475 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4478 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4480 fix frame_speed = F1_0 / Debug_dump_frames;
4482 if (Frametime > frame_speed ){
4483 nprintf(("warning","slow frame: %x\n",Frametime));
4486 thistime = timer_get_fixed_seconds();
4487 Frametime = thistime - Last_time;
4488 } while (Frametime < frame_speed );
4490 Frametime = frame_speed;
4494 Assert( Framerate_cap > 0 );
4496 // Cap the framerate so it doesn't get too high.
4500 cap = F1_0/Framerate_cap;
4501 if (Frametime < cap) {
4502 thistime = cap - Frametime;
4503 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4504 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4506 thistime = timer_get_fixed_seconds();
4510 if((Game_mode & GM_STANDALONE_SERVER) &&
4511 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4513 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4514 Sleep((DWORD)(frame_cap_diff*1000));
4516 thistime += fl2f((frame_cap_diff));
4518 Frametime = thistime - Last_time;
4521 // If framerate is too low, cap it.
4522 if (Frametime > MAX_FRAMETIME) {
4524 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4526 // to remove warnings in release build
4527 debug_frametime = fl2f(flFrametime);
4529 Frametime = MAX_FRAMETIME;
4532 Frametime = fixmul(Frametime, Game_time_compression);
4534 Last_time = thistime;
4535 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4537 flFrametime = f2fl(Frametime);
4538 //if(!(Game_mode & GM_PLAYING_DEMO)){
4539 timestamp_inc(flFrametime);
4541 /* if ((Framecount > 0) && (Framecount < 10)) {
4542 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4547 // This is called from game_do_frame(), and from navmap_do_frame()
4548 void game_update_missiontime()
4550 // TODO JAS: Put in if and move this into game_set_frametime,
4551 // fix navmap to call game_stop/start_time
4552 //if ( !timer_paused )
4553 Missiontime += Frametime;
4556 void game_do_frame()
4558 game_set_frametime(GS_STATE_GAME_PLAY);
4559 game_update_missiontime();
4561 if (Game_mode & GM_STANDALONE_SERVER) {
4562 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4565 if ( game_single_step && (last_single_step == game_single_step) ) {
4566 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4567 while( key_checkch() == 0 )
4569 os_set_title( XSTR( "FreeSpace", 171) );
4570 Last_time = timer_get_fixed_seconds();
4573 last_single_step = game_single_step;
4575 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4576 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4580 Keep_mouse_centered = 0;
4581 monitor_update(); // Update monitor variables
4584 void multi_maybe_do_frame()
4586 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4591 int Joymouse_button_status = 0;
4593 // Flush all input devices
4601 Joymouse_button_status = 0;
4603 //mprintf(("Game flush!\n" ));
4606 // function for multiplayer only which calls game_do_state_common() when running the
4608 void game_do_dc_networking()
4610 Assert( Game_mode & GM_MULTIPLAYER );
4612 game_do_state_common( gameseq_get_state() );
4615 // Call this whenever in a loop, or when you need to check for a keystroke.
4616 int game_check_key()
4622 // convert keypad enter to normal enter
4623 if ((k & KEY_MASK) == KEY_PADENTER)
4624 k = (k & ~KEY_MASK) | KEY_ENTER;
4631 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4632 static int Demo_show_trailer_timestamp = 0;
4634 void demo_reset_trailer_timer()
4636 Demo_show_trailer_timestamp = timer_get_milliseconds();
4639 void demo_maybe_show_trailer(int k)
4642 // if key pressed, reset demo trailer timer
4644 demo_reset_trailer_timer();
4648 // if mouse moved, reset demo trailer timer
4651 mouse_get_delta(&dx, &dy);
4652 if ( (dx > 0) || (dy > 0) ) {
4653 demo_reset_trailer_timer();
4657 // if joystick has moved, reset demo trailer timer
4660 joy_get_delta(&dx, &dy);
4661 if ( (dx > 0) || (dy > 0) ) {
4662 demo_reset_trailer_timer();
4666 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4667 // the low-level code. Ugly, I know... but was the simplest and most
4670 // if 30 seconds since last demo trailer time reset, launch movie
4671 if ( os_foreground() ) {
4672 int now = timer_get_milliseconds();
4673 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4674 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4676 movie_play( NOX("fstrailer2.mve") );
4677 demo_reset_trailer_timer();
4685 // same as game_check_key(), except this is used while actually in the game. Since there
4686 // generally are differences between game control keys and general UI keys, makes sense to
4687 // have seperate functions for each case. If you are not checking a game control while in a
4688 // mission, you should probably be using game_check_key() instead.
4693 if (!os_foreground()) {
4698 // If we're in a single player game, pause it.
4699 if (!(Game_mode & GM_MULTIPLAYER)){
4700 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4701 game_process_pause_key();
4709 demo_maybe_show_trailer(k);
4712 // Move the mouse cursor with the joystick.
4713 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4714 // Move the mouse cursor with the joystick
4718 joy_get_pos( &jx, &jy, &jz, &jr );
4720 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4721 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4724 mouse_get_real_pos( &mx, &my );
4725 mouse_set_pos( mx+dx, my+dy );
4730 m = mouse_down(MOUSE_LEFT_BUTTON);
4732 if ( j != Joymouse_button_status ) {
4733 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4734 Joymouse_button_status = j;
4736 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4737 } else if ( (!j) && (m) ) {
4738 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4743 // if we should be ignoring keys because of some multiplayer situations
4744 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4748 // If a popup is running, don't process all the Fn keys
4749 if( popup_active() ) {
4753 state = gameseq_get_state();
4755 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4758 case KEY_DEBUGGED + KEY_BACKSP:
4763 launch_context_help();
4768 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4770 // don't allow f2 while warping out in multiplayer
4771 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4776 case GS_STATE_INITIAL_PLAYER_SELECT:
4777 case GS_STATE_OPTIONS_MENU:
4778 case GS_STATE_HUD_CONFIG:
4779 case GS_STATE_CONTROL_CONFIG:
4780 case GS_STATE_DEATH_DIED:
4781 case GS_STATE_DEATH_BLEW_UP:
4782 case GS_STATE_VIEW_MEDALS:
4786 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4793 // hotkey selection screen -- only valid from briefing and beyond.
4796 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) ) {
4797 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4803 case KEY_DEBUGGED + KEY_F3:
4804 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4807 case KEY_DEBUGGED + KEY_F4:
4808 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4812 if(Game_mode & GM_MULTIPLAYER){
4813 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4814 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4818 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4819 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4825 case KEY_ESC | KEY_SHIFTED:
4826 // make sure to quit properly out of multiplayer
4827 if(Game_mode & GM_MULTIPLAYER){
4828 multi_quit_game(PROMPT_NONE);
4831 gameseq_post_event( GS_EVENT_QUIT_GAME );
4836 case KEY_DEBUGGED + KEY_P:
4839 case KEY_PRINT_SCRN:
4841 static int counter = 0;
4846 sprintf( tmp_name, NOX("screen%02d"), counter );
4848 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4849 gr_print_screen(tmp_name);
4857 case KEY_SHIFTED | KEY_ENTER: {
4859 #if !defined(NDEBUG)
4861 if ( Game_mode & GM_NORMAL ){
4865 // if we're in multiplayer mode, do some special networking
4866 if(Game_mode & GM_MULTIPLAYER){
4867 debug_console(game_do_dc_networking);
4874 if ( Game_mode & GM_NORMAL )
4888 gameseq_post_event(GS_EVENT_QUIT_GAME);
4891 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4894 void camera_set_position( vector *pos )
4899 void camera_set_orient( matrix *orient )
4901 Camera_orient = *orient;
4904 void camera_set_velocity( vector *vel, int instantaneous )
4906 Camera_desired_velocity.xyz.x = 0.0f;
4907 Camera_desired_velocity.xyz.y = 0.0f;
4908 Camera_desired_velocity.xyz.z = 0.0f;
4910 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4911 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4912 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4914 if ( instantaneous ) {
4915 Camera_velocity = Camera_desired_velocity;
4923 vector new_vel, delta_pos;
4925 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4926 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4927 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4929 Camera_velocity = new_vel;
4931 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4933 vm_vec_add2( &Camera_pos, &delta_pos );
4935 float ot = Camera_time+0.0f;
4937 Camera_time += flFrametime;
4939 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4942 tmp.xyz.z = 4.739f; // always go this fast forward.
4944 // pick x and y velocities so they are always on a
4945 // circle with a 25 m radius.
4947 float tmp_angle = frand()*PI2;
4949 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4950 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4952 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4954 //mprintf(( "Changing velocity!\n" ));
4955 camera_set_velocity( &tmp, 0 );
4958 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4959 vector tmp = { 0.0f, 0.0f, 0.0f };
4960 camera_set_velocity( &tmp, 0 );
4965 void end_demo_campaign_do()
4967 #if defined(FS2_DEMO)
4968 // show upsell screens
4969 demo_upsell_show_screens();
4970 #elif defined(OEM_BUILD)
4971 // show oem upsell screens
4972 oem_upsell_show_screens();
4975 // drop into main hall
4976 gameseq_post_event( GS_EVENT_MAIN_MENU );
4979 // All code to process events. This is the only place
4980 // that you should change the state of the game.
4981 void game_process_event( int current_state, int event )
4983 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4986 case GS_EVENT_SIMULATOR_ROOM:
4987 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4990 case GS_EVENT_MAIN_MENU:
4991 gameseq_set_state(GS_STATE_MAIN_MENU);
4994 case GS_EVENT_OPTIONS_MENU:
4995 gameseq_push_state( GS_STATE_OPTIONS_MENU );
4998 case GS_EVENT_BARRACKS_MENU:
4999 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5002 case GS_EVENT_TECH_MENU:
5003 gameseq_set_state(GS_STATE_TECH_MENU);
5006 case GS_EVENT_TRAINING_MENU:
5007 gameseq_set_state(GS_STATE_TRAINING_MENU);
5010 case GS_EVENT_START_GAME:
5011 Select_default_ship = 0;
5012 Player_multi_died_check = -1;
5013 gameseq_set_state(GS_STATE_CMD_BRIEF);
5016 case GS_EVENT_START_BRIEFING:
5017 gameseq_set_state(GS_STATE_BRIEFING);
5020 case GS_EVENT_DEBRIEF:
5021 // did we end the campaign in the main freespace 2 single player campaign?
5022 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5023 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5025 gameseq_set_state(GS_STATE_DEBRIEF);
5028 Player_multi_died_check = -1;
5031 case GS_EVENT_SHIP_SELECTION:
5032 gameseq_set_state( GS_STATE_SHIP_SELECT );
5035 case GS_EVENT_WEAPON_SELECTION:
5036 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5039 case GS_EVENT_ENTER_GAME:
5041 // maybe start recording a demo
5043 demo_start_record("test.fsd");
5047 if (Game_mode & GM_MULTIPLAYER) {
5048 // if we're respawning, make sure we change the view mode so that the hud shows up
5049 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5053 gameseq_set_state(GS_STATE_GAME_PLAY);
5055 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5058 Player_multi_died_check = -1;
5060 // clear multiplayer button info
5061 extern button_info Multi_ship_status_bi;
5062 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5064 Start_time = f2fl(timer_get_approx_seconds());
5066 mprintf(("Entering game at time = %7.3f\n", Start_time));
5070 case GS_EVENT_START_GAME_QUICK:
5071 Select_default_ship = 1;
5072 gameseq_post_event(GS_EVENT_ENTER_GAME);
5076 case GS_EVENT_END_GAME:
5077 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5078 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5079 gameseq_set_state(GS_STATE_MAIN_MENU);
5084 Player_multi_died_check = -1;
5087 case GS_EVENT_QUIT_GAME:
5088 main_hall_stop_music();
5089 main_hall_stop_ambient();
5090 gameseq_set_state(GS_STATE_QUIT_GAME);
5092 Player_multi_died_check = -1;
5095 case GS_EVENT_GAMEPLAY_HELP:
5096 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5099 case GS_EVENT_PAUSE_GAME:
5100 gameseq_push_state(GS_STATE_GAME_PAUSED);
5103 case GS_EVENT_DEBUG_PAUSE_GAME:
5104 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5107 case GS_EVENT_TRAINING_PAUSE:
5108 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5111 case GS_EVENT_PREVIOUS_STATE:
5112 gameseq_pop_state();
5115 case GS_EVENT_TOGGLE_FULLSCREEN:
5116 #ifndef HARDWARE_ONLY
5118 if ( gr_screen.mode == GR_SOFTWARE ) {
5119 gr_init( GR_640, GR_DIRECTDRAW );
5120 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5121 gr_init( GR_640, GR_SOFTWARE );
5127 case GS_EVENT_TOGGLE_GLIDE:
5129 if ( gr_screen.mode != GR_GLIDE ) {
5130 gr_init( GR_640, GR_GLIDE );
5132 gr_init( GR_640, GR_SOFTWARE );
5137 case GS_EVENT_LOAD_MISSION_MENU:
5138 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5141 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5142 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5145 case GS_EVENT_HUD_CONFIG:
5146 gameseq_push_state( GS_STATE_HUD_CONFIG );
5149 case GS_EVENT_CONTROL_CONFIG:
5150 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5153 case GS_EVENT_DEATH_DIED:
5154 gameseq_set_state( GS_STATE_DEATH_DIED );
5157 case GS_EVENT_DEATH_BLEW_UP:
5158 if ( current_state == GS_STATE_DEATH_DIED ) {
5159 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5160 event_music_player_death();
5162 // multiplayer clients set their extra check here
5163 if(Game_mode & GM_MULTIPLAYER){
5164 // set the multi died absolute last chance check
5165 Player_multi_died_check = time(NULL);
5168 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5172 case GS_EVENT_NEW_CAMPAIGN:
5173 if (!mission_load_up_campaign()){
5174 readyroom_continue_campaign();
5177 Player_multi_died_check = -1;
5180 case GS_EVENT_CAMPAIGN_CHEAT:
5181 if (!mission_load_up_campaign()){
5183 // bash campaign value
5184 extern char Main_hall_campaign_cheat[512];
5187 // look for the mission
5188 for(idx=0; idx<Campaign.num_missions; idx++){
5189 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5190 Campaign.next_mission = idx;
5191 Campaign.prev_mission = idx - 1;
5198 readyroom_continue_campaign();
5201 Player_multi_died_check = -1;
5204 case GS_EVENT_CAMPAIGN_ROOM:
5205 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5208 case GS_EVENT_CMD_BRIEF:
5209 gameseq_set_state(GS_STATE_CMD_BRIEF);
5212 case GS_EVENT_RED_ALERT:
5213 gameseq_set_state(GS_STATE_RED_ALERT);
5216 case GS_EVENT_CREDITS:
5217 gameseq_set_state( GS_STATE_CREDITS );
5220 case GS_EVENT_VIEW_MEDALS:
5221 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5224 case GS_EVENT_SHOW_GOALS:
5225 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5228 case GS_EVENT_HOTKEY_SCREEN:
5229 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5232 // multiplayer stuff follow these comments
5234 case GS_EVENT_MULTI_JOIN_GAME:
5235 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5238 case GS_EVENT_MULTI_HOST_SETUP:
5239 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5242 case GS_EVENT_MULTI_CLIENT_SETUP:
5243 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5246 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5247 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5250 case GS_EVENT_MULTI_STD_WAIT:
5251 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5254 case GS_EVENT_STANDALONE_MAIN:
5255 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5258 case GS_EVENT_MULTI_PAUSE:
5259 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5262 case GS_EVENT_INGAME_PRE_JOIN:
5263 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5266 case GS_EVENT_EVENT_DEBUG:
5267 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5270 // Start a warpout where player automatically goes 70 no matter what
5271 // and can't cancel out of it.
5272 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5273 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5275 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5276 Player->saved_viewer_mode = Viewer_mode;
5277 Player->control_mode = PCM_WARPOUT_STAGE1;
5278 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5279 Warpout_time = 0.0f; // Start timer!
5282 case GS_EVENT_PLAYER_WARPOUT_START:
5283 if ( Player->control_mode != PCM_NORMAL ) {
5284 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5286 Player->saved_viewer_mode = Viewer_mode;
5287 Player->control_mode = PCM_WARPOUT_STAGE1;
5288 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5289 Warpout_time = 0.0f; // Start timer!
5290 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5294 case GS_EVENT_PLAYER_WARPOUT_STOP:
5295 if ( Player->control_mode != PCM_NORMAL ) {
5296 if ( !Warpout_forced ) { // cannot cancel forced warpout
5297 Player->control_mode = PCM_NORMAL;
5298 Viewer_mode = Player->saved_viewer_mode;
5299 hud_subspace_notify_abort();
5300 mprintf(( "Player put back to normal mode.\n" ));
5301 if ( Warpout_sound > -1 ) {
5302 snd_stop( Warpout_sound );
5309 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5310 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5311 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5312 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5314 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5315 shipfx_warpout_start( Player_obj );
5316 Player->control_mode = PCM_WARPOUT_STAGE2;
5317 Player->saved_viewer_mode = Viewer_mode;
5318 Viewer_mode |= VM_WARP_CHASE;
5320 vector tmp = Player_obj->pos;
5322 ship_get_eye( &tmp, &tmp_m, Player_obj );
5323 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5324 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5325 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5327 camera_set_position( &tmp );
5328 camera_set_orient( &Player_obj->orient );
5329 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5331 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5332 camera_set_velocity( &tmp_vel, 1);
5336 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5337 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5338 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5339 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5341 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5342 Player->control_mode = PCM_WARPOUT_STAGE3;
5346 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5347 mprintf(( "Player warped out. Going to debriefing!\n" ));
5348 Player->control_mode = PCM_NORMAL;
5349 Viewer_mode = Player->saved_viewer_mode;
5352 // we have a special debriefing screen for multiplayer furballs
5353 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5354 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5356 // do the normal debriefing for all other situations
5358 gameseq_post_event(GS_EVENT_DEBRIEF);
5362 case GS_EVENT_STANDALONE_POSTGAME:
5363 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5366 case GS_EVENT_INITIAL_PLAYER_SELECT:
5367 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5370 case GS_EVENT_GAME_INIT:
5371 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5372 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5374 // see if the command line option has been set to use the last pilot, and act acoordingly
5375 if( player_select_get_last_pilot() ) {
5376 // always enter the main menu -- do the automatic network startup stuff elsewhere
5377 // so that we still have valid checks for networking modes, etc.
5378 gameseq_set_state(GS_STATE_MAIN_MENU);
5380 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5385 case GS_EVENT_MULTI_MISSION_SYNC:
5386 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5389 case GS_EVENT_MULTI_START_GAME:
5390 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5393 case GS_EVENT_MULTI_HOST_OPTIONS:
5394 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5397 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5398 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5401 case GS_EVENT_TEAM_SELECT:
5402 gameseq_set_state(GS_STATE_TEAM_SELECT);
5405 case GS_EVENT_END_CAMPAIGN:
5406 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5409 case GS_EVENT_END_DEMO:
5410 gameseq_set_state(GS_STATE_END_DEMO);
5413 case GS_EVENT_LOOP_BRIEF:
5414 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5423 // Called when a state is being left.
5424 // The current state is still at old_state, but as soon as
5425 // this function leaves, then the current state will become
5426 // new state. You should never try to change the state
5427 // in here... if you think you need to, you probably really
5428 // need to post an event, not change the state.
5429 void game_leave_state( int old_state, int new_state )
5431 int end_mission = 1;
5433 switch (new_state) {
5434 case GS_STATE_GAME_PAUSED:
5435 case GS_STATE_DEBUG_PAUSED:
5436 case GS_STATE_OPTIONS_MENU:
5437 case GS_STATE_CONTROL_CONFIG:
5438 case GS_STATE_MISSION_LOG_SCROLLBACK:
5439 case GS_STATE_DEATH_DIED:
5440 case GS_STATE_SHOW_GOALS:
5441 case GS_STATE_HOTKEY_SCREEN:
5442 case GS_STATE_MULTI_PAUSED:
5443 case GS_STATE_TRAINING_PAUSED:
5444 case GS_STATE_EVENT_DEBUG:
5445 case GS_STATE_GAMEPLAY_HELP:
5446 end_mission = 0; // these events shouldn't end a mission
5450 switch (old_state) {
5451 case GS_STATE_BRIEFING:
5452 brief_stop_voices();
5453 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5454 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5455 && (new_state != GS_STATE_TEAM_SELECT) ){
5456 common_select_close();
5457 if ( new_state == GS_STATE_MAIN_MENU ) {
5458 freespace_stop_mission();
5462 // COMMAND LINE OPTION
5463 if (Cmdline_multi_stream_chat_to_file){
5464 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5465 cfclose(Multi_chat_stream);
5469 case GS_STATE_DEBRIEF:
5470 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5475 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5476 multi_df_debrief_close();
5479 case GS_STATE_LOAD_MISSION_MENU:
5480 mission_load_menu_close();
5483 case GS_STATE_SIMULATOR_ROOM:
5487 case GS_STATE_CAMPAIGN_ROOM:
5488 campaign_room_close();
5491 case GS_STATE_CMD_BRIEF:
5492 if (new_state == GS_STATE_OPTIONS_MENU) {
5497 if (new_state == GS_STATE_MAIN_MENU)
5498 freespace_stop_mission();
5503 case GS_STATE_RED_ALERT:
5507 case GS_STATE_SHIP_SELECT:
5508 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5509 new_state != GS_STATE_HOTKEY_SCREEN &&
5510 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5511 common_select_close();
5512 if ( new_state == GS_STATE_MAIN_MENU ) {
5513 freespace_stop_mission();
5518 case GS_STATE_WEAPON_SELECT:
5519 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5520 new_state != GS_STATE_HOTKEY_SCREEN &&
5521 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5522 common_select_close();
5523 if ( new_state == GS_STATE_MAIN_MENU ) {
5524 freespace_stop_mission();
5529 case GS_STATE_TEAM_SELECT:
5530 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5531 new_state != GS_STATE_HOTKEY_SCREEN &&
5532 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5533 common_select_close();
5534 if ( new_state == GS_STATE_MAIN_MENU ) {
5535 freespace_stop_mission();
5540 case GS_STATE_MAIN_MENU:
5541 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5548 case GS_STATE_OPTIONS_MENU:
5549 //game_start_time();
5550 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5551 multi_join_clear_game_list();
5553 options_menu_close();
5556 case GS_STATE_BARRACKS_MENU:
5557 if(new_state != GS_STATE_VIEW_MEDALS){
5562 case GS_STATE_MISSION_LOG_SCROLLBACK:
5563 hud_scrollback_close();
5566 case GS_STATE_TRAINING_MENU:
5567 training_menu_close();
5570 case GS_STATE_GAME_PLAY:
5571 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5572 player_save_target_and_weapon_link_prefs();
5573 game_stop_looped_sounds();
5576 sound_env_disable();
5577 joy_ff_stop_effects();
5579 // stop game time under certain conditions
5580 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5585 // shut down any recording or playing demos
5590 // when in multiplayer and going back to the main menu, send a leave game packet
5591 // right away (before calling stop mission). stop_mission was taking to long to
5592 // close mission down and I want people to get notified ASAP.
5593 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5594 multi_quit_game(PROMPT_NONE);
5597 freespace_stop_mission();
5598 Game_time_compression = F1_0;
5602 case GS_STATE_TECH_MENU:
5606 case GS_STATE_TRAINING_PAUSED:
5607 Training_num_lines = 0;
5608 // fall through to GS_STATE_GAME_PAUSED
5610 case GS_STATE_GAME_PAUSED:
5612 if ( end_mission ) {
5617 case GS_STATE_DEBUG_PAUSED:
5620 pause_debug_close();
5624 case GS_STATE_HUD_CONFIG:
5628 // join/start a game
5629 case GS_STATE_MULTI_JOIN_GAME:
5630 if(new_state != GS_STATE_OPTIONS_MENU){
5631 multi_join_game_close();
5635 case GS_STATE_MULTI_HOST_SETUP:
5636 case GS_STATE_MULTI_CLIENT_SETUP:
5637 // if this is just the host going into the options screen, don't do anything
5638 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5642 // close down the proper state
5643 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5644 multi_create_game_close();
5646 multi_game_client_setup_close();
5649 // COMMAND LINE OPTION
5650 if (Cmdline_multi_stream_chat_to_file){
5651 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5652 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5653 cfclose(Multi_chat_stream);
5658 case GS_STATE_CONTROL_CONFIG:
5659 control_config_close();
5662 case GS_STATE_DEATH_DIED:
5663 Game_mode &= ~GM_DEAD_DIED;
5665 // early end while respawning or blowing up in a multiplayer game
5666 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5668 freespace_stop_mission();
5672 case GS_STATE_DEATH_BLEW_UP:
5673 Game_mode &= ~GM_DEAD_BLEW_UP;
5675 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5676 // to determine if I should do anything.
5677 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5679 freespace_stop_mission();
5682 // if we are not respawing as an observer or as a player, our new state will not
5683 // be gameplay state.
5684 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5685 game_stop_time(); // hasn't been called yet!!
5686 freespace_stop_mission();
5692 case GS_STATE_CREDITS:
5696 case GS_STATE_VIEW_MEDALS:
5700 case GS_STATE_SHOW_GOALS:
5701 mission_show_goals_close();
5704 case GS_STATE_HOTKEY_SCREEN:
5705 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5706 mission_hotkey_close();
5710 case GS_STATE_MULTI_MISSION_SYNC:
5711 // if we're moving into the options menu, don't do anything
5712 if(new_state == GS_STATE_OPTIONS_MENU){
5716 Assert( Game_mode & GM_MULTIPLAYER );
5718 if ( new_state == GS_STATE_GAME_PLAY ){
5719 // palette_restore_palette();
5721 // change a couple of flags to indicate our state!!!
5722 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5723 send_netplayer_update_packet();
5725 // set the game mode
5726 Game_mode |= GM_IN_MISSION;
5730 case GS_STATE_VIEW_CUTSCENES:
5731 cutscenes_screen_close();
5734 case GS_STATE_MULTI_STD_WAIT:
5735 multi_standalone_wait_close();
5738 case GS_STATE_STANDALONE_MAIN:
5739 standalone_main_close();
5740 if(new_state == GS_STATE_MULTI_STD_WAIT){
5741 init_multiplayer_stats();
5745 case GS_STATE_MULTI_PAUSED:
5746 // if ( end_mission ){
5751 case GS_STATE_INGAME_PRE_JOIN:
5752 multi_ingame_select_close();
5755 case GS_STATE_STANDALONE_POSTGAME:
5756 multi_standalone_postgame_close();
5759 case GS_STATE_INITIAL_PLAYER_SELECT:
5760 player_select_close();
5763 case GS_STATE_MULTI_START_GAME:
5764 multi_start_game_close();
5767 case GS_STATE_MULTI_HOST_OPTIONS:
5768 multi_host_options_close();
5771 case GS_STATE_END_OF_CAMPAIGN:
5772 mission_campaign_end_close();
5775 case GS_STATE_LOOP_BRIEF:
5781 // Called when a state is being entered.
5782 // The current state is set to the state we're entering at
5783 // this point, and old_state is set to the state we're coming
5784 // from. You should never try to change the state
5785 // in here... if you think you need to, you probably really
5786 // need to post an event, not change the state.
5788 void game_enter_state( int old_state, int new_state )
5790 switch (new_state) {
5791 case GS_STATE_MAIN_MENU:
5792 // in multiplayer mode, be sure that we are not doing networking anymore.
5793 if ( Game_mode & GM_MULTIPLAYER ) {
5794 Assert( Net_player != NULL );
5795 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5798 Game_time_compression = F1_0;
5800 // determine which ship this guy is currently based on
5801 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5804 if (Player->on_bastion) {
5812 case GS_STATE_BRIEFING:
5813 main_hall_stop_music();
5814 main_hall_stop_ambient();
5816 if (Game_mode & GM_NORMAL) {
5817 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5818 // MWA: or from options or hotkey screens
5819 // JH: or if the command brief state already did this
5820 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5821 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5822 && (old_state != GS_STATE_CMD_BRIEF) ) {
5823 if ( !game_start_mission() ) // this should put us into a new state on failure!
5827 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5828 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5829 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5831 Game_time_compression = F1_0;
5833 if ( red_alert_mission() ) {
5834 gameseq_post_event(GS_EVENT_RED_ALERT);
5841 case GS_STATE_DEBRIEF:
5842 game_stop_looped_sounds();
5843 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5844 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5849 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5850 multi_df_debrief_init();
5853 case GS_STATE_LOAD_MISSION_MENU:
5854 mission_load_menu_init();
5857 case GS_STATE_SIMULATOR_ROOM:
5861 case GS_STATE_CAMPAIGN_ROOM:
5862 campaign_room_init();
5865 case GS_STATE_RED_ALERT:
5866 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5870 case GS_STATE_CMD_BRIEF: {
5871 int team_num = 0; // team number used as index for which cmd brief to use.
5873 if (old_state == GS_STATE_OPTIONS_MENU) {
5877 main_hall_stop_music();
5878 main_hall_stop_ambient();
5880 if (Game_mode & GM_NORMAL) {
5881 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5882 // MWA: or from options or hotkey screens
5883 // JH: or if the command brief state already did this
5884 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5885 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5886 if ( !game_start_mission() ) // this should put us into a new state on failure!
5891 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5892 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5893 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5895 cmd_brief_init(team_num);
5901 case GS_STATE_SHIP_SELECT:
5905 case GS_STATE_WEAPON_SELECT:
5906 weapon_select_init();
5909 case GS_STATE_TEAM_SELECT:
5913 case GS_STATE_GAME_PAUSED:
5918 case GS_STATE_DEBUG_PAUSED:
5919 // game_stop_time();
5920 // os_set_title("FreeSpace - PAUSED");
5923 case GS_STATE_TRAINING_PAUSED:
5930 case GS_STATE_OPTIONS_MENU:
5932 options_menu_init();
5935 case GS_STATE_GAME_PLAY:
5936 // coming from the gameplay state or the main menu, we might need to load the mission
5937 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5938 if ( !game_start_mission() ) // this should put us into a new state.
5943 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5944 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5945 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5946 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5947 (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) ) {
5948 // JAS: Used to do all paging here.
5952 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5956 main_hall_stop_music();
5957 main_hall_stop_ambient();
5958 event_music_first_pattern(); // start the first pattern
5961 // special code that restores player ship selection and weapons loadout when doing a quick start
5962 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5963 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5964 wss_direct_restore_loadout();
5968 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5969 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5970 event_music_first_pattern(); // start the first pattern
5973 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5974 event_music_first_pattern(); // start the first pattern
5976 player_restore_target_and_weapon_link_prefs();
5978 Game_mode |= GM_IN_MISSION;
5981 // required to truely make mouse deltas zeroed in debug mouse code
5982 void mouse_force_pos(int x, int y);
5983 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5988 // only start time if in single player, or coming from multi wait state
5991 (Game_mode & GM_NORMAL) &&
5992 (old_state != GS_STATE_VIEW_CUTSCENES)
5994 (Game_mode & GM_MULTIPLAYER) && (
5995 (old_state == GS_STATE_MULTI_PAUSED) ||
5996 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6002 // when coming from the multi paused state, reset the timestamps
6003 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6004 multi_reset_timestamps();
6007 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6008 // initialize all object update details
6009 multi_oo_gameplay_init();
6012 // under certain circumstances, the server should reset the object update rate limiting stuff
6013 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6014 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6016 // reinitialize the rate limiting system for all clients
6017 multi_oo_rate_init_all();
6020 // multiplayer clients should always re-initialize their control info rate limiting system
6021 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6022 multi_oo_rate_init_all();
6026 if(Game_mode & GM_MULTIPLAYER){
6027 multi_ping_reset_players();
6030 Game_subspace_effect = 0;
6031 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6032 Game_subspace_effect = 1;
6033 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6034 game_start_subspace_ambient_sound();
6038 sound_env_set(&Game_sound_env);
6039 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6041 // clear multiplayer button info i
6042 extern button_info Multi_ship_status_bi;
6043 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6046 case GS_STATE_HUD_CONFIG:
6050 case GS_STATE_MULTI_JOIN_GAME:
6051 multi_join_clear_game_list();
6053 if (old_state != GS_STATE_OPTIONS_MENU) {
6054 multi_join_game_init();
6059 case GS_STATE_MULTI_HOST_SETUP:
6060 // don't reinitialize if we're coming back from the host options screen
6061 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6062 multi_create_game_init();
6067 case GS_STATE_MULTI_CLIENT_SETUP:
6068 if (old_state != GS_STATE_OPTIONS_MENU) {
6069 multi_game_client_setup_init();
6074 case GS_STATE_CONTROL_CONFIG:
6075 control_config_init();
6078 case GS_STATE_TECH_MENU:
6082 case GS_STATE_BARRACKS_MENU:
6083 if(old_state != GS_STATE_VIEW_MEDALS){
6088 case GS_STATE_MISSION_LOG_SCROLLBACK:
6089 hud_scrollback_init();
6092 case GS_STATE_DEATH_DIED:
6093 Player_died_time = timestamp(10);
6095 if(!(Game_mode & GM_MULTIPLAYER)){
6096 player_show_death_message();
6098 Game_mode |= GM_DEAD_DIED;
6101 case GS_STATE_DEATH_BLEW_UP:
6102 if ( !popupdead_is_active() ) {
6103 Player_ai->target_objnum = -1;
6106 // stop any local EMP effect
6109 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6110 Game_mode |= GM_DEAD_BLEW_UP;
6111 Show_viewing_from_self = 0;
6113 // timestamp how long we should wait before displaying the died popup
6114 if ( !popupdead_is_active() ) {
6115 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6119 case GS_STATE_GAMEPLAY_HELP:
6120 gameplay_help_init();
6123 case GS_STATE_CREDITS:
6124 main_hall_stop_music();
6125 main_hall_stop_ambient();
6129 case GS_STATE_VIEW_MEDALS:
6130 medal_main_init(Player);
6133 case GS_STATE_SHOW_GOALS:
6134 mission_show_goals_init();
6137 case GS_STATE_HOTKEY_SCREEN:
6138 mission_hotkey_init();
6141 case GS_STATE_MULTI_MISSION_SYNC:
6142 // if we're coming from the options screen, don't do any
6143 if(old_state == GS_STATE_OPTIONS_MENU){
6147 switch(Multi_sync_mode){
6148 case MULTI_SYNC_PRE_BRIEFING:
6149 // if moving from game forming to the team select state
6152 case MULTI_SYNC_POST_BRIEFING:
6153 // if moving from briefing into the mission itself
6156 // tell everyone that we're now loading data
6157 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6158 send_netplayer_update_packet();
6160 // JAS: Used to do all paging here!!!!
6162 Net_player->state = NETPLAYER_STATE_WAITING;
6163 send_netplayer_update_packet();
6165 Game_time_compression = F1_0;
6167 case MULTI_SYNC_INGAME:
6173 case GS_STATE_VIEW_CUTSCENES:
6174 cutscenes_screen_init();
6177 case GS_STATE_MULTI_STD_WAIT:
6178 multi_standalone_wait_init();
6181 case GS_STATE_STANDALONE_MAIN:
6182 // don't initialize if we're coming from one of these 2 states unless there are no
6183 // players left (reset situation)
6184 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6185 standalone_main_init();
6189 case GS_STATE_MULTI_PAUSED:
6193 case GS_STATE_INGAME_PRE_JOIN:
6194 multi_ingame_select_init();
6197 case GS_STATE_STANDALONE_POSTGAME:
6198 multi_standalone_postgame_init();
6201 case GS_STATE_INITIAL_PLAYER_SELECT:
6202 player_select_init();
6205 case GS_STATE_MULTI_START_GAME:
6206 multi_start_game_init();
6209 case GS_STATE_MULTI_HOST_OPTIONS:
6210 multi_host_options_init();
6213 case GS_STATE_END_OF_CAMPAIGN:
6214 mission_campaign_end_init();
6217 case GS_STATE_LOOP_BRIEF:
6224 // do stuff that may need to be done regardless of state
6225 void game_do_state_common(int state,int no_networking)
6227 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6228 snd_do_frame(); // update sound system
6229 event_music_do_frame(); // music needs to play across many states
6231 multi_log_process();
6233 if (no_networking) {
6237 // maybe do a multiplayer frame based on game mode and state type
6238 if (Game_mode & GM_MULTIPLAYER) {
6240 case GS_STATE_OPTIONS_MENU:
6241 case GS_STATE_GAMEPLAY_HELP:
6242 case GS_STATE_HOTKEY_SCREEN:
6243 case GS_STATE_HUD_CONFIG:
6244 case GS_STATE_CONTROL_CONFIG:
6245 case GS_STATE_MISSION_LOG_SCROLLBACK:
6246 case GS_STATE_SHOW_GOALS:
6247 case GS_STATE_VIEW_CUTSCENES:
6248 case GS_STATE_EVENT_DEBUG:
6249 multi_maybe_do_frame();
6253 game_do_networking();
6257 // Called once a frame.
6258 // You should never try to change the state
6259 // in here... if you think you need to, you probably really
6260 // need to post an event, not change the state.
6261 int Game_do_state_should_skip = 0;
6262 void game_do_state(int state)
6264 // always lets the do_state_common() function determine if the state should be skipped
6265 Game_do_state_should_skip = 0;
6267 // legal to set the should skip state anywhere in this function
6268 game_do_state_common(state); // do stuff that may need to be done regardless of state
6270 if(Game_do_state_should_skip){
6275 case GS_STATE_MAIN_MENU:
6276 game_set_frametime(GS_STATE_MAIN_MENU);
6277 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6280 main_hall_do(flFrametime);
6284 case GS_STATE_OPTIONS_MENU:
6285 game_set_frametime(GS_STATE_OPTIONS_MENU);
6286 options_menu_do_frame(flFrametime);
6289 case GS_STATE_BARRACKS_MENU:
6290 game_set_frametime(GS_STATE_BARRACKS_MENU);
6291 barracks_do_frame(flFrametime);
6294 case GS_STATE_TRAINING_MENU:
6295 game_set_frametime(GS_STATE_TRAINING_MENU);
6296 training_menu_do_frame(flFrametime);
6299 case GS_STATE_TECH_MENU:
6300 game_set_frametime(GS_STATE_TECH_MENU);
6301 techroom_do_frame(flFrametime);
6304 case GS_STATE_GAMEPLAY_HELP:
6305 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6306 gameplay_help_do_frame(flFrametime);
6309 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6313 case GS_STATE_GAME_PAUSED:
6317 case GS_STATE_DEBUG_PAUSED:
6319 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6324 case GS_STATE_TRAINING_PAUSED:
6325 game_training_pause_do();
6328 case GS_STATE_LOAD_MISSION_MENU:
6329 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6330 mission_load_menu_do();
6333 case GS_STATE_BRIEFING:
6334 game_set_frametime(GS_STATE_BRIEFING);
6335 brief_do_frame(flFrametime);
6338 case GS_STATE_DEBRIEF:
6339 game_set_frametime(GS_STATE_DEBRIEF);
6340 debrief_do_frame(flFrametime);
6343 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6344 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6345 multi_df_debrief_do();
6348 case GS_STATE_SHIP_SELECT:
6349 game_set_frametime(GS_STATE_SHIP_SELECT);
6350 ship_select_do(flFrametime);
6353 case GS_STATE_WEAPON_SELECT:
6354 game_set_frametime(GS_STATE_WEAPON_SELECT);
6355 weapon_select_do(flFrametime);
6358 case GS_STATE_MISSION_LOG_SCROLLBACK:
6359 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6360 hud_scrollback_do_frame(flFrametime);
6363 case GS_STATE_HUD_CONFIG:
6364 game_set_frametime(GS_STATE_HUD_CONFIG);
6365 hud_config_do_frame(flFrametime);
6368 case GS_STATE_MULTI_JOIN_GAME:
6369 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6370 multi_join_game_do_frame();
6373 case GS_STATE_MULTI_HOST_SETUP:
6374 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6375 multi_create_game_do();
6378 case GS_STATE_MULTI_CLIENT_SETUP:
6379 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6380 multi_game_client_setup_do_frame();
6383 case GS_STATE_CONTROL_CONFIG:
6384 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6385 control_config_do_frame(flFrametime);
6388 case GS_STATE_DEATH_DIED:
6392 case GS_STATE_DEATH_BLEW_UP:
6396 case GS_STATE_SIMULATOR_ROOM:
6397 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6398 sim_room_do_frame(flFrametime);
6401 case GS_STATE_CAMPAIGN_ROOM:
6402 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6403 campaign_room_do_frame(flFrametime);
6406 case GS_STATE_RED_ALERT:
6407 game_set_frametime(GS_STATE_RED_ALERT);
6408 red_alert_do_frame(flFrametime);
6411 case GS_STATE_CMD_BRIEF:
6412 game_set_frametime(GS_STATE_CMD_BRIEF);
6413 cmd_brief_do_frame(flFrametime);
6416 case GS_STATE_CREDITS:
6417 game_set_frametime(GS_STATE_CREDITS);
6418 credits_do_frame(flFrametime);
6421 case GS_STATE_VIEW_MEDALS:
6422 game_set_frametime(GS_STATE_VIEW_MEDALS);
6426 case GS_STATE_SHOW_GOALS:
6427 game_set_frametime(GS_STATE_SHOW_GOALS);
6428 mission_show_goals_do_frame(flFrametime);
6431 case GS_STATE_HOTKEY_SCREEN:
6432 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6433 mission_hotkey_do_frame(flFrametime);
6436 case GS_STATE_VIEW_CUTSCENES:
6437 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6438 cutscenes_screen_do_frame();
6441 case GS_STATE_MULTI_STD_WAIT:
6442 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6443 multi_standalone_wait_do();
6446 case GS_STATE_STANDALONE_MAIN:
6447 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6448 standalone_main_do();
6451 case GS_STATE_MULTI_PAUSED:
6452 game_set_frametime(GS_STATE_MULTI_PAUSED);
6456 case GS_STATE_TEAM_SELECT:
6457 game_set_frametime(GS_STATE_TEAM_SELECT);
6461 case GS_STATE_INGAME_PRE_JOIN:
6462 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6463 multi_ingame_select_do();
6466 case GS_STATE_EVENT_DEBUG:
6468 game_set_frametime(GS_STATE_EVENT_DEBUG);
6469 game_show_event_debug(flFrametime);
6473 case GS_STATE_STANDALONE_POSTGAME:
6474 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6475 multi_standalone_postgame_do();
6478 case GS_STATE_INITIAL_PLAYER_SELECT:
6479 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6483 case GS_STATE_MULTI_MISSION_SYNC:
6484 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6488 case GS_STATE_MULTI_START_GAME:
6489 game_set_frametime(GS_STATE_MULTI_START_GAME);
6490 multi_start_game_do();
6493 case GS_STATE_MULTI_HOST_OPTIONS:
6494 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6495 multi_host_options_do();
6498 case GS_STATE_END_OF_CAMPAIGN:
6499 mission_campaign_end_do();
6502 case GS_STATE_END_DEMO:
6503 game_set_frametime(GS_STATE_END_DEMO);
6504 end_demo_campaign_do();
6507 case GS_STATE_LOOP_BRIEF:
6508 game_set_frametime(GS_STATE_LOOP_BRIEF);
6512 } // end switch(gs_current_state)
6516 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6517 int game_do_ram_check(int ram_in_bytes)
6519 if ( ram_in_bytes < 30*1024*1024 ) {
6520 int allowed_to_run = 1;
6521 if ( ram_in_bytes < 25*1024*1024 ) {
6526 int Freespace_total_ram_MB;
6527 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6529 if ( allowed_to_run ) {
6531 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);
6536 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6537 if ( msgbox_rval == IDCANCEL ) {
6544 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);
6546 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6557 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6558 // If so, copy it over and remove the update directory.
6559 void game_maybe_update_launcher(char *exe_dir)
6562 char src_filename[MAX_PATH];
6563 char dest_filename[MAX_PATH];
6565 strcpy(src_filename, exe_dir);
6566 strcat(src_filename, NOX("\\update\\freespace.exe"));
6568 strcpy(dest_filename, exe_dir);
6569 strcat(dest_filename, NOX("\\freespace.exe"));
6571 // see if src_filename exists
6573 fp = fopen(src_filename, "rb");
6579 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6581 // copy updated freespace.exe to freespace exe dir
6582 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6583 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 );
6587 // delete the file in the update directory
6588 DeleteFile(src_filename);
6590 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6591 char update_dir[MAX_PATH];
6592 strcpy(update_dir, exe_dir);
6593 strcat(update_dir, NOX("\\update"));
6594 RemoveDirectory(update_dir);
6600 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6604 int sub_total_destroyed = 0;
6608 // get the total for all his children
6609 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6610 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6613 // find the # of faces for this _individual_ object
6614 total = submodel_get_num_polys(model_num, sm);
6615 if(strstr(pm->submodel[sm].name, "-destroyed")){
6616 sub_total_destroyed = total;
6620 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6623 *out_total += total + sub_total;
6624 *out_destroyed_total += sub_total_destroyed;
6627 #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);
6628 void game_spew_pof_info()
6630 char *pof_list[1000];
6633 int idx, model_num, i, j;
6635 int total, root_total, model_total, destroyed_total, counted;
6639 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6641 // spew info on all the pofs
6647 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6652 for(idx=0; idx<num_files; idx++, counted++){
6653 sprintf(str, "%s.pof", pof_list[idx]);
6654 model_num = model_load(str, 0, NULL);
6656 pm = model_get(model_num);
6658 // if we have a real model
6663 // go through and print all raw submodels
6664 cfputs("RAW\n", out);
6667 for (i=0; i<pm->n_models; i++) {
6668 total = submodel_get_num_polys(model_num, i);
6670 model_total += total;
6671 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6674 sprintf(str, "Model total %d\n", model_total);
6677 // now go through and do it by LOD
6678 cfputs("BY LOD\n\n", out);
6679 for(i=0; i<pm->n_detail_levels; i++){
6680 sprintf(str, "LOD %d\n", i);
6684 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6686 destroyed_total = 0;
6687 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6688 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6691 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6694 sprintf(str, "TOTAL: %d\n", total + root_total);
6696 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6698 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6701 cfputs("------------------------------------------------------------------------\n\n", out);
6705 if(counted >= MAX_POLYGON_MODELS - 5){
6718 game_spew_pof_info();
6721 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6726 // Don't let more than one instance of Freespace run.
6727 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6729 SetForegroundWindow(hwnd);
6734 // Find out how much RAM is on this machine
6737 ms.dwLength = sizeof(MEMORYSTATUS);
6738 GlobalMemoryStatus(&ms);
6739 Freespace_total_ram = ms.dwTotalPhys;
6741 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6745 if ( ms.dwTotalVirtual < 1024 ) {
6746 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6750 if (!vm_init(24*1024*1024)) {
6751 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 );
6755 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6757 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);
6765 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6766 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6767 seem worth bothering with.
6771 lResult = RegOpenKeyEx(
6772 HKEY_LOCAL_MACHINE, // Where it is
6773 "Software\\Microsoft\\DirectX", // name of key
6774 NULL, // DWORD reserved
6775 KEY_QUERY_VALUE, // Allows all changes
6776 &hKey // Location to store key
6779 if (lResult == ERROR_SUCCESS) {
6781 DWORD dwType, dwLen;
6784 lResult = RegQueryValueEx(
6785 hKey, // Handle to key
6786 "Version", // The values name
6787 NULL, // DWORD reserved
6788 &dwType, // What kind it is
6789 (ubyte *) version, // value to set
6790 &dwLen // How many bytes to set
6793 if (lResult == ERROR_SUCCESS) {
6794 dx_version = atoi(strstr(version, ".") + 1);
6798 DWORD dwType, dwLen;
6801 lResult = RegQueryValueEx(
6802 hKey, // Handle to key
6803 "InstalledVersion", // The values name
6804 NULL, // DWORD reserved
6805 &dwType, // What kind it is
6806 (ubyte *) &val, // value to set
6807 &dwLen // How many bytes to set
6810 if (lResult == ERROR_SUCCESS) {
6818 if (dx_version < 3) {
6819 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6820 "latest version of DirectX at:\n\n"
6821 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6823 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6824 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6829 //=====================================================
6830 // Make sure we're running in the right directory.
6834 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6835 char *p = exe_dir + strlen(exe_dir);
6837 // chop off the filename
6838 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6844 if ( strlen(exe_dir) > 0 ) {
6845 SetCurrentDirectory(exe_dir);
6848 // check for updated freespace.exe
6849 game_maybe_update_launcher(exe_dir);
6857 extern void windebug_memwatch_init();
6858 windebug_memwatch_init();
6862 parse_cmdline(szCmdLine);
6864 #ifdef STANDALONE_ONLY_BUILD
6866 nprintf(("Network", "Standalone running"));
6869 nprintf(("Network", "Standalone running"));
6877 // maybe spew pof stuff
6878 if(Cmdline_spew_pof_info){
6879 game_spew_pof_info();
6884 // non-demo, non-standalone, play the intro movie
6889 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) ){
6891 #if defined(OEM_BUILD)
6892 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6894 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6895 #endif // defined(OEM_BUILD)
6900 if ( !Is_standalone ) {
6902 // release -- movies always play
6905 // 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
6907 // movie_play( NOX("intro.mve"), 0 );
6909 // debug version, movie will only play with -showmovies
6910 #elif !defined(NDEBUG)
6913 // movie_play( NOX("intro.mve"), 0);
6916 if ( Cmdline_show_movies )
6917 movie_play( NOX("intro.mve"), 0 );
6926 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6928 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6932 // only important for non THREADED mode
6935 state = gameseq_process_events();
6936 if ( state == GS_STATE_QUIT_GAME ){
6943 demo_upsell_show_screens();
6945 #elif defined(OEM_BUILD)
6946 // show upsell screens on exit
6947 oem_upsell_show_screens();
6954 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6960 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6962 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6964 // Do nothing here - RecordExceptionInfo() has already done
6965 // everything that is needed. Actually this code won't even
6966 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6967 // the __except clause.
6971 nprintf(("WinMain", "exceptions shall fall through"));
6973 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6979 // launcher the fslauncher program on exit
6980 void game_launch_launcher_on_exit()
6984 PROCESS_INFORMATION pi;
6985 char cmd_line[2048];
6986 char original_path[1024] = "";
6988 memset( &si, 0, sizeof(STARTUPINFO) );
6992 _getcwd(original_path, 1023);
6994 // set up command line
6995 strcpy(cmd_line, original_path);
6996 strcat(cmd_line, "\\");
6997 strcat(cmd_line, LAUNCHER_FNAME);
6998 strcat(cmd_line, " -straight_to_update");
7000 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7001 cmd_line, // pointer to command line string
7002 NULL, // pointer to process security attributes
7003 NULL, // pointer to thread security attributes
7004 FALSE, // handle inheritance flag
7005 CREATE_DEFAULT_ERROR_MODE, // creation flags
7006 NULL, // pointer to new environment block
7007 NULL, // pointer to current directory name
7008 &si, // pointer to STARTUPINFO
7009 &pi // pointer to PROCESS_INFORMATION
7011 // to eliminate build warnings
7021 // This function is called when FreeSpace terminates normally.
7023 void game_shutdown(void)
7029 // don't ever flip a page on the standalone!
7030 if(!(Game_mode & GM_STANDALONE_SERVER)){
7036 // if the player has left the "player select" screen and quit the game without actually choosing
7037 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7038 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7042 // load up common multiplayer icons
7043 multi_unload_common_icons();
7045 shockwave_close(); // release any memory used by shockwave system
7046 fireball_close(); // free fireball system
7047 ship_close(); // free any memory that was allocated for the ships
7048 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7049 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7050 bm_unload_all(); // free bitmaps
7051 mission_campaign_close(); // close out the campaign stuff
7052 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7054 #ifdef MULTI_USE_LAG
7058 // the menu close functions will unload the bitmaps if they were displayed during the game
7059 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7062 training_menu_close();
7065 extern void joy_close();
7068 audiostream_close();
7070 event_music_close();
7074 // HACKITY HACK HACK
7075 // if this flag is set, we should be firing up the launcher when exiting freespace
7076 extern int Multi_update_fireup_launcher_on_exit;
7077 if(Multi_update_fireup_launcher_on_exit){
7078 game_launch_launcher_on_exit();
7082 // game_stop_looped_sounds()
7084 // This function will call the appropriate stop looped sound functions for those
7085 // modules which use looping sounds. It is not enough just to stop a looping sound
7086 // at the DirectSound level, the game is keeping track of looping sounds, and this
7087 // function is used to inform the game that looping sounds are being halted.
7089 void game_stop_looped_sounds()
7091 hud_stop_looped_locking_sounds();
7092 hud_stop_looped_engine_sounds();
7093 afterburner_stop_sounds();
7094 player_stop_looped_sounds();
7095 obj_snd_stop_all(); // stop all object-linked persistant sounds
7096 game_stop_subspace_ambient_sound();
7097 snd_stop(Radar_static_looping);
7098 Radar_static_looping = -1;
7099 snd_stop(Target_static_looping);
7100 shipfx_stop_engine_wash_sound();
7101 Target_static_looping = -1;
7104 //////////////////////////////////////////////////////////////////////////
7106 // Code for supporting an animating mouse pointer
7109 //////////////////////////////////////////////////////////////////////////
7111 typedef struct animating_obj
7120 static animating_obj Animating_mouse;
7122 // ----------------------------------------------------------------------------
7123 // init_animating_pointer()
7125 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7126 // gets properly initialized
7128 void init_animating_pointer()
7130 Animating_mouse.first_frame = -1;
7131 Animating_mouse.num_frames = 0;
7132 Animating_mouse.current_frame = -1;
7133 Animating_mouse.time = 0.0f;
7134 Animating_mouse.elapsed_time = 0.0f;
7137 // ----------------------------------------------------------------------------
7138 // load_animating_pointer()
7140 // Called at game init to load in the frames for the animating mouse pointer
7142 // input: filename => filename of animation file that holds the animation
7144 void load_animating_pointer(char *filename, int dx, int dy)
7149 init_animating_pointer();
7151 am = &Animating_mouse;
7152 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7153 if ( am->first_frame == -1 )
7154 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7155 am->current_frame = 0;
7156 am->time = am->num_frames / i2fl(fps);
7159 // ----------------------------------------------------------------------------
7160 // unload_animating_pointer()
7162 // Called at game shutdown to free the memory used to store the animation frames
7164 void unload_animating_pointer()
7169 am = &Animating_mouse;
7170 for ( i = 0; i < am->num_frames; i++ ) {
7171 Assert( (am->first_frame+i) >= 0 );
7172 bm_release(am->first_frame + i);
7175 am->first_frame = -1;
7177 am->current_frame = -1;
7180 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7181 void game_render_mouse(float frametime)
7186 // if animating cursor exists, play the next frame
7187 am = &Animating_mouse;
7188 if ( am->first_frame != -1 ) {
7189 mouse_get_pos(&mx, &my);
7190 am->elapsed_time += frametime;
7191 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7192 if ( am->current_frame >= am->num_frames ) {
7193 am->current_frame = 0;
7194 am->elapsed_time = 0.0f;
7196 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7200 // ----------------------------------------------------------------------------
7201 // game_maybe_draw_mouse()
7203 // determines whether to draw the mouse pointer at all, and what frame of
7204 // animation to use if the mouse is animating
7206 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7208 // input: frametime => elapsed frame time in seconds since last call
7210 void game_maybe_draw_mouse(float frametime)
7214 game_state = gameseq_get_state();
7216 switch ( game_state ) {
7217 case GS_STATE_GAME_PAUSED:
7218 // case GS_STATE_MULTI_PAUSED:
7219 case GS_STATE_GAME_PLAY:
7220 case GS_STATE_DEATH_DIED:
7221 case GS_STATE_DEATH_BLEW_UP:
7222 if ( popup_active() || popupdead_is_active() ) {
7234 if ( !Mouse_hidden )
7235 game_render_mouse(frametime);
7239 void game_do_training_checks()
7243 waypoint_list *wplp;
7245 if (Training_context & TRAINING_CONTEXT_SPEED) {
7246 s = (int) Player_obj->phys_info.fspeed;
7247 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7248 if (!Training_context_speed_set) {
7249 Training_context_speed_set = 1;
7250 Training_context_speed_timestamp = timestamp();
7254 Training_context_speed_set = 0;
7257 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7258 wplp = &Waypoint_lists[Training_context_path];
7259 if (wplp->count > Training_context_goal_waypoint) {
7260 i = Training_context_goal_waypoint;
7262 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7263 if (d <= Training_context_distance) {
7264 Training_context_at_waypoint = i;
7265 if (Training_context_goal_waypoint == i) {
7266 Training_context_goal_waypoint++;
7267 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7274 if (i == wplp->count)
7277 } while (i != Training_context_goal_waypoint);
7281 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7282 Players_target = Player_ai->target_objnum;
7283 Players_targeted_subsys = Player_ai->targeted_subsys;
7284 Players_target_timestamp = timestamp();
7288 /////////// Following is for event debug view screen
7292 #define EVENT_DEBUG_MAX 5000
7293 #define EVENT_DEBUG_EVENT 0x8000
7295 int Event_debug_index[EVENT_DEBUG_MAX];
7298 void game_add_event_debug_index(int n, int indent)
7300 if (ED_count < EVENT_DEBUG_MAX)
7301 Event_debug_index[ED_count++] = n | (indent << 16);
7304 void game_add_event_debug_sexp(int n, int indent)
7309 if (Sexp_nodes[n].first >= 0) {
7310 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7311 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7315 game_add_event_debug_index(n, indent);
7316 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7317 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7319 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7322 void game_event_debug_init()
7327 for (e=0; e<Num_mission_events; e++) {
7328 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7329 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7333 void game_show_event_debug(float frametime)
7337 int font_height, font_width;
7339 static int scroll_offset = 0;
7341 k = game_check_key();
7347 if (scroll_offset < 0)
7357 scroll_offset -= 20;
7358 if (scroll_offset < 0)
7363 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7367 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7373 gr_set_color_fast(&Color_bright);
7375 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7377 gr_set_color_fast(&Color_normal);
7379 gr_get_string_size(&font_width, &font_height, NOX("test"));
7380 y_max = gr_screen.max_h - font_height - 5;
7384 while (k < ED_count) {
7385 if (y_index > y_max)
7388 z = Event_debug_index[k];
7389 if (z & EVENT_DEBUG_EVENT) {
7391 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7392 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7393 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7394 Mission_events[z].repeat_count, Mission_events[z].interval);
7402 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7403 switch (Sexp_nodes[z & 0x7fff].value) {
7405 strcat(buf, NOX(" (True)"));
7409 strcat(buf, NOX(" (False)"));
7412 case SEXP_KNOWN_TRUE:
7413 strcat(buf, NOX(" (Always true)"));
7416 case SEXP_KNOWN_FALSE:
7417 strcat(buf, NOX(" (Always false)"));
7420 case SEXP_CANT_EVAL:
7421 strcat(buf, NOX(" (Can't eval)"));
7425 case SEXP_NAN_FOREVER:
7426 strcat(buf, NOX(" (Not a number)"));
7431 gr_printf(10, y_index, buf);
7432 y_index += font_height;
7445 extern int Tmap_npixels;
7447 int Tmap_num_too_big = 0;
7448 int Num_models_needing_splitting = 0;
7450 void Time_model( int modelnum )
7452 // mprintf(( "Timing ship '%s'\n", si->name ));
7454 vector eye_pos, model_pos;
7455 matrix eye_orient, model_orient;
7457 polymodel *pm = model_get( modelnum );
7459 int l = strlen(pm->filename);
7461 if ( (l == '/') || (l=='\\') || (l==':')) {
7467 char *pof_file = &pm->filename[l];
7469 int model_needs_splitting = 0;
7471 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7473 for (i=0; i<pm->n_textures; i++ ) {
7474 char filename[1024];
7477 int bmp_num = pm->original_textures[i];
7478 if ( bmp_num > -1 ) {
7479 bm_get_palette(pm->original_textures[i], pal, filename );
7481 bm_get_info( pm->original_textures[i],&w, &h );
7484 if ( (w > 512) || (h > 512) ) {
7485 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7487 model_needs_splitting++;
7490 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7494 if ( model_needs_splitting ) {
7495 Num_models_needing_splitting++;
7497 eye_orient = model_orient = vmd_identity_matrix;
7498 eye_pos = model_pos = vmd_zero_vector;
7500 eye_pos.xyz.z = -pm->rad*2.0f;
7502 vector eye_to_model;
7504 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7505 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7507 fix t1 = timer_get_fixed_seconds();
7510 ta.p = ta.b = ta.h = 0.0f;
7515 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7517 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7519 modelstats_num_polys = modelstats_num_verts = 0;
7521 while( ta.h < PI2 ) {
7524 vm_angles_2_matrix(&m1, &ta );
7525 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7532 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7534 model_clear_instance( modelnum );
7535 model_set_detail_level(0); // use highest detail level
7536 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7544 int k = key_inkey();
7545 if ( k == KEY_ESC ) {
7550 fix t2 = timer_get_fixed_seconds();
7552 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7553 //bitmaps_used_this_frame /= framecount;
7555 modelstats_num_polys /= framecount;
7556 modelstats_num_verts /= framecount;
7558 Tmap_npixels /=framecount;
7561 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7562 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 );
7563 // 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 );
7569 int Time_models = 0;
7570 DCF_BOOL( time_models, Time_models );
7572 void Do_model_timings_test()
7576 if ( !Time_models ) return;
7578 mprintf(( "Timing models!\n" ));
7582 ubyte model_used[MAX_POLYGON_MODELS];
7583 int model_id[MAX_POLYGON_MODELS];
7584 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7589 for (i=0; i<Num_ship_types; i++ ) {
7590 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7592 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7593 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7596 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7597 if ( !Texture_fp ) return;
7599 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7600 if ( !Time_fp ) return;
7602 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7603 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7605 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7606 if ( model_used[i] ) {
7607 Time_model( model_id[i] );
7611 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7612 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7621 // Call this function when you want to inform the player that a feature is not
7622 // enabled in the DEMO version of FreSpace
7623 void game_feature_not_in_demo_popup()
7625 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7628 // format the specified time (fixed point) into a nice string
7629 void game_format_time(fix m_time,char *time_str)
7632 int hours,minutes,seconds;
7635 mtime = f2fl(m_time);
7637 // get the hours, minutes and seconds
7638 hours = (int)(mtime / 3600.0f);
7640 mtime -= (3600.0f * (float)hours);
7642 seconds = (int)mtime%60;
7643 minutes = (int)mtime/60;
7645 // print the hour if necessary
7647 sprintf(time_str,XSTR( "%d:", 201),hours);
7648 // if there are less than 10 minutes, print a leading 0
7650 strcpy(tmp,NOX("0"));
7651 strcat(time_str,tmp);
7655 // print the minutes
7657 sprintf(tmp,XSTR( "%d:", 201),minutes);
7658 strcat(time_str,tmp);
7660 sprintf(time_str,XSTR( "%d:", 201),minutes);
7663 // print the seconds
7665 strcpy(tmp,NOX("0"));
7666 strcat(time_str,tmp);
7668 sprintf(tmp,"%d",seconds);
7669 strcat(time_str,tmp);
7672 // Stuff version string in *str.
7673 void get_version_string(char *str)
7676 if ( FS_VERSION_BUILD == 0 ) {
7677 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7679 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7682 #if defined (FS2_DEMO)
7684 #elif defined (OEM_BUILD)
7685 strcat(str, " (OEM)");
7691 char myname[_MAX_PATH];
7692 int namelen, major, minor, build, waste;
7693 unsigned int buf_size;
7699 // Find my EXE file name
7700 hMod = GetModuleHandle(NULL);
7701 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7703 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7704 infop = (char *)malloc(version_size);
7705 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7707 // get the product version
7708 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7709 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7711 sprintf(str,"Dv%d.%02d",major, minor);
7713 sprintf(str,"v%d.%02d",major, minor);
7718 void get_version_string_short(char *str)
7720 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7723 // ----------------------------------------------------------------
7725 // OEM UPSELL SCREENS BEGIN
7727 // ----------------------------------------------------------------
7728 #if defined(OEM_BUILD)
7730 #define NUM_OEM_UPSELL_SCREENS 3
7731 #define OEM_UPSELL_SCREEN_DELAY 10000
7733 static int Oem_upsell_bitmaps_loaded = 0;
7734 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7735 static int Oem_upsell_screen_number = 0;
7736 static int Oem_upsell_show_next_bitmap_time;
7739 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7752 static int Oem_normal_cursor = -1;
7753 static int Oem_web_cursor = -1;
7754 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7755 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7757 void oem_upsell_next_screen()
7759 Oem_upsell_screen_number++;
7760 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7761 // extra long delay, mouse shown on last upsell
7762 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7766 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7770 void oem_upsell_load_bitmaps()
7774 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7775 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7779 void oem_upsell_unload_bitmaps()
7783 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7784 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7785 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7790 Oem_upsell_bitmaps_loaded = 0;
7793 // clickable hotspot on 3rd OEM upsell screen
7794 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7796 28, 350, 287, 96 // x, y, w, h
7799 45, 561, 460, 152 // x, y, w, h
7803 void oem_upsell_show_screens()
7805 int current_time, k;
7808 if ( !Oem_upsell_bitmaps_loaded ) {
7809 oem_upsell_load_bitmaps();
7810 Oem_upsell_bitmaps_loaded = 1;
7813 // may use upsell screens more than once
7814 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7815 Oem_upsell_screen_number = 0;
7821 int nframes; // used to pass, not really needed (should be 1)
7822 Oem_normal_cursor = gr_get_cursor_bitmap();
7823 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7824 Assert(Oem_web_cursor >= 0);
7825 if (Oem_web_cursor < 0) {
7826 Oem_web_cursor = Oem_normal_cursor;
7831 //oem_reset_trailer_timer();
7833 current_time = timer_get_milliseconds();
7838 // advance screen on keypress or timeout
7839 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7840 oem_upsell_next_screen();
7843 // check if we are done
7844 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7845 Oem_upsell_screen_number--;
7848 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7853 // show me the upsell
7854 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7855 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7859 // if this is the 3rd upsell, make it clickable, d00d
7860 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7862 int button_state = mouse_get_pos(&mx, &my);
7863 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])
7864 && (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]) )
7867 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7870 if (button_state & MOUSE_LEFT_BUTTON) {
7872 multi_pxo_url(OEM_UPSELL_URL);
7876 // switch cursor back to normal one
7877 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7882 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7892 oem_upsell_unload_bitmaps();
7894 // switch cursor back to normal one
7895 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7899 #endif // defined(OEM_BUILD)
7900 // ----------------------------------------------------------------
7902 // OEM UPSELL SCREENS END
7904 // ----------------------------------------------------------------
7908 // ----------------------------------------------------------------
7910 // DEMO UPSELL SCREENS BEGIN
7912 // ----------------------------------------------------------------
7916 //#define NUM_DEMO_UPSELL_SCREENS 4
7918 #define NUM_DEMO_UPSELL_SCREENS 2
7919 #define DEMO_UPSELL_SCREEN_DELAY 3000
7921 static int Demo_upsell_bitmaps_loaded = 0;
7922 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7923 static int Demo_upsell_screen_number = 0;
7924 static int Demo_upsell_show_next_bitmap_time;
7927 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7940 void demo_upsell_next_screen()
7942 Demo_upsell_screen_number++;
7943 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7944 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7946 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7950 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7951 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7952 #ifndef HARDWARE_ONLY
7953 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7960 void demo_upsell_load_bitmaps()
7964 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7965 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7969 void demo_upsell_unload_bitmaps()
7973 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7974 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7975 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7980 Demo_upsell_bitmaps_loaded = 0;
7983 void demo_upsell_show_screens()
7985 int current_time, k;
7988 if ( !Demo_upsell_bitmaps_loaded ) {
7989 demo_upsell_load_bitmaps();
7990 Demo_upsell_bitmaps_loaded = 1;
7993 // may use upsell screens more than once
7994 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7995 Demo_upsell_screen_number = 0;
8002 demo_reset_trailer_timer();
8004 current_time = timer_get_milliseconds();
8011 // don't time out, wait for keypress
8013 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8014 demo_upsell_next_screen();
8019 demo_upsell_next_screen();
8022 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8023 Demo_upsell_screen_number--;
8026 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8031 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8032 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8037 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8047 demo_upsell_unload_bitmaps();
8052 // ----------------------------------------------------------------
8054 // DEMO UPSELL SCREENS END
8056 // ----------------------------------------------------------------
8059 // ----------------------------------------------------------------
8061 // Subspace Ambient Sound START
8063 // ----------------------------------------------------------------
8065 static int Subspace_ambient_left_channel = -1;
8066 static int Subspace_ambient_right_channel = -1;
8069 void game_start_subspace_ambient_sound()
8071 if ( Subspace_ambient_left_channel < 0 ) {
8072 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8075 if ( Subspace_ambient_right_channel < 0 ) {
8076 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8080 void game_stop_subspace_ambient_sound()
8082 if ( Subspace_ambient_left_channel >= 0 ) {
8083 snd_stop(Subspace_ambient_left_channel);
8084 Subspace_ambient_left_channel = -1;
8087 if ( Subspace_ambient_right_channel >= 0 ) {
8088 snd_stop(Subspace_ambient_right_channel);
8089 Subspace_ambient_right_channel = -1;
8093 // ----------------------------------------------------------------
8095 // Subspace Ambient Sound END
8097 // ----------------------------------------------------------------
8099 // ----------------------------------------------------------------
8101 // CDROM detection code START
8103 // ----------------------------------------------------------------
8105 #define CD_SIZE_72_MINUTE_MAX (697000000)
8107 uint game_get_cd_used_space(char *path)
8111 char use_path[512] = "";
8112 char sub_path[512] = "";
8113 WIN32_FIND_DATA find;
8116 // recurse through all files and directories
8117 strcpy(use_path, path);
8118 strcat(use_path, "*.*");
8119 find_handle = FindFirstFile(use_path, &find);
8122 if(find_handle == INVALID_HANDLE_VALUE){
8128 // subdirectory. make sure to ignore . and ..
8129 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8131 strcpy(sub_path, path);
8132 strcat(sub_path, find.cFileName);
8133 strcat(sub_path, "\\");
8134 total += game_get_cd_used_space(sub_path);
8136 total += (uint)find.nFileSizeLow;
8138 } while(FindNextFile(find_handle, &find));
8141 FindClose(find_handle);
8153 // if volume_name is non-null, the CD name must match that
8154 int find_freespace_cd(char *volume_name)
8157 char oldpath[MAX_PATH];
8161 int volume_match = 0;
8165 GetCurrentDirectory(MAX_PATH, oldpath);
8167 for (i = 0; i < 26; i++)
8173 path[0] = (char)('A'+i);
8174 if (GetDriveType(path) == DRIVE_CDROM) {
8176 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8177 nprintf(("CD", "CD volume: %s\n", volume));
8179 // check for any CD volume
8180 int volume1_present = 0;
8181 int volume2_present = 0;
8182 int volume3_present = 0;
8184 char full_check[512] = "";
8186 // look for setup.exe
8187 strcpy(full_check, path);
8188 strcat(full_check, "setup.exe");
8189 find_handle = _findfirst(full_check, &find);
8190 if(find_handle != -1){
8191 volume1_present = 1;
8192 _findclose(find_handle);
8195 // look for intro.mve
8196 strcpy(full_check, path);
8197 strcat(full_check, "intro.mve");
8198 find_handle = _findfirst(full_check, &find);
8199 if(find_handle != -1){
8200 volume2_present = 1;
8201 _findclose(find_handle);
8204 // look for endpart1.mve
8205 strcpy(full_check, path);
8206 strcat(full_check, "endpart1.mve");
8207 find_handle = _findfirst(full_check, &find);
8208 if(find_handle != -1){
8209 volume3_present = 1;
8210 _findclose(find_handle);
8213 // see if we have the specific CD we're looking for
8214 if ( volume_name ) {
8216 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8220 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8224 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8228 if ( volume1_present || volume2_present || volume3_present ) {
8233 // 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
8234 if ( volume_match ){
8236 // 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
8237 if(volume2_present || volume3_present) {
8238 // first step - check to make sure its a cdrom
8239 if(GetDriveType(path) != DRIVE_CDROM){
8243 #if !defined(OEM_BUILD)
8244 // oem not on 80 min cds, so dont check tha size
8246 uint used_space = game_get_cd_used_space(path);
8247 if(used_space < CD_SIZE_72_MINUTE_MAX){
8250 #endif // !defined(OEM_BUILD)
8258 #endif // RELEASE_REAL
8264 SetCurrentDirectory(oldpath);
8273 int set_cdrom_path(int drive_num)
8277 if (drive_num < 0) { //no CD
8279 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8282 strcpy(Game_CDROM_dir,""); //set directory
8286 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8302 i = find_freespace_cd();
8304 rval = set_cdrom_path(i);
8308 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8310 nprintf(("CD", "FreeSpace CD not found\n"));
8318 int Last_cd_label_found = 0;
8319 char Last_cd_label[256];
8321 int game_cd_changed()
8328 if ( strlen(Game_CDROM_dir) == 0 ) {
8332 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8334 if ( found != Last_cd_label_found ) {
8335 Last_cd_label_found = found;
8337 mprintf(( "CD '%s' was inserted\n", label ));
8340 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8344 if ( Last_cd_label_found ) {
8345 if ( !stricmp( Last_cd_label, label )) {
8346 //mprintf(( "CD didn't change\n" ));
8348 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8352 // none found before, none found now.
8353 //mprintf(( "still no CD...\n" ));
8357 Last_cd_label_found = found;
8359 strcpy( Last_cd_label, label );
8361 strcpy( Last_cd_label, "" );
8372 // check if _any_ FreeSpace2 CDs are in the drive
8373 // return: 1 => CD now in drive
8374 // 0 => Could not find CD, they refuse to put it in the drive
8375 int game_do_cd_check(char *volume_name)
8377 #if !defined(GAME_CD_CHECK)
8383 int num_attempts = 0;
8384 int refresh_files = 0;
8386 int path_set_ok, popup_rval;
8388 cd_drive_num = find_freespace_cd(volume_name);
8389 path_set_ok = set_cdrom_path(cd_drive_num);
8390 if ( path_set_ok ) {
8392 if ( refresh_files ) {
8404 // no CD found, so prompt user
8405 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8407 if ( popup_rval != 1 ) {
8412 if ( num_attempts++ > 5 ) {
8423 // check if _any_ FreeSpace2 CDs are in the drive
8424 // return: 1 => CD now in drive
8425 // 0 => Could not find CD, they refuse to put it in the drive
8426 int game_do_cd_check_specific(char *volume_name, int cdnum)
8431 int num_attempts = 0;
8432 int refresh_files = 0;
8434 int path_set_ok, popup_rval;
8436 cd_drive_num = find_freespace_cd(volume_name);
8437 path_set_ok = set_cdrom_path(cd_drive_num);
8438 if ( path_set_ok ) {
8440 if ( refresh_files ) {
8451 // no CD found, so prompt user
8452 #if defined(DVD_MESSAGE_HACK)
8453 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8455 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8458 if ( popup_rval != 1 ) {
8463 if ( num_attempts++ > 5 ) {
8473 // only need to do this in RELEASE_REAL
8474 int game_do_cd_mission_check(char *filename)
8480 fs_builtin_mission *m = game_find_builtin_mission(filename);
8482 // check for changed CD
8483 if(game_cd_changed()){
8488 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8492 // not builtin, so do a general check (any FS2 CD will do)
8494 return game_do_cd_check();
8497 // does not have any CD requirement, do a general check
8498 if(strlen(m->cd_volume) <= 0){
8499 return game_do_cd_check();
8503 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8505 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8507 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8510 return game_do_cd_check();
8513 // did we find the cd?
8514 if(find_freespace_cd(m->cd_volume) >= 0){
8518 // make sure the volume exists
8519 int num_attempts = 0;
8520 int refresh_files = 0;
8522 int path_set_ok, popup_rval;
8524 cd_drive_num = find_freespace_cd(m->cd_volume);
8525 path_set_ok = set_cdrom_path(cd_drive_num);
8526 if ( path_set_ok ) {
8528 if ( refresh_files ) {
8535 // no CD found, so prompt user
8536 #if defined(DVD_MESSAGE_HACK)
8537 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8539 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8543 if ( popup_rval != 1 ) {
8548 if ( num_attempts++ > 5 ) {
8560 // ----------------------------------------------------------------
8562 // CDROM detection code END
8564 // ----------------------------------------------------------------
8566 // ----------------------------------------------------------------
8567 // SHIPS TBL VERIFICATION STUFF
8570 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8571 #define NUM_SHIPS_TBL_CHECKSUMS 1
8574 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8575 1696074201, // FS2 demo
8579 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8580 -463907578, // US - beta 1
8581 1696074201, // FS2 demo
8584 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8585 // -1022810006, // 1.0 FULL
8586 -1254285366 // 1.2 FULL (German)
8590 void verify_ships_tbl()
8594 Game_ships_tbl_valid = 1;
8600 // detect if the packfile exists
8601 CFILE *detect = cfopen("ships.tbl", "rb");
8602 Game_ships_tbl_valid = 0;
8606 Game_ships_tbl_valid = 0;
8610 // get the long checksum of the file
8612 cfseek(detect, 0, SEEK_SET);
8613 cf_chksum_long(detect, &file_checksum);
8617 // now compare the checksum/filesize against known #'s
8618 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8619 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8620 Game_ships_tbl_valid = 1;
8627 DCF(shipspew, "display the checksum for the current ships.tbl")
8630 CFILE *detect = cfopen("ships.tbl", "rb");
8631 // get the long checksum of the file
8633 cfseek(detect, 0, SEEK_SET);
8634 cf_chksum_long(detect, &file_checksum);
8637 dc_printf("%d", file_checksum);
8640 // ----------------------------------------------------------------
8641 // WEAPONS TBL VERIFICATION STUFF
8644 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8645 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8648 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8649 -266420030, // demo 1
8653 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8654 141718090, // US - beta 1
8655 -266420030, // demo 1
8658 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8659 // 399297860, // 1.0 FULL
8660 -553984927 // 1.2 FULL (german)
8664 void verify_weapons_tbl()
8668 Game_weapons_tbl_valid = 1;
8674 // detect if the packfile exists
8675 CFILE *detect = cfopen("weapons.tbl", "rb");
8676 Game_weapons_tbl_valid = 0;
8680 Game_weapons_tbl_valid = 0;
8684 // get the long checksum of the file
8686 cfseek(detect, 0, SEEK_SET);
8687 cf_chksum_long(detect, &file_checksum);
8691 // now compare the checksum/filesize against known #'s
8692 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8693 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8694 Game_weapons_tbl_valid = 1;
8701 DCF(wepspew, "display the checksum for the current weapons.tbl")
8704 CFILE *detect = cfopen("weapons.tbl", "rb");
8705 // get the long checksum of the file
8707 cfseek(detect, 0, SEEK_SET);
8708 cf_chksum_long(detect, &file_checksum);
8711 dc_printf("%d", file_checksum);
8714 // if the game is running using hacked data
8715 int game_hacked_data()
8718 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8726 void display_title_screen()
8728 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8729 ///int title_bitmap;
8732 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8733 if (title_bitmap == -1) {
8739 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8740 extern void d3d_start_frame();
8746 gr_set_bitmap(title_bitmap);
8753 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8754 extern void d3d_stop_frame();
8762 bm_unload(title_bitmap);
8763 #endif // FS2_DEMO || OEM_BUILD
8766 // return true if the game is running with "low memory", which is less than 48MB
8767 bool game_using_low_mem()
8769 if (Use_low_mem == 0) {