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.20 2002/07/24 00:20:41 relnev
21 * Revision 1.19 2002/06/17 06:33:08 relnev
22 * ryan's struct patch for gcc 2.95
24 * Revision 1.18 2002/06/16 04:46:33 relnev
25 * set up correct checksums for demo
27 * Revision 1.17 2002/06/09 04:41:17 relnev
28 * added copyright header
30 * Revision 1.16 2002/06/09 03:16:04 relnev
33 * removed unneeded asm, old sdl 2d setup.
35 * fixed crash caused by opengl_get_region.
37 * Revision 1.15 2002/06/05 08:05:28 relnev
38 * stub/warning removal.
40 * reworked the sound code.
42 * Revision 1.14 2002/06/05 04:03:32 relnev
43 * finished cfilesystem.
45 * removed some old code.
47 * fixed mouse save off-by-one.
51 * Revision 1.13 2002/06/02 04:26:34 relnev
54 * Revision 1.12 2002/06/02 00:31:35 relnev
55 * implemented osregistry
57 * Revision 1.11 2002/06/01 09:00:34 relnev
58 * silly debug memmanager
60 * Revision 1.10 2002/06/01 07:12:32 relnev
61 * a few NDEBUG updates.
63 * removed a few warnings.
65 * Revision 1.9 2002/05/31 03:05:59 relnev
68 * Revision 1.8 2002/05/29 02:52:32 theoddone33
69 * Enable OpenGL renderer
71 * Revision 1.7 2002/05/28 08:52:03 relnev
72 * implemented two assembly stubs.
74 * cleaned up a few warnings.
76 * added a little demo hackery to make it progress a little farther.
78 * Revision 1.6 2002/05/28 06:28:20 theoddone33
79 * Filesystem mods, actually reads some data files now
81 * Revision 1.5 2002/05/28 04:07:28 theoddone33
82 * New graphics stubbing arrangement
84 * Revision 1.4 2002/05/27 22:46:52 theoddone33
85 * Remove more undefined symbols
87 * Revision 1.3 2002/05/26 23:31:18 relnev
88 * added a few files that needed to be compiled
90 * freespace.cpp: now compiles
92 * Revision 1.2 2002/05/07 03:16:44 theoddone33
93 * The Great Newline Fix
95 * Revision 1.1.1.1 2002/05/03 03:28:09 root
99 * 201 6/16/00 3:15p Jefff
100 * sim of the year dvd version changes, a few german soty localization
103 * 200 11/03/99 11:06a Jefff
106 * 199 10/26/99 5:07p Jamest
107 * fixed jeffs dumb debug code
109 * 198 10/25/99 5:53p Jefff
110 * call control_config_common_init() on startup
112 * 197 10/14/99 10:18a Daveb
113 * Fixed incorrect CD checking problem on standalone server.
115 * 196 10/13/99 9:22a Daveb
116 * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
117 * related to movies. Fixed launcher spawning from PXO screen.
119 * 195 10/06/99 11:05a Jefff
120 * new oem upsell 3 hotspot coords
122 * 194 10/06/99 10:31a Jefff
125 * 193 10/01/99 9:10a Daveb
128 * 192 9/15/99 4:57a Dave
129 * Updated ships.tbl checksum
131 * 191 9/15/99 3:58a Dave
132 * Removed framerate warning at all times.
134 * 190 9/15/99 3:16a Dave
135 * Remove mt-011.fs2 from the builtin mission list.
137 * 189 9/15/99 1:45a Dave
138 * Don't init joystick on standalone. Fixed campaign mode on standalone.
139 * Fixed no-score-report problem in TvT
141 * 188 9/14/99 6:08a Dave
142 * Updated (final) single, multi, and campaign list.
144 * 187 9/14/99 3:26a Dave
145 * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
146 * respawn-too-early problem. Made a few crash points safe.
148 * 186 9/13/99 4:52p Dave
151 * 185 9/12/99 8:09p Dave
152 * Fixed problem where skip-training button would cause mission messages
153 * not to get paged out for the current mission.
155 * 184 9/10/99 11:53a Dave
156 * Shutdown graphics before sound to eliminate apparent lockups when
157 * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
159 * 183 9/09/99 11:40p Dave
160 * Handle an Assert() in beam code. Added supernova sounds. Play the right
161 * 2 end movies properly, based upon what the player did in the mission.
163 * 182 9/08/99 10:29p Dave
164 * Make beam sound pausing and unpausing much safer.
166 * 181 9/08/99 10:01p Dave
167 * Make sure game won't run in a drive's root directory. Make sure
168 * standalone routes suqad war messages properly to the host.
170 * 180 9/08/99 3:22p Dave
171 * Updated builtin mission list.
173 * 179 9/08/99 12:01p Jefff
174 * fixed Game_builtin_mission_list typo on Training-2.fs2
176 * 178 9/08/99 9:48a Andsager
177 * Add force feedback for engine wash.
179 * 177 9/07/99 4:01p Dave
180 * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
181 * does everything properly (setting up address when binding). Remove
182 * black rectangle background from UI_INPUTBOX.
184 * 176 9/13/99 2:40a Dave
185 * Comment in full 80 minute CD check for RELEASE_REAL builds.
187 * 175 9/06/99 6:38p Dave
188 * Improved CD detection code.
190 * 174 9/06/99 1:30a Dave
191 * Intermediate checkin. Started on enforcing CD-in-drive to play the
194 * 173 9/06/99 1:16a Dave
195 * Make sure the user sees the intro movie.
197 * 172 9/04/99 8:00p Dave
198 * Fixed up 1024 and 32 bit movie support.
200 * 171 9/03/99 1:32a Dave
201 * CD checking by act. Added support to play 2 cutscenes in a row
202 * seamlessly. Fixed super low level cfile bug related to files in the
203 * root directory of a CD. Added cheat code to set campaign mission # in
206 * 170 9/01/99 10:49p Dave
207 * Added nice SquadWar checkbox to the client join wait screen.
209 * 169 9/01/99 10:14a Dave
212 * 168 8/29/99 4:51p Dave
213 * Fixed damaged checkin.
215 * 167 8/29/99 4:18p Andsager
216 * New "burst" limit for friendly damage. Also credit more damage done
217 * against large friendly ships.
219 * 166 8/27/99 6:38p Alanl
220 * crush the blasted repeating messages bug
222 * 164 8/26/99 9:09p Dave
223 * Force framerate check in everything but a RELEASE_REAL build.
225 * 163 8/26/99 9:45a Dave
226 * First pass at easter eggs and cheats.
228 * 162 8/24/99 8:55p Dave
229 * Make sure nondimming pixels work properly in tech menu.
231 * 161 8/24/99 1:49a Dave
232 * Fixed client-side afterburner stuttering. Added checkbox for no version
233 * checking on PXO join. Made button info passing more friendly between
236 * 160 8/22/99 5:53p Dave
237 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
238 * instead of ship designations for multiplayer players.
240 * 159 8/22/99 1:19p Dave
241 * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
242 * which d3d cards are detected.
244 * 158 8/20/99 2:09p Dave
245 * PXO banner cycling.
247 * 157 8/19/99 10:59a Dave
248 * Packet loss detection.
250 * 156 8/19/99 10:12a Alanl
251 * preload mission-specific messages on machines greater than 48MB
253 * 155 8/16/99 4:04p Dave
254 * Big honking checkin.
256 * 154 8/11/99 5:54p Dave
257 * Fixed collision problem. Fixed standalone ghost problem.
259 * 153 8/10/99 7:59p Jefff
262 * 152 8/10/99 6:54p Dave
263 * Mad optimizations. Added paging to the nebula effect.
265 * 151 8/10/99 3:44p Jefff
266 * loads Intelligence information on startup
268 * 150 8/09/99 3:47p Dave
269 * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
270 * non-nebula missions.
272 * 149 8/09/99 2:21p Andsager
273 * Fix patching from multiplayer direct to launcher update tab.
275 * 148 8/09/99 10:36a Dave
276 * Version info for game.
278 * 147 8/06/99 9:46p Dave
279 * Hopefully final changes for the demo.
281 * 146 8/06/99 3:34p Andsager
282 * Make title version info "(D)" -> "D" show up nicely
284 * 145 8/06/99 2:59p Adamp
285 * Fixed NT launcher/update problem.
287 * 144 8/06/99 1:52p Dave
288 * Bumped up MAX_BITMAPS for the demo.
290 * 143 8/06/99 12:17p Andsager
291 * Demo: down to just 1 demo dog
293 * 142 8/05/99 9:39p Dave
294 * Yet another new checksum.
296 * 141 8/05/99 6:19p Dave
297 * New demo checksums.
299 * 140 8/05/99 5:31p Andsager
300 * Up demo version 1.01
302 * 139 8/05/99 4:22p Andsager
303 * No time limit on upsell screens. Reverse order of display of upsell
306 * 138 8/05/99 4:17p Dave
307 * Tweaks to client interpolation.
309 * 137 8/05/99 3:52p Danw
311 * 136 8/05/99 3:01p Danw
313 * 135 8/05/99 2:43a Anoop
314 * removed duplicate definition.
316 * 134 8/05/99 2:13a Dave
319 * 133 8/05/99 2:05a Dave
322 * 132 8/05/99 1:22a Andsager
325 * 131 8/04/99 9:51p Andsager
326 * Add title screen to demo
328 * 130 8/04/99 6:47p Jefff
329 * fixed link error resulting from #ifdefs
331 * 129 8/04/99 6:26p Dave
332 * Updated ship tbl checksum.
334 * 128 8/04/99 5:40p Andsager
335 * Add multiple demo dogs
337 * 127 8/04/99 5:36p Andsager
338 * Show upsell screens at end of demo campaign before returning to main
341 * 126 8/04/99 11:42a Danw
342 * tone down EAX reverb
344 * 125 8/04/99 11:23a Dave
345 * Updated demo checksums.
347 * 124 8/03/99 11:02p Dave
348 * Maybe fixed sync problems in multiplayer.
350 * 123 8/03/99 6:21p Jefff
353 * 122 8/03/99 3:44p Andsager
354 * Launch laucher if trying to run FS without first having configured
357 * 121 8/03/99 12:45p Dave
360 * 120 8/02/99 9:13p Dave
363 * 119 7/30/99 10:31p Dave
364 * Added comm menu to the configurable hud files.
366 * 118 7/30/99 5:17p Andsager
367 * first fs2demo checksums
369 * 117 7/29/99 3:09p Anoop
371 * 116 7/29/99 12:05a Dave
372 * Nebula speed optimizations.
374 * 115 7/27/99 8:59a Andsager
375 * Make major, minor version consistent for all builds. Only show major
376 * and minor for launcher update window.
378 * 114 7/26/99 5:50p Dave
379 * Revised ingame join. Better? We'll see....
381 * 113 7/26/99 5:27p Andsager
382 * Add training mission as builtin to demo build
384 * 112 7/24/99 1:54p Dave
385 * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
388 * 111 7/22/99 4:00p Dave
389 * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
391 * 110 7/21/99 8:10p Dave
392 * First run of supernova effect.
394 * 109 7/20/99 1:49p Dave
395 * Peter Drake build. Fixed some release build warnings.
397 * 108 7/19/99 2:26p Andsager
398 * set demo multiplayer missions
400 * 107 7/18/99 5:19p Dave
401 * Jump node icon. Fixed debris fogging. Framerate warning stuff.
403 * 106 7/16/99 1:50p Dave
404 * 8 bit aabitmaps. yay.
406 * 105 7/15/99 3:07p Dave
407 * 32 bit detection support. Mouse coord commandline.
409 * 104 7/15/99 2:13p Dave
410 * Added 32 bit detection.
412 * 103 7/15/99 9:20a Andsager
413 * FS2_DEMO initial checkin
415 * 102 7/14/99 11:02a Dave
416 * Skill level default back to easy. Blech.
418 * 101 7/09/99 5:54p Dave
419 * Seperated cruiser types into individual types. Added tons of new
420 * briefing icons. Campaign screen.
422 * 100 7/08/99 4:43p Andsager
423 * New check for sparky_hi and print if not found.
425 * 99 7/08/99 10:53a Dave
426 * New multiplayer interpolation scheme. Not 100% done yet, but still
427 * better than the old way.
429 * 98 7/06/99 4:24p Dave
430 * Mid-level checkin. Starting on some potentially cool multiplayer
433 * 97 7/06/99 3:35p Andsager
434 * Allow movie to play before red alert mission.
436 * 96 7/03/99 5:50p Dave
437 * Make rotated bitmaps draw properly in padlock views.
439 * 95 7/02/99 9:55p Dave
440 * Player engine wash sound.
442 * 94 7/02/99 4:30p Dave
443 * Much more sophisticated lightning support.
445 * 93 6/29/99 7:52p Dave
446 * Put in exception handling in FS2.
448 * 92 6/22/99 9:37p Dave
449 * Put in pof spewing.
451 * 91 6/16/99 4:06p Dave
452 * New pilot info popup. Added new draw-bitmap-as-poly function.
454 * 90 6/15/99 1:56p Andsager
455 * For release builds, allow start up in high res only with
458 * 89 6/15/99 9:34a Dave
459 * Fixed key checking in single threaded version of the stamp notification
462 * 88 6/09/99 2:55p Andsager
463 * Allow multiple asteroid subtypes (of large, medium, small) and follow
466 * 87 6/08/99 1:14a Dave
467 * Multi colored hud test.
469 * 86 6/04/99 9:52a Dave
470 * Fixed some rendering problems.
472 * 85 6/03/99 10:15p Dave
473 * Put in temporary main hall screen.
475 * 84 6/02/99 6:18p Dave
476 * Fixed TNT lockup problems! Wheeeee!
478 * 83 6/01/99 3:52p Dave
479 * View footage screen. Fixed xstrings to not display the & symbol. Popup,
480 * dead popup, pxo find player popup, pxo private room popup.
482 * 82 5/26/99 1:28p Jasenw
483 * changed coords for loading ani
485 * 81 5/26/99 11:46a Dave
486 * Added ship-blasting lighting and made the randomization of lighting
487 * much more customizable.
489 * 80 5/24/99 5:45p Dave
490 * Added detail levels to the nebula, with a decent speedup. Split nebula
491 * lightning into its own section.
509 #include "systemvars.h"
514 #include "starfield.h"
515 #include "lighting.h"
520 #include "fireballs.h"
524 #include "floating.h"
525 #include "gamesequence.h"
527 #include "optionsmenu.h"
528 #include "playermenu.h"
529 #include "trainingmenu.h"
530 #include "techmenu.h"
533 #include "hudmessage.h"
535 #include "missiongoals.h"
536 #include "missionparse.h"
541 #include "multiutil.h"
542 #include "multimsgs.h"
546 #include "freespace.h"
547 #include "managepilot.h"
549 #include "contexthelp.h"
552 #include "missionbrief.h"
553 #include "missiondebrief.h"
555 #include "missionshipchoice.h"
557 #include "hudconfig.h"
558 #include "controlsconfig.h"
559 #include "missionmessage.h"
560 #include "missiontraining.h"
562 #include "hudtarget.h"
566 #include "eventmusic.h"
567 #include "animplay.h"
568 #include "missionweaponchoice.h"
569 #include "missionlog.h"
570 #include "audiostr.h"
572 #include "missioncampaign.h"
574 #include "missionhotkey.h"
575 #include "objectsnd.h"
576 #include "cmeasure.h"
578 #include "linklist.h"
579 #include "shockwave.h"
580 #include "afterburner.h"
585 #include "stand_gui.h"
586 #include "pcxutils.h"
587 #include "hudtargetbox.h"
588 #include "multi_xfer.h"
589 #include "hudescort.h"
590 #include "multiutil.h"
593 #include "multiteamselect.h"
596 #include "readyroom.h"
597 #include "mainhallmenu.h"
598 #include "multilag.h"
600 #include "particle.h"
602 #include "multi_ingame.h"
603 #include "snazzyui.h"
604 #include "asteroid.h"
605 #include "popupdead.h"
606 #include "multi_voice.h"
607 #include "missioncmdbrief.h"
608 #include "redalert.h"
609 #include "gameplayhelp.h"
610 #include "multilag.h"
611 #include "staticrand.h"
612 #include "multi_pmsg.h"
613 #include "levelpaging.h"
614 #include "observer.h"
615 #include "multi_pause.h"
616 #include "multi_endgame.h"
617 #include "cutscenes.h"
618 #include "multi_respawn.h"
620 #include "multi_obj.h"
621 #include "multi_log.h"
623 #include "localize.h"
624 #include "osregistry.h"
625 #include "barracks.h"
626 #include "missionpause.h"
628 #include "alphacolors.h"
629 #include "objcollide.h"
632 #include "neblightning.h"
633 #include "shipcontrails.h"
636 #include "multi_dogfight.h"
637 #include "multi_rate.h"
638 #include "muzzleflash.h"
642 #include "mainhalltemp.h"
643 #include "exceptionhandler.h"
647 #include "supernova.h"
648 #include "hudshield.h"
649 // #include "names.h"
651 #include "missionloopbrief.h"
655 #error macro FRED is defined when trying to build release Fred. Please undefine FRED macro in build settings
661 // 1.00.04 5/26/98 MWA -- going final (12 pm)
662 // 1.00.03 5/26/98 MWA -- going final (3 am)
663 // 1.00.02 5/25/98 MWA -- going final
664 // 1.00.01 5/25/98 MWA -- going final
665 // 0.90 5/21/98 MWA -- getting ready for final.
666 // 0.10 4/9/98. Set by MK.
668 // Demo version: (obsolete since DEMO codebase split from tree)
669 // 0.03 4/10/98 AL. Interplay rev
670 // 0.02 4/8/98 MK. Increased when this system was modified.
671 // 0.01 4/7/98? AL. First release to Interplay QA.
674 // 1.00 5/28/98 AL. First release to Interplay QA.
676 void game_level_init(int seed = -1);
677 void game_post_level_init();
678 void game_do_frame();
679 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
680 void game_reset_time();
681 void game_show_framerate(); // draws framerate in lower right corner
683 int Game_no_clear = 0;
685 int Pofview_running = 0;
686 int Nebedit_running = 0;
688 typedef struct big_expl_flash {
689 float max_flash_intensity; // max intensity
690 float cur_flash_intensity; // cur intensity
691 int flash_start; // start time
694 #define FRAME_FILTER 16
696 #define DEFAULT_SKILL_LEVEL 1
697 int Game_skill_level = DEFAULT_SKILL_LEVEL;
699 #define VIEWER_ZOOM_DEFAULT 0.75f // Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
700 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
702 #define EXE_FNAME ("fs2.exe")
703 #define LAUNCHER_FNAME ("freespace2.exe")
705 // JAS: Code for warphole camera.
706 // Needs to be cleaned up.
707 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
708 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
709 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
710 matrix Camera_orient = IDENTITY_MATRIX;
711 float Camera_damping = 1.0f;
712 float Camera_time = 0.0f;
713 float Warpout_time = 0.0f;
714 int Warpout_forced = 0; // Set if this is a forced warpout that cannot be cancelled.
715 int Warpout_sound = -1;
717 int Use_joy_mouse = 0;
718 int Use_palette_flash = 1;
720 int Use_fullscreen_at_startup = 0;
722 int Show_area_effect = 0;
723 object *Last_view_target = NULL;
725 int dogfight_blown = 0;
728 float frametimes[FRAME_FILTER];
729 float frametotal = 0.0f;
733 int Show_framerate = 0;
735 int Show_framerate = 1;
738 int Framerate_cap = 120;
741 int Show_target_debug_info = 0;
742 int Show_target_weapons = 0;
746 static int Show_player_pos = 0; // debug console command to show player world pos on HUD
749 int Debug_octant = -1;
751 fix Game_time_compression = F1_0;
753 // if the ships.tbl the player has is valid
754 int Game_ships_tbl_valid = 0;
756 // if the weapons.tbl the player has is valid
757 int Game_weapons_tbl_valid = 0;
761 extern int Player_attacking_enabled;
765 int Pre_player_entry;
767 int Fred_running = 0;
768 char Game_current_mission_filename[MAX_FILENAME_LEN];
769 int game_single_step = 0;
770 int last_single_step=0;
772 extern int MSG_WINDOW_X_START; // used to position mission_time and shields output
773 extern int MSG_WINDOW_Y_START;
774 extern int MSG_WINDOW_HEIGHT;
776 int game_zbuffer = 1;
777 //static int Game_music_paused;
778 static int Game_paused;
782 #define EXPIRE_BAD_CHECKSUM 1
783 #define EXPIRE_BAD_TIME 2
785 extern void ssm_init();
786 extern void ssm_level_init();
787 extern void ssm_process();
789 // static variable to contain the time this version was built
790 // commented out for now until
791 // I figure out how to get the username into the file
792 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
794 // defines and variables used for dumping frame for making trailers.
796 int Debug_dump_frames = 0; // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
797 int Debug_dump_trigger = 0;
798 int Debug_dump_frame_count;
799 int Debug_dump_frame_num = 0;
800 #define DUMP_BUFFER_NUM_FRAMES 1 // store every 15 frames
803 // amount of time to wait after the player has died before we display the death died popup
804 #define PLAYER_DIED_POPUP_WAIT 2500
805 int Player_died_popup_wait = -1;
806 int Player_multi_died_check = -1;
808 // builtin mission list stuff
810 int Game_builtin_mission_count = 6;
811 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
812 { "SPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
813 { "SPDemo-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
814 { "DemoTrain.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), "" },
815 { "Demo.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
816 { "MPDemo-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
817 { "Demo-DOG-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
819 #elif defined(PD_BUILD)
820 int Game_builtin_mission_count = 4;
821 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
822 { "sm1-01.fs2", (FSB_FROM_VOLITION), "" },
823 { "sm1-05.fs2", (FSB_FROM_VOLITION), "" },
824 { "sm1-01", (FSB_FROM_VOLITION), "" },
825 { "sm1-05", (FSB_FROM_VOLITION), "" },
827 #elif defined(MULTIPLAYER_BETA)
828 int Game_builtin_mission_count = 17;
829 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
831 { "md-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
832 { "md-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
833 { "md-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
834 { "md-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
835 { "md-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
836 { "md-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
837 { "md-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
838 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
839 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
840 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
841 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
842 { "m-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
843 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
844 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
845 { "templar-03a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
846 { "templar-04a.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
847 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
849 #elif defined(OEM_BUILD)
850 int Game_builtin_mission_count = 17;
851 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
852 // oem version - act 1 only
853 { "freespace2oem.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
856 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
857 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
858 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
859 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
860 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
861 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
862 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
863 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
864 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
865 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
866 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
867 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
868 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
869 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
870 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 },
871 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_1 }
874 int Game_builtin_mission_count = 92;
875 fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
876 // single player campaign
877 { "freespace2.fc2", (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE), "" },
880 { "sm1-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
881 { "sm1-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
882 { "sm1-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
883 { "sm1-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
884 { "sm1-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
885 { "sm1-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
886 { "sm1-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
887 { "sm1-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
888 { "sm1-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
889 { "sm1-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
890 { "loop1-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
891 { "loop1-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
892 { "loop1-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
893 { "training-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
894 { "training-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
895 { "training-3.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
896 { "tsm-104.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
897 { "tsm-105.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
898 { "tsm-106.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_2 },
901 { "sm2-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
902 { "sm2-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
903 { "sm2-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
904 { "sm2-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
905 { "sm2-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
906 { "sm2-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
907 { "sm2-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
908 { "sm2-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
909 { "sm2-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
910 { "sm2-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
913 { "sm3-01.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
914 { "sm3-02.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
915 { "sm3-03.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
916 { "sm3-04.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
917 { "sm3-05.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
918 { "sm3-06.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
919 { "sm3-07.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
920 { "sm3-08.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
921 { "sm3-09.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
922 { "sm3-10.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
923 { "loop2-1.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
924 { "loop2-2.fs2", (FSB_FROM_VOLITION | FSB_CAMPAIGN), FS_CDROM_VOLUME_3 },
926 // multiplayer missions
929 { "g-shi.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
930 { "g-ter.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
931 { "g-vas.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
934 { "m-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
935 { "m-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
936 { "m-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
937 { "m-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
940 { "mdh-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
941 { "mdh-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
942 { "mdh-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
943 { "mdh-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
944 { "mdh-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
945 { "mdh-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
946 { "mdh-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
947 { "mdh-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
948 { "mdh-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
949 { "mdl-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
950 { "mdl-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
951 { "mdl-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
952 { "mdl-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
953 { "mdl-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
954 { "mdl-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
955 { "mdl-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
956 { "mdl-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
957 { "mdl-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
958 { "mdm-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
959 { "mdm-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
960 { "mdm-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
961 { "mdm-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
962 { "mdm-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
963 { "mdm-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
964 { "mdm-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
965 { "mdm-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
966 { "mdm-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
967 { "osdog.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
970 { "mt-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
971 { "mt-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
972 { "mt-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
973 { "mt-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
974 { "mt-05.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
975 { "mt-06.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
976 { "mt-07.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
977 { "mt-08.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
978 { "mt-09.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
979 { "mt-10.fs2", (FSB_FROM_VOLITION | FSB_MULTI), "" },
982 { "templar.fc2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE), "" },
983 { "templar-01.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
984 { "templar-02.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
985 { "templar-03.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
986 { "templar-04.fs2", (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN), "" },
991 // Internal function prototypes
992 void game_maybe_draw_mouse(float frametime);
993 void init_animating_pointer();
994 void load_animating_pointer(char *filename, int dx, int dy);
995 void unload_animating_pointer();
996 void game_do_training_checks();
997 void game_shutdown(void);
998 void game_show_event_debug(float frametime);
999 void game_event_debug_init();
1001 void demo_upsell_show_screens();
1002 void game_start_subspace_ambient_sound();
1003 void game_stop_subspace_ambient_sound();
1004 void verify_ships_tbl();
1005 void verify_weapons_tbl();
1006 void display_title_screen();
1008 // loading background filenames
1009 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
1010 "LoadingBG", // GR_640
1011 "2_LoadingBG" // GR_1024
1015 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
1016 "Loading.ani", // GR_640
1017 "2_Loading.ani" // GR_1024
1020 #if defined(FS2_DEMO)
1021 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1025 #elif defined(OEM_BUILD)
1026 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
1033 char Game_CDROM_dir[MAX_PATH_LEN];
1036 // How much RAM is on this machine. Set in WinMain
1037 uint Freespace_total_ram = 0;
1040 float Game_flash_red = 0.0f;
1041 float Game_flash_green = 0.0f;
1042 float Game_flash_blue = 0.0f;
1043 float Sun_spot = 0.0f;
1044 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
1046 // game shudder stuff (in ms)
1047 int Game_shudder_time = -1;
1048 int Game_shudder_total = 0;
1049 float Game_shudder_intensity = 0.0f; // should be between 0.0 and 100.0
1052 sound_env Game_sound_env;
1053 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
1054 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
1056 int Game_sound_env_update_timestamp;
1058 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
1061 // WARPIN CRAP END --------------------------------------------------------------------------------------------
1063 fs_builtin_mission *game_find_builtin_mission(char *filename)
1067 // look through all existing builtin missions
1068 for(idx=0; idx<Game_builtin_mission_count; idx++){
1069 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
1070 return &Game_builtin_mission_list[idx];
1078 int game_get_default_skill_level()
1080 return DEFAULT_SKILL_LEVEL;
1084 void game_flash_reset()
1086 Game_flash_red = 0.0f;
1087 Game_flash_green = 0.0f;
1088 Game_flash_blue = 0.0f;
1090 Big_expl_flash.max_flash_intensity = 0.0f;
1091 Big_expl_flash.cur_flash_intensity = 0.0f;
1092 Big_expl_flash.flash_start = 0;
1095 float Gf_critical = -1.0f; // framerate we should be above on the average for this mission
1096 float Gf_critical_time = 0.0f; // how much time we've been at the critical framerate
1098 void game_framerate_check_init()
1100 // zero critical time
1101 Gf_critical_time = 0.0f;
1104 if(The_mission.flags & MISSION_FLAG_FULLNEB){
1105 // if this is a glide card
1106 if(gr_screen.mode == GR_GLIDE){
1108 extern GrHwConfiguration hwconfig;
1111 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1112 Gf_critical = 15.0f;
1116 Gf_critical = 10.0f;
1121 Gf_critical = 15.0f;
1124 // d3d. only care about good cards here I guess (TNT)
1126 Gf_critical = 15.0f;
1129 // if this is a glide card
1130 if(gr_screen.mode == GR_GLIDE){
1132 extern GrHwConfiguration hwconfig;
1135 if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1136 Gf_critical = 25.0f;
1140 Gf_critical = 20.0f;
1145 Gf_critical = 25.0f;
1148 // d3d. only care about good cards here I guess (TNT)
1150 Gf_critical = 25.0f;
1155 extern float Framerate;
1156 void game_framerate_check()
1160 // if the current framerate is above the critical level, add frametime
1161 if(Framerate >= Gf_critical){
1162 Gf_critical_time += flFrametime;
1165 if(!Show_framerate){
1169 // display if we're above the critical framerate
1170 if(Framerate < Gf_critical){
1171 gr_set_color_fast(&Color_bright_red);
1172 gr_string(200, y_start, "Framerate warning");
1177 // display our current pct of good frametime
1178 if(f2fl(Missiontime) >= 0.0f){
1179 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1182 gr_set_color_fast(&Color_bright_green);
1184 gr_set_color_fast(&Color_bright_red);
1187 gr_printf(200, y_start, "%d%%", (int)pct);
1194 // Adds a flash effect. These can be positive or negative.
1195 // The range will get capped at around -1 to 1, so stick
1196 // with a range like that.
1197 void game_flash( float r, float g, float b )
1199 Game_flash_red += r;
1200 Game_flash_green += g;
1201 Game_flash_blue += b;
1203 if ( Game_flash_red < -1.0f ) {
1204 Game_flash_red = -1.0f;
1205 } else if ( Game_flash_red > 1.0f ) {
1206 Game_flash_red = 1.0f;
1209 if ( Game_flash_green < -1.0f ) {
1210 Game_flash_green = -1.0f;
1211 } else if ( Game_flash_green > 1.0f ) {
1212 Game_flash_green = 1.0f;
1215 if ( Game_flash_blue < -1.0f ) {
1216 Game_flash_blue = -1.0f;
1217 } else if ( Game_flash_blue > 1.0f ) {
1218 Game_flash_blue = 1.0f;
1223 // Adds a flash for Big Ship explosions
1224 // cap range from 0 to 1
1225 void big_explosion_flash(float flash)
1227 Big_expl_flash.flash_start = timestamp(1);
1231 } else if (flash < 0.0f) {
1235 Big_expl_flash.max_flash_intensity = flash;
1236 Big_expl_flash.cur_flash_intensity = 0.0f;
1239 // Amount to diminish palette towards normal, per second.
1240 #define DIMINISH_RATE 0.75f
1241 #define SUN_DIMINISH_RATE 6.00f
1245 float sn_glare_scale = 1.7f;
1248 dc_get_arg(ARG_FLOAT);
1249 sn_glare_scale = Dc_arg_float;
1252 float Supernova_last_glare = 0.0f;
1253 void game_sunspot_process(float frametime)
1257 float Sun_spot_goal = 0.0f;
1260 sn_stage = supernova_active();
1262 // sunspot differently based on supernova stage
1264 // approaching. player still in control
1267 pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1270 light_get_global_dir(&light_dir, 0);
1272 dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec );
1275 // scale it some more
1276 dot = dot * (0.5f + (pct * 0.5f));
1279 Sun_spot_goal += (dot * sn_glare_scale);
1282 // draw the sun glow
1283 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) ) {
1284 // draw the glow for this sun
1285 stars_draw_sun_glow(0);
1288 Supernova_last_glare = Sun_spot_goal;
1291 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1294 Sun_spot_goal = 0.9f;
1295 Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1297 if(Sun_spot_goal > 1.0f){
1298 Sun_spot_goal = 1.0f;
1301 Sun_spot_goal *= sn_glare_scale;
1302 Supernova_last_glare = Sun_spot_goal;
1305 // fade to white. display dead popup
1308 Supernova_last_glare += (2.0f * flFrametime);
1309 if(Supernova_last_glare > 2.0f){
1310 Supernova_last_glare = 2.0f;
1313 Sun_spot_goal = Supernova_last_glare;
1320 // check sunspots for all suns
1321 n_lights = light_get_global_count();
1324 for(idx=0; idx<n_lights; idx++){
1325 //(vector *eye_pos, matrix *eye_orient)
1326 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) ) {
1329 light_get_global_dir(&light_dir, idx);
1331 float dot = vm_vec_dot( &light_dir, &Eye_matrix.v.fvec )*0.5f+0.5f;
1333 Sun_spot_goal += (float)pow(dot,85.0f);
1335 // draw the glow for this sun
1336 stars_draw_sun_glow(idx);
1338 Sun_spot_goal = 0.0f;
1344 Sun_spot_goal = 0.0f;
1348 float dec_amount = frametime*SUN_DIMINISH_RATE;
1350 if ( Sun_spot < Sun_spot_goal ) {
1351 Sun_spot += dec_amount;
1352 if ( Sun_spot > Sun_spot_goal ) {
1353 Sun_spot = Sun_spot_goal;
1355 } else if ( Sun_spot > Sun_spot_goal ) {
1356 Sun_spot -= dec_amount;
1357 if ( Sun_spot < Sun_spot_goal ) {
1358 Sun_spot = Sun_spot_goal;
1364 // Call once a frame to diminish the
1365 // flash effect to 0.
1366 void game_flash_diminish(float frametime)
1368 float dec_amount = frametime*DIMINISH_RATE;
1370 if ( Game_flash_red > 0.0f ) {
1371 Game_flash_red -= dec_amount;
1372 if ( Game_flash_red < 0.0f )
1373 Game_flash_red = 0.0f;
1375 Game_flash_red += dec_amount;
1376 if ( Game_flash_red > 0.0f )
1377 Game_flash_red = 0.0f;
1380 if ( Game_flash_green > 0.0f ) {
1381 Game_flash_green -= dec_amount;
1382 if ( Game_flash_green < 0.0f )
1383 Game_flash_green = 0.0f;
1385 Game_flash_green += dec_amount;
1386 if ( Game_flash_green > 0.0f )
1387 Game_flash_green = 0.0f;
1390 if ( Game_flash_blue > 0.0f ) {
1391 Game_flash_blue -= dec_amount;
1392 if ( Game_flash_blue < 0.0f )
1393 Game_flash_blue = 0.0f;
1395 Game_flash_blue += dec_amount;
1396 if ( Game_flash_blue > 0.0f )
1397 Game_flash_blue = 0.0f;
1400 // update big_explosion_cur_flash
1401 #define TIME_UP 1500
1402 #define TIME_DOWN 2500
1403 int duration = TIME_UP + TIME_DOWN;
1404 int time = timestamp_until(Big_expl_flash.flash_start);
1405 if (time > -duration) {
1407 if (time < TIME_UP) {
1408 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1411 Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1415 if ( Use_palette_flash ) {
1417 // static int or=0, og=0, ob=0;
1419 // Change the 200 to change the color range of colors.
1420 r = fl2i( Game_flash_red*128.0f );
1421 g = fl2i( Game_flash_green*128.0f );
1422 b = fl2i( Game_flash_blue*128.0f );
1424 if ( Sun_spot > 0.0f ) {
1425 r += fl2i(Sun_spot*128.0f);
1426 g += fl2i(Sun_spot*128.0f);
1427 b += fl2i(Sun_spot*128.0f);
1430 if ( Big_expl_flash.cur_flash_intensity > 0.0f ) {
1431 r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1432 g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1433 b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1436 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1437 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1438 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1440 if ( (r!=0) || (g!=0) || (b!=0) ) {
1441 gr_flash( r, g, b );
1443 //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1454 void game_level_close()
1456 // De-Initialize the game subsystems
1457 message_mission_shutdown();
1458 event_music_level_close();
1459 game_stop_looped_sounds();
1461 obj_snd_level_close(); // uninit object-linked persistant sounds
1462 gamesnd_unload_gameplay_sounds(); // unload gameplay sounds from memory
1463 anim_level_close(); // stop and clean up any anim instances
1464 shockwave_level_close();
1465 fireball_level_close();
1467 mission_event_shutdown();
1468 asteroid_level_close();
1469 model_cache_reset(); // Reset/free all the model caching stuff
1470 flak_level_close(); // unload flak stuff
1471 neb2_level_close(); // shutdown gaseous nebula stuff
1474 mflash_level_close();
1476 audiostream_unpause_all();
1481 // intializes game stuff and loads the mission. Returns 0 on failure, 1 on success
1482 // input: seed => DEFAULT PARAMETER (value -1). Only set by demo playback code.
1483 void game_level_init(int seed)
1485 // seed the random number generator
1487 // if no seed was passed, seed the generator either from the time value, or from the
1488 // netgame security flags -- ensures that all players in multiplayer game will have the
1489 // same randon number sequence (with static rand functions)
1490 if ( Game_mode & GM_NORMAL ) {
1491 Game_level_seed = time(NULL);
1493 Game_level_seed = Netgame.security;
1496 // mwa 9/17/98 -- maybe this assert isn't needed????
1497 Assert( !(Game_mode & GM_MULTIPLAYER) );
1498 Game_level_seed = seed;
1500 srand( Game_level_seed );
1502 // semirand function needs to get re-initted every time in multiplayer
1503 if ( Game_mode & GM_MULTIPLAYER ){
1509 Key_normal_game = (Game_mode & GM_NORMAL);
1512 Game_shudder_time = -1;
1514 // Initialize the game subsystems
1515 // timestamp_reset(); // Must be inited before everything else
1517 game_reset_time(); // resets time, and resets saved time too
1519 obj_init(); // Must be inited before the other systems
1520 model_free_all(); // Free all existing models
1521 mission_brief_common_init(); // Free all existing briefing/debriefing text
1522 weapon_level_init();
1523 ai_level_init(); // Call this before ship_init() because it reads ai.tbl.
1525 player_level_init();
1526 shipfx_flash_init(); // Init the ship gun flash system.
1527 game_flash_reset(); // Reset the flash effect
1528 particle_init(); // Reset the particle system
1532 shield_hit_init(); // Initialize system for showing shield hits
1533 radar_mission_init();
1534 mission_init_goals();
1537 obj_snd_level_init(); // init object-linked persistant sounds
1539 shockwave_level_init();
1540 afterburner_level_init();
1541 scoring_level_init( &Player->stats );
1543 asteroid_level_init();
1544 control_config_clear_used_status();
1545 collide_ship_ship_sounds_init();
1547 Pre_player_entry = 1; // Means the player has not yet entered.
1548 Entry_delay_time = 0; // Could get overwritten in mission read.
1549 fireball_preload(); // page in warphole bitmaps
1551 flak_level_init(); // initialize flak - bitmaps, etc
1552 ct_level_init(); // initialize ships contrails, etc
1553 awacs_level_init(); // initialize AWACS
1554 beam_level_init(); // initialize beam weapons
1555 mflash_level_init();
1557 supernova_level_init();
1559 // multiplayer dogfight hack
1562 shipfx_engine_wash_level_init();
1566 Last_view_target = NULL;
1571 // campaign wasn't ended
1572 Campaign_ended_in_mission = 0;
1575 // called when a mission is over -- does server specific stuff.
1576 void freespace_stop_mission()
1579 Game_mode &= ~GM_IN_MISSION;
1582 // called at frame interval to process networking stuff
1583 void game_do_networking()
1585 Assert( Net_player != NULL );
1586 if (!(Game_mode & GM_MULTIPLAYER)){
1590 // see if this player should be reading/writing data. Bit is set when at join
1591 // screen onward until quits back to main menu.
1592 if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1596 if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1599 multi_pause_do_frame();
1604 // Loads the best palette for this level, based
1605 // on nebula color and hud color. You could just call palette_load_table with
1606 // the appropriate filename, but who wants to do that.
1607 void game_load_palette()
1609 char palette_filename[1024];
1611 // We only use 3 hud colors right now
1612 // Assert( HUD_config.color >= 0 );
1613 // Assert( HUD_config.color <= 2 );
1615 Assert( Mission_palette >= 0 );
1616 Assert( Mission_palette <= 98 );
1618 // if ( The_mission.flags & MISSION_FLAG_SUBSPACE ) {
1619 strcpy( palette_filename, NOX("gamepalette-subspace") );
1621 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1624 mprintf(( "Loading palette %s\n", palette_filename ));
1626 // palette_load_table(palette_filename);
1629 void game_post_level_init()
1631 // Stuff which gets called after mission is loaded. Because player isn't created until
1632 // after mission loads, some things must get initted after the level loads
1634 model_level_post_init();
1637 hud_setup_escort_list();
1638 mission_hotkey_set_defaults(); // set up the default hotkeys (from mission file)
1644 game_event_debug_init();
1647 training_mission_init();
1648 asteroid_create_all();
1650 game_framerate_check_init();
1654 // An estimate as to how high the count passed to game_loading_callback will go.
1655 // This is just a guess, it seems to always be about the same. The count is
1656 // proportional to the code being executed, not the time, so this works good
1657 // for a bar, assuming the code does about the same thing each time you
1658 // load a level. You can find this value by looking at the return value
1659 // of game_busy_callback(NULL), which I conveniently print out to the
1660 // debug output window with the '=== ENDING LOAD ==' stuff.
1661 //#define COUNT_ESTIMATE 3706
1662 #define COUNT_ESTIMATE 1111
1664 int Game_loading_callback_inited = 0;
1666 int Game_loading_background = -1;
1667 anim * Game_loading_ani = NULL;
1668 anim_instance *Game_loading_ani_instance;
1669 int Game_loading_frame=-1;
1671 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1680 // This gets called 10x per second and count is the number of times
1681 // game_busy() has been called since the current callback function
1683 void game_loading_callback(int count)
1685 game_do_networking();
1687 Assert( Game_loading_callback_inited==1 );
1688 Assert( Game_loading_ani != NULL );
1690 int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1691 if ( framenum > Game_loading_ani->total_frames-1 ) {
1692 framenum = Game_loading_ani->total_frames-1;
1693 } else if ( framenum < 0 ) {
1698 while ( Game_loading_frame < framenum ) {
1699 Game_loading_frame++;
1700 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1704 if ( cbitmap > -1 ) {
1705 if ( Game_loading_background > -1 ) {
1706 gr_set_bitmap( Game_loading_background );
1710 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame , Game_loading_ani->total_frames, cbitmap ));
1711 gr_set_bitmap( cbitmap );
1712 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1714 bm_release(cbitmap);
1720 void game_loading_callback_init()
1722 Assert( Game_loading_callback_inited==0 );
1724 Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1725 //common_set_interface_palette("InterfacePalette"); // set the interface palette
1728 Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1729 Assert( Game_loading_ani != NULL );
1730 Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1731 Assert( Game_loading_ani_instance != NULL );
1732 Game_loading_frame = -1;
1734 Game_loading_callback_inited = 1;
1736 game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 );
1741 void game_loading_callback_close()
1743 Assert( Game_loading_callback_inited==1 );
1745 // Make sure bar shows all the way over.
1746 game_loading_callback(COUNT_ESTIMATE);
1748 int real_count = game_busy_callback( NULL );
1751 Game_loading_callback_inited = 0;
1754 mprintf(( "=================== ENDING LOAD ================\n" ));
1755 mprintf(( "Real count = %d, Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1756 mprintf(( "================================================\n" ));
1758 // to remove warnings in release build
1762 free_anim_instance(Game_loading_ani_instance);
1763 Game_loading_ani_instance = NULL;
1764 anim_free(Game_loading_ani);
1765 Game_loading_ani = NULL;
1767 bm_release( Game_loading_background );
1768 common_free_interface_palette(); // restore game palette
1769 Game_loading_background = -1;
1771 gr_set_font( FONT1 );
1774 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1776 void game_maybe_update_sound_environment()
1778 // do nothing for now
1781 // Assign the sound environment for the game, based on the current mission
1783 void game_assign_sound_environment()
1786 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1787 Game_sound_env.id = SND_ENV_DRUGGED;
1788 Game_sound_env.volume = 0.800f;
1789 Game_sound_env.damping = 1.188f;
1790 Game_sound_env.decay = 6.392f;
1792 } else if (Num_asteroids > 30) {
1793 Game_sound_env.id = SND_ENV_AUDITORIUM;
1794 Game_sound_env.volume = 0.603f;
1795 Game_sound_env.damping = 0.5f;
1796 Game_sound_env.decay = 4.279f;
1799 Game_sound_env = Game_default_sound_env;
1803 Game_sound_env = Game_default_sound_env;
1804 Game_sound_env_update_timestamp = timestamp(1);
1807 // function which gets called before actually entering the mission. It is broken down into a funciton
1808 // since it will get called in one place from a single player game and from another place for
1809 // a multiplayer game
1810 void freespace_mission_load_stuff()
1812 // called if we're not on a freespace dedicated (non rendering, no pilot) server
1813 // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1814 if(!(Game_mode & GM_STANDALONE_SERVER)){
1816 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1818 game_loading_callback_init();
1820 event_music_level_init(); // preloads the first 2 seconds for each event music track
1823 gamesnd_unload_interface_sounds(); // unload interface sounds from memory
1826 gamesnd_preload_common_sounds(); // load in sounds that are expected to play
1829 ship_assign_sound_all(); // assign engine sounds to ships
1830 game_assign_sound_environment(); // assign the sound environment for this mission
1833 // call function in missionparse.cpp to fixup player/ai stuff.
1834 mission_parse_fixup_players();
1837 // Load in all the bitmaps for this level
1842 game_loading_callback_close();
1844 // the only thing we need to call on the standalone for now.
1846 // call function in missionparse.cpp to fixup player/ai stuff.
1847 mission_parse_fixup_players();
1849 // Load in all the bitmaps for this level
1855 uint load_mission_load;
1856 uint load_post_level_init;
1857 uint load_mission_stuff;
1859 // tells the server to load the mission and initialize structures
1860 int game_start_mission()
1862 mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1864 load_gl_init = time(NULL);
1866 load_gl_init = time(NULL) - load_gl_init;
1868 if (Game_mode & GM_MULTIPLAYER) {
1869 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1871 // clear multiplayer stats
1872 init_multiplayer_stats();
1875 load_mission_load = time(NULL);
1876 if (mission_load()) {
1877 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1878 popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1879 gameseq_post_event(GS_EVENT_MAIN_MENU);
1881 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1886 load_mission_load = time(NULL) - load_mission_load;
1888 // If this is a red alert mission in campaign mode, bash wingman status
1889 if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1890 red_alert_bash_wingman_status();
1893 // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1894 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1895 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1896 // game_load_palette();
1899 load_post_level_init = time(NULL);
1900 game_post_level_init();
1901 load_post_level_init = time(NULL) - load_post_level_init;
1905 void Do_model_timings_test();
1906 Do_model_timings_test();
1910 load_mission_stuff = time(NULL);
1911 freespace_mission_load_stuff();
1912 load_mission_stuff = time(NULL) - load_mission_stuff;
1917 int Interface_framerate = 0;
1920 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1921 DCF_BOOL( show_framerate, Show_framerate )
1922 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1923 DCF_BOOL( show_target_weapons, Show_target_weapons )
1924 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1925 DCF_BOOL( sound, Sound_enabled )
1926 DCF_BOOL( zbuffer, game_zbuffer )
1927 DCF_BOOL( shield_system, New_shield_system )
1928 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1929 DCF_BOOL( player_attacking, Player_attacking_enabled )
1930 DCF_BOOL( show_waypoints, Show_waypoints )
1931 DCF_BOOL( show_area_effect, Show_area_effect )
1932 DCF_BOOL( show_net_stats, Show_net_stats )
1933 DCF_BOOL( log, Log_debug_output_to_file )
1934 DCF_BOOL( training_msg_method, Training_msg_method )
1935 DCF_BOOL( show_player_pos, Show_player_pos )
1936 DCF_BOOL(i_framerate, Interface_framerate )
1938 DCF(show_mem,"Toggles showing mem usage")
1941 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1942 if ( Dc_arg_type & ARG_TRUE ) Show_mem = 1;
1943 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;
1944 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;
1950 if ( Dc_help ) dc_printf( "Usage: Show_mem\nSets show_mem to true or false. If nothing passed, then toggles it.\n" );
1952 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1953 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1957 DCF(show_cpu,"Toggles showing cpu usage")
1960 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1961 if ( Dc_arg_type & ARG_TRUE ) Show_cpu = 1;
1962 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;
1963 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;
1969 if ( Dc_help ) dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false. If nothing passed, then toggles it.\n" );
1971 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );
1972 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );
1979 // AL 4-8-98: always allow players to display their framerate
1982 DCF_BOOL( show_framerate, Show_framerate )
1989 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1992 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
1993 if ( Dc_arg_type & ARG_TRUE ) Use_joy_mouse = 1;
1994 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;
1995 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;
1997 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" );
1998 if ( Dc_status ) dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );
2000 os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
2003 DCF(palette_flash,"Toggles palette flash effect on/off")
2006 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2007 if ( Dc_arg_type & ARG_TRUE ) Use_palette_flash = 1;
2008 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;
2009 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;
2011 if ( Dc_help ) dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false. If nothing passed, then toggles it.\n" );
2012 if ( Dc_status ) dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );
2015 int Use_low_mem = 0;
2017 DCF(low_mem,"Uses low memory settings regardless of RAM")
2020 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2021 if ( Dc_arg_type & ARG_TRUE ) Use_low_mem = 1;
2022 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;
2023 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;
2025 if ( Dc_help ) dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false. If nothing passed, then toggles it.\n" );
2026 if ( Dc_status ) dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );
2028 os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
2034 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
2037 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2038 if ( Dc_arg_type & ARG_TRUE ) Use_fullscreen_at_startup = 1;
2039 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;
2040 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;
2042 if ( Dc_help ) dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false. If nothing passed, then toggles it.\n" );
2043 if ( Dc_status ) dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );
2044 os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
2048 int Framerate_delay = 0;
2050 float Freespace_gamma = 1.0f;
2052 DCF(gamma,"Sets Gamma factor")
2055 dc_get_arg(ARG_FLOAT|ARG_NONE);
2056 if ( Dc_arg_type & ARG_FLOAT ) {
2057 Freespace_gamma = Dc_arg_float;
2059 dc_printf( "Gamma reset to 1.0f\n" );
2060 Freespace_gamma = 1.0f;
2062 if ( Freespace_gamma < 0.1f ) {
2063 Freespace_gamma = 0.1f;
2064 } else if ( Freespace_gamma > 5.0f ) {
2065 Freespace_gamma = 5.0f;
2067 gr_set_gamma(Freespace_gamma);
2069 char tmp_gamma_string[32];
2070 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2071 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2075 dc_printf( "Usage: gamma <float>\n" );
2076 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
2077 Dc_status = 0; // don't print status if help is printed. Too messy.
2081 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2090 Game_current_mission_filename[0] = 0;
2092 // seed the random number generator
2093 Game_init_seed = time(NULL);
2094 srand( Game_init_seed );
2096 Framerate_delay = 0;
2102 extern void bm_init();
2108 // Initialize the timer before the os
2116 GetCurrentDirectory(1024, whee);
2119 getcwd (whee, 1024);
2122 strcat(whee, EXE_FNAME);
2124 //Initialize the libraries
2125 s1 = timer_get_milliseconds();
2126 if(cfile_init(whee, Game_CDROM_dir)){ // initialize before calling any cfopen stuff!!!
2129 e1 = timer_get_milliseconds();
2131 // time a bunch of cfopens
2133 s2 = timer_get_milliseconds();
2135 for(int idx=0; idx<10000; idx++){
2136 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2141 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2143 e2 = timer_get_milliseconds();
2146 if (Is_standalone) {
2147 std_init_standalone();
2149 os_init( Osreg_class_name, Osreg_app_name );
2150 os_set_title(Osreg_title);
2153 // initialize localization module. Make sure this is down AFTER initialzing OS.
2154 // int t1 = timer_get_milliseconds();
2157 // mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2159 // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2162 // verify that he has a valid weapons.tbl
2163 verify_weapons_tbl();
2165 // Output version numbers to registry for auto patching purposes
2166 os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2167 os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2168 os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2170 Use_joy_mouse = 0; //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2171 //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2172 Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2175 Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2179 Asteroids_enabled = 1;
2182 /////////////////////////////
2184 /////////////////////////////
2189 ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2190 mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2192 if (!stricmp(ptr, NOX("no sound"))) {
2193 Cmdline_freespace_no_sound = 1;
2195 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2197 } else if (!stricmp(ptr, NOX("EAX"))) {
2202 if (!Is_standalone) {
2203 snd_init(use_a3d, use_eax);
2205 /////////////////////////////
2207 /////////////////////////////
2209 ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2212 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);
2214 // fire up the UpdateLauncher executable
2216 PROCESS_INFORMATION pi;
2218 memset( &si, 0, sizeof(STARTUPINFO) );
2221 BOOL ret = CreateProcess( LAUNCHER_FNAME, // pointer to name of executable module
2222 NULL, // pointer to command line string
2223 NULL, // pointer to process security attributes
2224 NULL, // pointer to thread security attributes
2225 FALSE, // handle inheritance flag
2226 CREATE_DEFAULT_ERROR_MODE, // creation flags
2227 NULL, // pointer to new environment block
2228 NULL, // pointer to current directory name
2229 &si, // pointer to STARTUPINFO
2230 &pi // pointer to PROCESS_INFORMATION
2233 // If the Launcher could not be started up, let the user know
2235 MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2244 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2246 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);
2254 // check for hi res pack file
2255 int has_sparky_hi = 0;
2257 // check if sparky_hi exists -- access mode 0 means does file exist
2260 if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2263 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2266 // see if we've got 32 bit in the string
2267 if(strstr(ptr, "32 bit")){
2274 if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2276 // always 640 for E3
2277 gr_init(GR_640, GR_GLIDE);
2279 // regular or hi-res ?
2281 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2283 if(strstr(ptr, NOX("(1024x768)"))){
2285 gr_init(GR_1024, GR_GLIDE);
2287 gr_init(GR_640, GR_GLIDE);
2290 } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2292 // always 640 for E3
2294 gr_init(GR_640, GR_DIRECT3D, depth);
2296 // regular or hi-res ?
2298 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2300 if(strstr(ptr, NOX("(1024x768)"))){
2304 gr_init(GR_1024, GR_DIRECT3D, depth);
2308 gr_init(GR_640, GR_DIRECT3D, depth);
2314 if ( Use_fullscreen_at_startup && !Is_standalone) {
2315 gr_init(GR_640, GR_DIRECTDRAW);
2317 gr_init(GR_640, GR_SOFTWARE);
2320 if ( !Is_standalone ) {
2321 gr_init(GR_640, GR_DIRECTDRAW);
2323 gr_init(GR_640, GR_SOFTWARE);
2328 if (!Is_standalone /* && ptr && (strstr(ptr, NOX("OpenGL"))) */) {
2329 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2330 gr_init(GR_1024, GR_OPENGL);
2332 gr_init(GR_640, GR_OPENGL);
2336 gr_init(GR_640, GR_SOFTWARE);
2341 extern int Gr_inited;
2342 if(trying_d3d && !Gr_inited){
2344 extern char Device_init_error[512];
2345 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2354 ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2355 Freespace_gamma = (float)atof(ptr);
2356 if ( Freespace_gamma == 0.0f ) {
2357 Freespace_gamma = 1.80f;
2358 } else if ( Freespace_gamma < 0.1f ) {
2359 Freespace_gamma = 0.1f;
2360 } else if ( Freespace_gamma > 5.0f ) {
2361 Freespace_gamma = 5.0f;
2363 char tmp_gamma_string[32];
2364 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2365 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2367 gr_set_gamma(Freespace_gamma);
2369 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2372 display_title_screen();
2376 // attempt to load up master tracker registry info (login and password)
2377 Multi_tracker_id = -1;
2379 // pxo login and password
2380 ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2382 nprintf(("Network","Error reading in PXO login data\n"));
2383 strcpy(Multi_tracker_login,"");
2385 strcpy(Multi_tracker_login,ptr);
2387 ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2389 nprintf(("Network","Error reading PXO password\n"));
2390 strcpy(Multi_tracker_passwd,"");
2392 strcpy(Multi_tracker_passwd,ptr);
2395 // pxo squad name and password
2396 ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2398 nprintf(("Network","Error reading in PXO squad name\n"));
2399 strcpy(Multi_tracker_squad_name, "");
2401 strcpy(Multi_tracker_squad_name, ptr);
2404 // If less than 48MB of RAM, use low memory model.
2407 (Freespace_total_ram < 48*1024*1024) ||
2410 mprintf(( "Using normal memory settings...\n" ));
2411 bm_set_low_mem(1); // Use every other frame of bitmaps
2413 mprintf(( "Using high memory settings...\n" ));
2414 bm_set_low_mem(0); // Use all frames of bitmaps
2417 // load non-darkening pixel defs
2418 palman_load_pixels();
2420 // hud shield icon stuff
2421 hud_shield_game_init();
2423 control_config_common_init(); // sets up localization stuff in the control config
2429 gamesnd_parse_soundstbl();
2434 // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2439 player_controls_init();
2442 //if(!Is_standalone){
2450 ship_init(); // read in ships.tbl
2452 mission_campaign_init(); // load in the default campaign
2454 // navmap_init(); // init the navigation map system
2455 context_help_init();
2456 techroom_intel_init(); // parse species.tbl, load intel info
2458 psnet_init( Multi_options_g.protocol, Multi_options_g.port ); // initialize the networking code
2459 init_animating_pointer();
2461 mission_brief_common_init(); // Mark all the briefing structures as empty.
2462 gr_font_init(); // loads up all fonts
2464 neb2_init(); // fullneb stuff
2468 player_tips_init(); // helpful tips
2471 // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2472 pilot_load_pic_list();
2473 pilot_load_squad_pic_list();
2475 load_animating_pointer(NOX("cursor"), 0, 0);
2477 // initialize alpha colors
2478 alpha_colors_init();
2481 // Game_music_paused = 0;
2488 nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2489 nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2491 mprintf(("cfile_init() took %d\n", e1 - s1));
2492 // mprintf(("1000 cfopens() took %d\n", e2 - s2));
2495 char transfer_text[128];
2497 float Start_time = 0.0f;
2499 float Framerate = 0.0f;
2501 float Timing_total = 0.0f;
2502 float Timing_render2 = 0.0f;
2503 float Timing_render3 = 0.0f;
2504 float Timing_flip = 0.0f;
2505 float Timing_clear = 0.0f;
2507 MONITOR(NumPolysDrawn);
2513 void game_get_framerate()
2515 char text[128] = "";
2517 if ( frame_int == -1 ) {
2519 for (i=0; i<FRAME_FILTER; i++ ) {
2520 frametimes[i] = 0.0f;
2525 frametotal -= frametimes[frame_int];
2526 frametotal += flFrametime;
2527 frametimes[frame_int] = flFrametime;
2528 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2530 if ( frametotal != 0.0 ) {
2531 if ( Framecount >= FRAME_FILTER )
2532 Framerate = FRAME_FILTER / frametotal;
2534 Framerate = Framecount / frametotal;
2535 sprintf( text, NOX("FPS: %.1f"), Framerate );
2537 sprintf( text, NOX("FPS: ?") );
2541 if (Show_framerate) {
2542 gr_set_color_fast(&HUD_color_debug);
2543 gr_string( 570, 2, text );
2547 void game_show_framerate()
2551 cur_time = f2fl(timer_get_approx_seconds());
2552 if (cur_time - Start_time > 30.0f) {
2553 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2554 Start_time += 1000.0f;
2557 //mprintf(( "%s\n", text ));
2560 if ( Debug_dump_frames )
2564 // possibly show control checking info
2565 control_check_indicate();
2567 // int bitmaps_used_this_frame, bitmaps_new_this_frame;
2568 // bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2569 // MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2570 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2573 if ( Show_cpu == 1 ) {
2578 dy = gr_get_font_height() + 1;
2580 gr_set_color_fast(&HUD_color_debug);
2584 extern int D3D_textures_in;
2585 extern int D3D_textures_in_frame;
2586 extern int Glide_textures_in;
2587 extern int Glide_textures_in_frame;
2588 extern int Glide_explosion_vram;
2589 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2591 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2593 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2597 // gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2599 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2601 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2603 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2605 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2610 extern int Num_pairs; // Number of object pairs that were checked.
2611 gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2614 extern int Num_pairs_checked; // What percent of object pairs were checked.
2615 gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2617 Num_pairs_checked = 0;
2621 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2624 if ( Timing_total > 0.01f ) {
2625 gr_printf( sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2627 gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2629 gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2631 gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2633 gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2643 dy = gr_get_font_height() + 1;
2645 gr_set_color_fast(&HUD_color_debug);
2648 extern int TotalRam;
2649 gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2654 extern int Model_ram;
2655 gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2659 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2661 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 ); // mem used to store game sound
2663 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 ); // mem used to store game sound
2667 extern int D3D_textures_in;
2668 extern int Glide_textures_in;
2669 extern int Glide_textures_in_frame;
2670 extern int Glide_explosion_vram;
2671 gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2673 gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2675 gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2682 if ( Show_player_pos ) {
2686 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));
2689 MONITOR_INC(NumPolys, modelstats_num_polys);
2690 MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2691 MONITOR_INC(NumVerts, modelstats_num_verts );
2693 modelstats_num_polys = 0;
2694 modelstats_num_polys_drawn = 0;
2695 modelstats_num_verts = 0;
2696 modelstats_num_sortnorms = 0;
2700 void game_show_standalone_framerate()
2702 float frame_rate=30.0f;
2703 if ( frame_int == -1 ) {
2705 for (i=0; i<FRAME_FILTER; i++ ) {
2706 frametimes[i] = 0.0f;
2711 frametotal -= frametimes[frame_int];
2712 frametotal += flFrametime;
2713 frametimes[frame_int] = flFrametime;
2714 frame_int = (frame_int + 1 ) % FRAME_FILTER;
2716 if ( frametotal != 0.0 ) {
2717 if ( Framecount >= FRAME_FILTER ){
2718 frame_rate = FRAME_FILTER / frametotal;
2720 frame_rate = Framecount / frametotal;
2723 std_set_standalone_fps(frame_rate);
2727 // function to show the time remaining in a mission. Used only when the end-mission sexpression is used
2728 void game_show_time_left()
2732 // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2733 // mission should end (in fixed seconds). There is code in missionparse.cpp which actually handles
2734 // checking how much time is left
2736 if ( Mission_end_time == -1 ){
2740 diff = f2i(Mission_end_time - Missiontime);
2741 // be sure to bash to 0. diff could be negative on frame that we quit mission
2746 hud_set_default_color();
2747 gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2750 //========================================================================================
2751 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2752 //========================================================================================
2756 DCF(ai_pause,"Pauses ai")
2759 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2760 if ( Dc_arg_type & ARG_TRUE ) ai_paused = 1;
2761 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;
2762 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;
2765 obj_init_all_ships_physics();
2768 if ( Dc_help ) dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false. If nothing passed, then toggles it.\n" );
2769 if ( Dc_status ) dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );
2772 DCF(single_step,"Single steps the game")
2775 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);
2776 if ( Dc_arg_type & ARG_TRUE ) game_single_step = 1;
2777 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;
2778 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;
2780 last_single_step = 0; // Make so single step waits a frame before stepping
2783 if ( Dc_help ) dc_printf( "Usage: single_step [bool]\nSets single_step to true or false. If nothing passed, then toggles it.\n" );
2784 if ( Dc_status ) dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );
2787 DCF_BOOL(physics_pause, physics_paused)
2788 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2789 DCF_BOOL(ai_firing, Ai_firing_enabled )
2791 // Create some simple aliases to these commands...
2792 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2793 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2794 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2795 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2796 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2799 //========================================================================================
2800 //========================================================================================
2803 void game_training_pause_do()
2807 key = game_check_key();
2809 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2816 void game_increase_skill_level()
2819 if (Game_skill_level >= NUM_SKILL_LEVELS){
2820 Game_skill_level = 0;
2824 int Player_died_time;
2826 int View_percent = 100;
2829 DCF(view, "Sets the percent of the 3d view to render.")
2832 dc_get_arg(ARG_INT);
2833 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2834 View_percent = Dc_arg_int;
2836 dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2842 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2846 dc_printf("View is set to %d%%\n", View_percent );
2851 // Set the clip region for the 3d rendering window
2852 void game_set_view_clip()
2854 if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2855 // Set the clip region for the letterbox "dead view"
2856 int yborder = gr_screen.max_h/4;
2858 // Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2859 // J.S. I've changed my ways!! See the new "no constants" code!!!
2860 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 );
2862 // Set the clip region for normal view
2863 if ( View_percent >= 100 ) {
2866 int xborder, yborder;
2868 if ( View_percent < 5 ) {
2872 float fp = i2fl(View_percent)/100.0f;
2873 int fi = fl2i(fl_sqrt(fp)*100.0f);
2874 if ( fi > 100 ) fi=100;
2876 xborder = ( gr_screen.max_w*(100-fi) )/200;
2877 yborder = ( gr_screen.max_h*(100-fi) )/200;
2879 gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2885 void show_debug_stuff()
2888 int laser_count = 0, missile_count = 0;
2890 for (i=0; i<MAX_OBJECTS; i++) {
2891 if (Objects[i].type == OBJ_WEAPON){
2892 if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2894 } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2900 nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2903 extern int Tool_enabled;
2908 int tst_bitmap = -1;
2910 float tst_offset, tst_offset_total;
2913 void game_tst_frame_pre()
2921 g3_rotate_vertex(&v, &tst_pos);
2922 g3_project_vertex(&v);
2925 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2929 // big ship? always tst
2931 // within 3000 meters
2932 if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2936 // within 300 meters
2937 if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2944 void game_tst_frame()
2954 tst_time = time(NULL);
2956 // load the tst bitmap
2957 switch((int)frand_range(0.0f, 3.0)){
2959 tst_bitmap = bm_load("ig_jim");
2961 mprintf(("TST 0\n"));
2965 tst_bitmap = bm_load("ig_kan");
2967 mprintf(("TST 1\n"));
2971 tst_bitmap = bm_load("ig_jim");
2973 mprintf(("TST 2\n"));
2977 tst_bitmap = bm_load("ig_kan");
2979 mprintf(("TST 3\n"));
2988 // get the tst bitmap dimensions
2990 bm_get_info(tst_bitmap, &w, &h);
2993 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2995 snd_play(&Snds[SND_VASUDAN_BUP]);
2997 // tst x and direction
3001 tst_offset_total = (float)w;
3002 tst_offset = (float)w;
3004 tst_x = (float)gr_screen.max_w;
3005 tst_offset_total = (float)-w;
3006 tst_offset = (float)w;
3014 float diff = (tst_offset_total / 0.5f) * flFrametime;
3020 tst_offset -= fl_abs(diff);
3021 } else if(tst_mode == 2){
3024 tst_offset -= fl_abs(diff);
3028 gr_set_bitmap(tst_bitmap);
3029 gr_bitmap((int)tst_x, (int)tst_y);
3032 if(timestamp_elapsed_safe(tst_stamp, 1100)){
3036 // if we passed the switch point
3037 if(tst_offset <= 0.0f){
3042 tst_stamp = timestamp(1000);
3043 tst_offset = fl_abs(tst_offset_total);
3054 void game_tst_mark(object *objp, ship *shipp)
3063 if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3066 sip = &Ship_info[shipp->ship_info_index];
3073 tst_pos = objp->pos;
3074 if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3080 extern void render_shields();
3082 void player_repair_frame(float frametime)
3084 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3086 for(idx=0;idx<MAX_PLAYERS;idx++){
3089 np = &Net_players[idx];
3091 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)){
3093 // don't rearm/repair if the player is dead or dying/departing
3094 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3095 ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3100 if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3101 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3107 #define NUM_FRAMES_TEST 300
3108 #define NUM_MIXED_SOUNDS 16
3109 void do_timing_test(float flFrametime)
3111 static int framecount = 0;
3112 static int test_running = 0;
3113 static float test_time = 0.0f;
3115 static int snds[NUM_MIXED_SOUNDS];
3118 if ( test_running ) {
3120 test_time += flFrametime;
3121 if ( framecount >= NUM_FRAMES_TEST ) {
3123 nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3124 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3129 if ( Test_begin == 1 ) {
3135 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3138 // start looping digital sounds
3139 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3140 snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3147 DCF(dcf_fov, "Change the field of view")
3150 dc_get_arg(ARG_FLOAT|ARG_NONE);
3151 if ( Dc_arg_type & ARG_NONE ) {
3152 Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3153 dc_printf( "Zoom factor reset\n" );
3155 if ( Dc_arg_type & ARG_FLOAT ) {
3156 if (Dc_arg_float < 0.25f) {
3157 Viewer_zoom = 0.25f;
3158 dc_printf("Zoom factor pinned at 0.25.\n");
3159 } else if (Dc_arg_float > 1.25f) {
3160 Viewer_zoom = 1.25f;
3161 dc_printf("Zoom factor pinned at 1.25.\n");
3163 Viewer_zoom = Dc_arg_float;
3169 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3172 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3176 DCF(framerate_cap, "Sets the framerate cap")
3179 dc_get_arg(ARG_INT);
3180 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3181 Framerate_cap = Dc_arg_int;
3183 dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3189 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3190 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3191 dc_printf("[n] must be from 1 to 120.\n");
3195 if ( Framerate_cap )
3196 dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3198 dc_printf("There is no framerate cap currently active.\n");
3202 #define MIN_DIST_TO_DEAD_CAMERA 50.0f
3203 int Show_viewing_from_self = 0;
3205 void say_view_target()
3207 object *view_target;
3209 if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3210 view_target = &Objects[Player_ai->target_objnum];
3212 view_target = Player_obj;
3214 if (Game_mode & GM_DEAD) {
3215 if (Player_ai->target_objnum != -1)
3216 view_target = &Objects[Player_ai->target_objnum];
3219 if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3220 if (view_target != Player_obj){
3222 char *view_target_name = NULL;
3223 switch(Objects[Player_ai->target_objnum].type) {
3225 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3228 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3229 Viewer_mode &= ~VM_OTHER_SHIP;
3231 case OBJ_JUMP_NODE: {
3232 char jump_node_name[128];
3233 strcpy(jump_node_name, XSTR( "jump node", 184));
3234 view_target_name = jump_node_name;
3235 Viewer_mode &= ~VM_OTHER_SHIP;
3244 if ( view_target_name ) {
3245 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3246 Show_viewing_from_self = 1;
3249 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3250 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3251 Show_viewing_from_self = 1;
3253 if (Show_viewing_from_self)
3254 HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3259 Last_view_target = view_target;
3263 float Game_hit_x = 0.0f;
3264 float Game_hit_y = 0.0f;
3266 // Reset at the beginning of each frame
3267 void game_whack_reset()
3273 // Apply a 2d whack to the player
3274 void game_whack_apply( float x, float y )
3276 // Do some force feedback
3277 joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3283 // mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3286 // call to apply a "shudder"
3287 void game_shudder_apply(int time, float intensity)
3289 Game_shudder_time = timestamp(time);
3290 Game_shudder_total = time;
3291 Game_shudder_intensity = intensity;
3294 #define FF_SCALE 10000
3295 void apply_hud_shake(matrix *eye_orient)
3297 if (Viewer_obj == Player_obj) {
3298 physics_info *pi = &Player_obj->phys_info;
3306 // Make eye shake due to afterburner
3307 if ( !timestamp_elapsed(pi->afterburner_decay) ) {
3310 dtime = timestamp_until(pi->afterburner_decay);
3314 tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3315 tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3318 // Make eye shake due to engine wash
3320 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3323 tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3324 tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3326 // get the intensity
3327 float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3331 vm_vec_rand_vec_quick(&rand_vec);
3334 joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3338 // make hud shake due to shuddering
3339 if(Game_shudder_time != -1){
3340 // if the timestamp has elapsed
3341 if(timestamp_elapsed(Game_shudder_time)){
3342 Game_shudder_time = -1;
3344 // otherwise apply some shudder
3348 dtime = timestamp_until(Game_shudder_time);
3352 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));
3353 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));
3358 vm_angles_2_matrix(&tm, &tangles);
3359 Assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3360 Assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3361 Assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3362 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3367 extern void compute_slew_matrix(matrix *orient, angles *a); // TODO: move code to proper place and extern in header file
3369 // Player's velocity just before he blew up. Used to keep camera target moving.
3370 vector Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3372 // Set eye_pos and eye_orient based on view mode.
3373 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3377 static int last_Viewer_mode = 0;
3378 static int last_Game_mode = 0;
3379 static int last_Viewer_objnum = -1;
3381 // This code is supposed to detect camera "cuts"... like going between
3384 // determine if we need to regenerate the nebula
3385 if( (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) || // internal to external
3386 ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) || // external to internal
3387 (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) || // non dead-view to dead-view
3388 ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) || // dead-view to non dead-view
3389 (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) || // non warp-chase to warp-chase
3390 ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) || // warp-chase to non warp-chase
3391 (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) || // non other-ship to other-ship
3392 ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) || // other-ship to non-other ship
3393 ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum)) // other ship mode, but targets changes
3396 // regenerate the nebula
3400 if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) ) {
3401 //mprintf(( "************** Camera cut! ************\n" ));
3402 last_Viewer_mode = Viewer_mode;
3403 last_Game_mode = Game_mode;
3405 // Camera moved. Tell stars & debris to not do blurring.
3411 if ( Viewer_mode & VM_PADLOCK_ANY ) {
3412 player_display_packlock_view();
3415 game_set_view_clip();
3417 if (Game_mode & GM_DEAD) {
3418 vector vec_to_deader, view_pos;
3421 Viewer_mode |= VM_DEAD_VIEW;
3423 if (Player_ai->target_objnum != -1) {
3424 int view_from_player = 1;
3426 if (Viewer_mode & VM_OTHER_SHIP) {
3427 // View from target.
3428 Viewer_obj = &Objects[Player_ai->target_objnum];
3430 last_Viewer_objnum = Player_ai->target_objnum;
3432 if ( Viewer_obj->type == OBJ_SHIP ) {
3433 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3434 view_from_player = 0;
3437 last_Viewer_objnum = -1;
3440 if ( view_from_player ) {
3441 // View target from player ship.
3443 *eye_pos = Player_obj->pos;
3444 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3445 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3448 dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3450 if (dist < MIN_DIST_TO_DEAD_CAMERA)
3451 dist += flFrametime * 16.0f;
3453 vm_vec_scale(&vec_to_deader, -dist);
3454 vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3456 view_pos = Player_obj->pos;
3458 if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3459 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3460 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3461 Dead_player_last_vel = Player_obj->phys_info.vel;
3462 //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));
3463 } else if (Player_ai->target_objnum != -1) {
3464 view_pos = Objects[Player_ai->target_objnum].pos;
3466 // Make camera follow explosion, but gradually slow down.
3467 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3468 view_pos = Player_obj->pos;
3469 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3470 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3473 *eye_pos = Dead_camera_pos;
3475 vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3477 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3482 // if supernova shockwave
3483 if(supernova_camera_cut()){
3487 // call it dead view
3488 Viewer_mode |= VM_DEAD_VIEW;
3490 // set eye pos and orient
3491 supernova_set_view(eye_pos, eye_orient);
3493 // If already blown up, these other modes can override.
3494 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3495 Viewer_mode &= ~VM_DEAD_VIEW;
3497 Viewer_obj = Player_obj;
3499 if (Viewer_mode & VM_OTHER_SHIP) {
3500 if (Player_ai->target_objnum != -1){
3501 Viewer_obj = &Objects[Player_ai->target_objnum];
3502 last_Viewer_objnum = Player_ai->target_objnum;
3504 Viewer_mode &= ~VM_OTHER_SHIP;
3505 last_Viewer_objnum = -1;
3508 last_Viewer_objnum = -1;
3511 if (Viewer_mode & VM_EXTERNAL) {
3514 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3515 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3517 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3519 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3520 vm_vec_normalize(&eye_dir);
3521 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3524 // Modify the orientation based on head orientation.
3525 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3527 } else if ( Viewer_mode & VM_CHASE ) {
3530 if ( Viewer_obj->phys_info.speed < 0.1 )
3531 move_dir = Viewer_obj->orient.v.fvec;
3533 move_dir = Viewer_obj->phys_info.vel;
3534 vm_vec_normalize(&move_dir);
3537 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3538 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3539 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3540 vm_vec_normalize(&eye_dir);
3542 // JAS: I added the following code because if you slew up using
3543 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3544 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3545 // call because the up and the forward vector are the same. I fixed
3546 // it by adding in a fraction of the right vector all the time to the
3548 vector tmp_up = Viewer_obj->orient.v.uvec;
3549 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3551 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3554 // Modify the orientation based on head orientation.
3555 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3556 } else if ( Viewer_mode & VM_WARP_CHASE ) {
3557 *eye_pos = Camera_pos;
3559 ship * shipp = &Ships[Player_obj->instance];
3561 vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3562 vm_vec_normalize(&eye_dir);
3563 vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3566 // get an eye position based upon the correct type of object
3567 switch(Viewer_obj->type){
3569 // make a call to get the eye point for the player object
3570 ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3573 // make a call to get the eye point for the player object
3574 observer_get_eye( eye_pos, eye_orient, Viewer_obj );
3580 #ifdef JOHNS_DEBUG_CODE
3581 john_debug_stuff(&eye_pos, &eye_orient);
3587 apply_hud_shake(eye_orient);
3589 // setup neb2 rendering
3590 neb2_render_setup(eye_pos, eye_orient);
3594 extern void ai_debug_render_stuff();
3597 int Game_subspace_effect = 0;
3598 DCF_BOOL( subspace, Game_subspace_effect );
3600 // Does everything needed to render a frame
3601 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3605 g3_start_frame(game_zbuffer);
3606 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3608 // maybe offset the HUD (jitter stuff)
3609 dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3610 HUD_set_offsets(Viewer_obj, !dont_offset);
3612 // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array. Have to
3613 // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3614 // must be done before ships are rendered
3615 if ( MULTIPLAYER_CLIENT ) {
3616 shield_point_multi_setup();
3619 if ( Game_subspace_effect ) {
3620 stars_draw(0,0,0,1);
3622 stars_draw(1,1,1,0);
3625 obj_render_all(obj_render);
3626 beam_render_all(); // render all beam weapons
3627 particle_render_all(); // render particles after everything else.
3628 trail_render_all(); // render missilie trails after everything else.
3629 mflash_render_all(); // render all muzzle flashes
3631 // Why do we not show the shield effect in these modes? Seems ok.
3632 //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3636 // render nebula lightning
3639 // render local player nebula
3640 neb2_render_player();
3643 ai_debug_render_stuff();
3646 #ifndef RELEASE_REAL
3647 // game_framerate_check();
3651 extern void snd_spew_debug_info();
3652 snd_spew_debug_info();
3655 //================ END OF 3D RENDERING STUFF ====================
3659 if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3660 hud_maybe_clear_head_area();
3661 anim_render_all(0, flFrametime);
3664 extern int Multi_display_netinfo;
3665 if(Multi_display_netinfo){
3666 extern void multi_display_netinfo();
3667 multi_display_netinfo();
3670 game_tst_frame_pre();
3673 do_timing_test(flFrametime);
3677 extern int OO_update_index;
3678 multi_rate_display(OO_update_index, 375, 0);
3683 extern void oo_display();
3690 //#define JOHNS_DEBUG_CODE 1
3692 #ifdef JOHNS_DEBUG_CODE
3693 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3695 //if ( keyd_pressed[KEY_LSHIFT] )
3697 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3699 model_subsystem *turret = tsys->system_info;
3701 if (turret->type == SUBSYSTEM_TURRET ) {
3702 vector v.fvec, v.uvec;
3703 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3705 ship_model_start(tobj);
3707 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3708 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3709 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3711 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3713 ship_model_stop(tobj);
3723 // following function for dumping frames for purposes of building trailers.
3726 // function to toggle state of dumping every frame into PCX when playing the game
3727 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3731 if ( Debug_dump_frames == 0 ) {
3733 Debug_dump_frames = 15;
3734 Debug_dump_trigger = 0;
3735 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3736 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3739 Debug_dump_frames = 0;
3740 Debug_dump_trigger = 0;
3741 gr_dump_frame_stop();
3742 dc_printf( "Frame dumping is now OFF\n" );
3748 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3752 if ( Debug_dump_frames == 0 ) {
3754 Debug_dump_frames = 15;
3755 Debug_dump_trigger = 1;
3756 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3757 dc_printf( "Frame dumping at 15 hz is now ON\n" );
3760 Debug_dump_frames = 0;
3761 Debug_dump_trigger = 0;
3762 gr_dump_frame_stop();
3763 dc_printf( "Frame dumping is now OFF\n" );
3769 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3773 if ( Debug_dump_frames == 0 ) {
3775 Debug_dump_frames = 30;
3776 Debug_dump_trigger = 0;
3777 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3778 dc_printf( "Frame dumping at 30 hz is now ON\n" );
3781 Debug_dump_frames = 0;
3782 Debug_dump_trigger = 0;
3783 gr_dump_frame_stop();
3784 dc_printf( "Frame dumping is now OFF\n" );
3790 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3794 if ( Debug_dump_frames == 0 ) {
3796 Debug_dump_frames = 30;
3797 Debug_dump_trigger = 1;
3798 gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3799 dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3802 Debug_dump_frames = 0;
3803 Debug_dump_trigger = 0;
3804 gr_dump_frame_stop();
3805 dc_printf( "Triggered frame dumping is now OFF\n" );
3811 void game_maybe_dump_frame()
3813 if ( !Debug_dump_frames ){
3817 if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3824 Debug_dump_frame_num++;
3830 extern int Player_dead_state;
3832 // Flip the page and time how long it took.
3833 void game_flip_page_and_time_it()
3837 t1 = timer_get_fixed_seconds();
3839 t2 = timer_get_fixed_seconds();
3841 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3842 sprintf( transfer_text, NOX("%ld MB/s"), fixmuldiv(t,65,d) );
3845 void game_simulation_frame()
3847 // blow ships up in multiplayer dogfight
3848 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){
3849 // blow up all non-player ships
3850 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3853 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3855 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)){
3856 moveup = GET_NEXT(moveup);
3859 shipp = &Ships[Objects[moveup->objnum].instance];
3860 sip = &Ship_info[shipp->ship_info_index];
3862 // only blow up small ships
3863 if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){
3864 // function to simply explode a ship where it is currently at
3865 ship_self_destruct( &Objects[moveup->objnum] );
3868 moveup = GET_NEXT(moveup);
3874 // process AWACS stuff - do this first thing
3877 // single player, set Player hits_this_frame to 0
3878 if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3879 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE / (0.001f * BURST_DURATION));
3880 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3884 supernova_process();
3885 if(supernova_active() >= 5){
3889 // fire targeting lasers now so that
3890 // 1 - created this frame
3891 // 2 - collide this frame
3892 // 3 - render this frame
3893 // 4 - ignored and deleted next frame
3894 // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3896 ship_process_targeting_lasers();
3898 // do this here so that it works for multiplayer
3900 // get viewer direction
3901 int viewer_direction = PHYSICS_VIEWER_REAR;
3903 if(Viewer_mode == 0){
3904 viewer_direction = PHYSICS_VIEWER_FRONT;
3906 if(Viewer_mode & VM_PADLOCK_UP){
3907 viewer_direction = PHYSICS_VIEWER_UP;
3909 else if(Viewer_mode & VM_PADLOCK_REAR){
3910 viewer_direction = PHYSICS_VIEWER_REAR;
3912 else if(Viewer_mode & VM_PADLOCK_LEFT){
3913 viewer_direction = PHYSICS_VIEWER_LEFT;
3915 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3916 viewer_direction = PHYSICS_VIEWER_RIGHT;
3919 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3921 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3924 #define VM_PADLOCK_UP (1 << 7)
3925 #define VM_PADLOCK_REAR (1 << 8)
3926 #define VM_PADLOCK_LEFT (1 << 9)
3927 #define VM_PADLOCK_RIGHT (1 << 10)
3929 // evaluate mission departures and arrivals before we process all objects.
3930 if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3932 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3933 // ships/wing packets.
3934 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3935 mission_parse_eval_stuff();
3938 // if we're an observer, move ourselves seperately from the standard physics
3939 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3940 obj_observer_move(flFrametime);
3943 // move all the objects now
3944 obj_move_all(flFrametime);
3946 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3947 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3948 // ship_check_cargo_all();
3949 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3950 mission_eval_goals();
3954 // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3955 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3956 training_check_objectives();
3959 // do all interpolation now
3960 if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3961 // client side processing of warping in effect stages
3962 multi_do_client_warp(flFrametime);
3964 // client side movement of an observer
3965 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3966 obj_observer_move(flFrametime);
3969 // move all objects - does interpolation now as well
3970 obj_move_all(flFrametime);
3973 // only process the message queue when the player is "in" the game
3974 if ( !Pre_player_entry ){
3975 message_queue_process(); // process any messages send to the player
3978 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3979 message_maybe_distort(); // maybe distort incoming message if comms damaged
3980 player_repair_frame(flFrametime); // AI objects get repaired in ai_process, called from move code...deal with player.
3981 player_process_pending_praise(); // maybe send off a delayed praise message to the player
3982 player_maybe_play_all_alone_msg(); // mabye tell the player he is all alone
3985 if(!(Game_mode & GM_STANDALONE_SERVER)){
3986 // process some stuff every frame (before frame is rendered)
3987 emp_process_local();
3989 hud_update_frame(); // update hud systems
3991 if (!physics_paused) {
3992 // Move particle system
3993 particle_move_all(flFrametime);
3995 // Move missile trails
3996 trail_move_all(flFrametime);
3998 // process muzzle flashes
3999 mflash_process_all();
4001 // Flash the gun flashes
4002 shipfx_flash_do_frame(flFrametime);
4004 shockwave_move_all(flFrametime); // update all the shockwaves
4007 // subspace missile strikes
4010 obj_snd_do_frame(); // update the object-linked persistant sounds
4011 game_maybe_update_sound_environment();
4012 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
4014 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
4016 if ( Game_subspace_effect ) {
4017 game_start_subspace_ambient_sound();
4023 // Maybe render and process the dead-popup
4024 void game_maybe_do_dead_popup(float frametime)
4026 if ( popupdead_is_active() ) {
4028 int choice = popupdead_do_frame(frametime);
4030 if ( Game_mode & GM_NORMAL ) {
4034 if(game_do_cd_mission_check(Game_current_mission_filename)){
4035 gameseq_post_event(GS_EVENT_ENTER_GAME);
4037 gameseq_post_event(GS_EVENT_MAIN_MENU);
4042 gameseq_post_event(GS_EVENT_END_GAME);
4047 if(game_do_cd_mission_check(Game_current_mission_filename)){
4048 gameseq_post_event(GS_EVENT_START_GAME);
4050 gameseq_post_event(GS_EVENT_MAIN_MENU);
4054 // this should only happen during a red alert mission
4057 Assert(The_mission.red_alert);
4058 if(!The_mission.red_alert){
4060 if(game_do_cd_mission_check(Game_current_mission_filename)){
4061 gameseq_post_event(GS_EVENT_START_GAME);
4063 gameseq_post_event(GS_EVENT_MAIN_MENU);
4068 // choose the previous mission
4069 mission_campaign_previous_mission();
4071 if(game_do_cd_mission_check(Game_current_mission_filename)){
4072 gameseq_post_event(GS_EVENT_START_GAME);
4074 gameseq_post_event(GS_EVENT_MAIN_MENU);
4085 case POPUPDEAD_DO_MAIN_HALL:
4086 multi_quit_game(PROMPT_NONE,-1);
4089 case POPUPDEAD_DO_RESPAWN:
4090 multi_respawn_normal();
4091 event_music_player_respawn();
4094 case POPUPDEAD_DO_OBSERVER:
4095 multi_respawn_observer();
4096 event_music_player_respawn_as_observer();
4105 if ( leave_popup ) {
4111 // returns true if player is actually in a game_play stats
4112 int game_actually_playing()
4116 state = gameseq_get_state();
4117 if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4123 // Draw the 2D HUD gauges
4124 void game_render_hud_2d()
4126 if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4130 HUD_render_2d(flFrametime);
4134 // Draw the 3D-dependant HUD gauges
4135 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4137 g3_start_frame(0); // 0 = turn zbuffering off
4138 g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4140 if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4141 HUD_render_3d(flFrametime);
4145 game_sunspot_process(flFrametime);
4147 // Diminish the palette effect
4148 game_flash_diminish(flFrametime);
4156 int actually_playing;
4157 fix total_time1, total_time2;
4158 fix render2_time1=0, render2_time2=0;
4159 fix render3_time1=0, render3_time2=0;
4160 fix flip_time1=0, flip_time2=0;
4161 fix clear_time1=0, clear_time2=0;
4167 if (Framerate_delay) {
4168 int start_time = timer_get_milliseconds();
4169 while (timer_get_milliseconds() < start_time + Framerate_delay)
4175 demo_do_frame_start();
4177 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4182 // start timing frame
4183 timing_frame_start();
4185 total_time1 = timer_get_fixed_seconds();
4187 // var to hold which state we are in
4188 actually_playing = game_actually_playing();
4190 if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4191 if (!(Game_mode & GM_STANDALONE_SERVER)){
4192 Assert( OBJ_INDEX(Player_obj) >= 0 );
4196 if (Missiontime > Entry_delay_time){
4197 Pre_player_entry = 0;
4199 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4202 // Note: These are done even before the player enters, else buffers can overflow.
4203 if (! (Game_mode & GM_STANDALONE_SERVER)){
4207 shield_frame_init();
4209 if ( Player->control_mode != PCM_NORMAL )
4212 if ( !Pre_player_entry && actually_playing ) {
4213 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4215 if( (!popup_running_state()) && (!popupdead_is_active()) ){
4216 game_process_keys();
4218 // don't read flying controls if we're playing a demo back
4219 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4220 read_player_controls( Player_obj, flFrametime);
4224 // if we're not the master, we may have to send the server-critical ship status button_info bits
4225 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4226 multi_maybe_send_ship_status();
4231 // Reset the whack stuff
4234 // These two lines must be outside of Pre_player_entry code,
4235 // otherwise too many lights are added.
4238 if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4242 game_simulation_frame();
4244 // if not actually in a game play state, then return. This condition could only be true in
4245 // a multiplayer game.
4246 if ( !actually_playing ) {
4247 Assert( Game_mode & GM_MULTIPLAYER );
4251 if (!Pre_player_entry) {
4252 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4253 clear_time1 = timer_get_fixed_seconds();
4254 // clear the screen to black
4256 if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4260 clear_time2 = timer_get_fixed_seconds();
4261 render3_time1 = timer_get_fixed_seconds();
4262 game_render_frame_setup(&eye_pos, &eye_orient);
4263 game_render_frame( &eye_pos, &eye_orient );
4265 // save the eye position and orientation
4266 if ( Game_mode & GM_MULTIPLAYER ) {
4267 Net_player->s_info.eye_pos = eye_pos;
4268 Net_player->s_info.eye_orient = eye_orient;
4271 hud_show_target_model();
4273 // check to see if we should display the death died popup
4274 if(Game_mode & GM_DEAD_BLEW_UP){
4275 if(Game_mode & GM_MULTIPLAYER){
4276 // catch the situation where we're supposed to be warping out on this transition
4277 if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4278 gameseq_post_event(GS_EVENT_DEBRIEF);
4279 } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4280 Player_died_popup_wait = -1;
4284 if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4285 Player_died_popup_wait = -1;
4291 // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4292 if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4293 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4294 if(!popupdead_is_active()){
4298 Player_multi_died_check = -1;
4302 render3_time2 = timer_get_fixed_seconds();
4303 render2_time1 = timer_get_fixed_seconds();
4306 game_get_framerate();
4307 game_show_framerate();
4309 game_show_time_left();
4311 // Draw the 2D HUD gauges
4312 if(supernova_active() < 3){
4313 game_render_hud_2d();
4316 game_set_view_clip();
4318 // Draw 3D HUD gauges
4319 game_render_hud_3d(&eye_pos, &eye_orient);
4323 render2_time2 = timer_get_fixed_seconds();
4325 // maybe render and process the dead popup
4326 game_maybe_do_dead_popup(flFrametime);
4328 // start timing frame
4329 timing_frame_stop();
4330 // timing_display(30, 10);
4332 // If a regular popup is active, don't flip (popup code flips)
4333 if( !popup_running_state() ){
4334 flip_time1 = timer_get_fixed_seconds();
4335 game_flip_page_and_time_it();
4336 flip_time2 = timer_get_fixed_seconds();
4340 game_maybe_dump_frame(); // used to dump pcx files for building trailers
4343 game_show_standalone_framerate();
4347 game_do_training_checks();
4350 // process lightning (nebula only)
4353 total_time2 = timer_get_fixed_seconds();
4355 // Got some timing numbers
4356 Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4357 Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4358 Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4359 Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4360 Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4363 demo_do_frame_end();
4365 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4371 #define MAX_FRAMETIME (F1_0/4) // Frametime gets saturated at this. Changed by MK on 11/1/97.
4372 // Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4373 // died. This resulted in screwed up death sequences.
4375 fix Last_time = 0; // The absolute time of game at end of last frame (beginning of this frame)
4376 fix Last_delta_time = 0; // While game is paused, this keeps track of how much elapsed in the frame before paused.
4377 static int timer_paused=0;
4378 #if defined(TIMER_TEST) && !defined(NDEBUG)
4379 static int stop_count,start_count;
4380 static int time_stopped,time_started;
4382 int saved_timestamp_ticker = -1;
4384 void game_reset_time()
4386 if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4390 // Last_time = timer_get_fixed_seconds();
4396 void game_stop_time()
4398 if (timer_paused==0) {
4400 time = timer_get_fixed_seconds();
4401 // Save how much time progressed so far in the frame so we can
4402 // use it when we unpause.
4403 Last_delta_time = time - Last_time;
4405 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4406 if (Last_delta_time < 0) {
4407 #if defined(TIMER_TEST) && !defined(NDEBUG)
4408 Int3(); //get Matt!!!!
4410 Last_delta_time = 0;
4412 #if defined(TIMER_TEST) && !defined(NDEBUG)
4413 time_stopped = time;
4416 // Stop the timer_tick stuff...
4417 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4418 saved_timestamp_ticker = timestamp_ticker;
4422 #if defined(TIMER_TEST) && !defined(NDEBUG)
4427 void game_start_time()
4430 Assert(timer_paused >= 0);
4431 if (timer_paused==0) {
4433 time = timer_get_fixed_seconds();
4434 #if defined(TIMER_TEST) && !defined(NDEBUG)
4436 Int3(); //get Matt!!!!
4439 // Take current time, and set it backwards to account for time
4440 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4441 // will be correct when it goes to calculate the frametime next
4443 Last_time = time - Last_delta_time;
4444 #if defined(TIMER_TEST) && !defined(NDEBUG)
4445 time_started = time;
4448 // Restore the timer_tick stuff...
4449 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4450 Assert( saved_timestamp_ticker > -1 ); // Called out of order, get JAS
4451 timestamp_ticker = saved_timestamp_ticker;
4452 saved_timestamp_ticker = -1;
4455 #if defined(TIMER_TEST) && !defined(NDEBUG)
4461 void game_set_frametime(int state)
4464 float frame_cap_diff;
4466 thistime = timer_get_fixed_seconds();
4468 if ( Last_time == 0 )
4469 Frametime = F1_0 / 30;
4471 Frametime = thistime - Last_time;
4473 // Frametime = F1_0 / 30;
4475 fix debug_frametime = Frametime; // Just used to display frametime.
4477 // If player hasn't entered mission yet, make frame take 1/4 second.
4478 if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4481 else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) { // note link to above if!!!!!
4483 fix frame_speed = F1_0 / Debug_dump_frames;
4485 if (Frametime > frame_speed ){
4486 nprintf(("warning","slow frame: %x\n",Frametime));
4489 thistime = timer_get_fixed_seconds();
4490 Frametime = thistime - Last_time;
4491 } while (Frametime < frame_speed );
4493 Frametime = frame_speed;
4497 Assert( Framerate_cap > 0 );
4499 // Cap the framerate so it doesn't get too high.
4503 cap = F1_0/Framerate_cap;
4504 if (Frametime < cap) {
4505 thistime = cap - Frametime;
4506 //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4507 Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4509 thistime = timer_get_fixed_seconds();
4513 if((Game_mode & GM_STANDALONE_SERVER) &&
4514 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4516 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4517 Sleep((DWORD)(frame_cap_diff*1000));
4519 thistime += fl2f((frame_cap_diff));
4521 Frametime = thistime - Last_time;
4524 // If framerate is too low, cap it.
4525 if (Frametime > MAX_FRAMETIME) {
4527 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4529 // to remove warnings in release build
4530 debug_frametime = fl2f(flFrametime);
4532 Frametime = MAX_FRAMETIME;
4535 Frametime = fixmul(Frametime, Game_time_compression);
4537 Last_time = thistime;
4538 //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4540 flFrametime = f2fl(Frametime);
4541 //if(!(Game_mode & GM_PLAYING_DEMO)){
4542 timestamp_inc(flFrametime);
4544 /* if ((Framecount > 0) && (Framecount < 10)) {
4545 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4550 // This is called from game_do_frame(), and from navmap_do_frame()
4551 void game_update_missiontime()
4553 // TODO JAS: Put in if and move this into game_set_frametime,
4554 // fix navmap to call game_stop/start_time
4555 //if ( !timer_paused )
4556 Missiontime += Frametime;
4559 void game_do_frame()
4561 game_set_frametime(GS_STATE_GAME_PLAY);
4562 game_update_missiontime();
4564 if (Game_mode & GM_STANDALONE_SERVER) {
4565 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4568 if ( game_single_step && (last_single_step == game_single_step) ) {
4569 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4570 while( key_checkch() == 0 )
4572 os_set_title( XSTR( "FreeSpace", 171) );
4573 Last_time = timer_get_fixed_seconds();
4576 last_single_step = game_single_step;
4578 if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4579 Keep_mouse_centered = 1; // force mouse to center of our window (so we don't hit movement limits)
4583 Keep_mouse_centered = 0;
4584 monitor_update(); // Update monitor variables
4587 void multi_maybe_do_frame()
4589 if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4594 int Joymouse_button_status = 0;
4596 // Flush all input devices
4604 Joymouse_button_status = 0;
4606 //mprintf(("Game flush!\n" ));
4609 // function for multiplayer only which calls game_do_state_common() when running the
4611 void game_do_dc_networking()
4613 Assert( Game_mode & GM_MULTIPLAYER );
4615 game_do_state_common( gameseq_get_state() );
4618 // Call this whenever in a loop, or when you need to check for a keystroke.
4619 int game_check_key()
4625 // convert keypad enter to normal enter
4626 if ((k & KEY_MASK) == KEY_PADENTER)
4627 k = (k & ~KEY_MASK) | KEY_ENTER;
4634 #define DEMO_TRAILER_TIMEOUT_MS 45000 // 45 seconds of no input, play trailer
4635 static int Demo_show_trailer_timestamp = 0;
4637 void demo_reset_trailer_timer()
4639 Demo_show_trailer_timestamp = timer_get_milliseconds();
4642 void demo_maybe_show_trailer(int k)
4645 // if key pressed, reset demo trailer timer
4647 demo_reset_trailer_timer();
4651 // if mouse moved, reset demo trailer timer
4654 mouse_get_delta(&dx, &dy);
4655 if ( (dx > 0) || (dy > 0) ) {
4656 demo_reset_trailer_timer();
4660 // if joystick has moved, reset demo trailer timer
4663 joy_get_delta(&dx, &dy);
4664 if ( (dx > 0) || (dy > 0) ) {
4665 demo_reset_trailer_timer();
4669 // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4670 // the low-level code. Ugly, I know... but was the simplest and most
4673 // if 30 seconds since last demo trailer time reset, launch movie
4674 if ( os_foreground() ) {
4675 int now = timer_get_milliseconds();
4676 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4677 // if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4679 movie_play( NOX("fstrailer2.mve") );
4680 demo_reset_trailer_timer();
4688 // same as game_check_key(), except this is used while actually in the game. Since there
4689 // generally are differences between game control keys and general UI keys, makes sense to
4690 // have seperate functions for each case. If you are not checking a game control while in a
4691 // mission, you should probably be using game_check_key() instead.
4696 if (!os_foreground()) {
4701 // If we're in a single player game, pause it.
4702 if (!(Game_mode & GM_MULTIPLAYER)){
4703 if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) ) {
4704 game_process_pause_key();
4712 demo_maybe_show_trailer(k);
4715 // Move the mouse cursor with the joystick.
4716 if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) ) {
4717 // Move the mouse cursor with the joystick
4721 joy_get_pos( &jx, &jy, &jz, &jr );
4723 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4724 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4727 mouse_get_real_pos( &mx, &my );
4728 mouse_set_pos( mx+dx, my+dy );
4733 m = mouse_down(MOUSE_LEFT_BUTTON);
4735 if ( j != Joymouse_button_status ) {
4736 //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4737 Joymouse_button_status = j;
4739 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4740 } else if ( (!j) && (m) ) {
4741 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4746 // if we should be ignoring keys because of some multiplayer situations
4747 if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4751 // If a popup is running, don't process all the Fn keys
4752 if( popup_active() ) {
4756 state = gameseq_get_state();
4758 // if ( k ) nprintf(( "General", "Key = %x\n", k ));
4761 case KEY_DEBUGGED + KEY_BACKSP:
4766 launch_context_help();
4771 // if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4773 // don't allow f2 while warping out in multiplayer
4774 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4779 case GS_STATE_INITIAL_PLAYER_SELECT:
4780 case GS_STATE_OPTIONS_MENU:
4781 case GS_STATE_HUD_CONFIG:
4782 case GS_STATE_CONTROL_CONFIG:
4783 case GS_STATE_DEATH_DIED:
4784 case GS_STATE_DEATH_BLEW_UP:
4785 case GS_STATE_VIEW_MEDALS:
4789 gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4796 // hotkey selection screen -- only valid from briefing and beyond.
4799 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) ) {
4800 gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4806 case KEY_DEBUGGED + KEY_F3:
4807 gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4810 case KEY_DEBUGGED + KEY_F4:
4811 gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4815 if(Game_mode & GM_MULTIPLAYER){
4816 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4817 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4821 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4822 gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4828 case KEY_ESC | KEY_SHIFTED:
4829 // make sure to quit properly out of multiplayer
4830 if(Game_mode & GM_MULTIPLAYER){
4831 multi_quit_game(PROMPT_NONE);
4834 gameseq_post_event( GS_EVENT_QUIT_GAME );
4839 case KEY_DEBUGGED + KEY_P:
4842 case KEY_PRINT_SCRN:
4844 static int counter = 0;
4849 sprintf( tmp_name, NOX("screen%02d"), counter );
4851 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4852 gr_print_screen(tmp_name);
4860 case KEY_SHIFTED | KEY_ENTER: {
4862 #if !defined(NDEBUG)
4864 if ( Game_mode & GM_NORMAL ){
4868 // if we're in multiplayer mode, do some special networking
4869 if(Game_mode & GM_MULTIPLAYER){
4870 debug_console(game_do_dc_networking);
4877 if ( Game_mode & GM_NORMAL )
4891 gameseq_post_event(GS_EVENT_QUIT_GAME);
4894 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4897 void camera_set_position( vector *pos )
4902 void camera_set_orient( matrix *orient )
4904 Camera_orient = *orient;
4907 void camera_set_velocity( vector *vel, int instantaneous )
4909 Camera_desired_velocity.xyz.x = 0.0f;
4910 Camera_desired_velocity.xyz.y = 0.0f;
4911 Camera_desired_velocity.xyz.z = 0.0f;
4913 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4914 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4915 vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4917 if ( instantaneous ) {
4918 Camera_velocity = Camera_desired_velocity;
4926 vector new_vel, delta_pos;
4928 apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4929 apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4930 apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4932 Camera_velocity = new_vel;
4934 // mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4936 vm_vec_add2( &Camera_pos, &delta_pos );
4938 float ot = Camera_time+0.0f;
4940 Camera_time += flFrametime;
4942 if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) ) {
4945 tmp.xyz.z = 4.739f; // always go this fast forward.
4947 // pick x and y velocities so they are always on a
4948 // circle with a 25 m radius.
4950 float tmp_angle = frand()*PI2;
4952 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4953 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4955 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4957 //mprintf(( "Changing velocity!\n" ));
4958 camera_set_velocity( &tmp, 0 );
4961 if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) ) {
4962 vector tmp = { 0.0f, 0.0f, 0.0f };
4963 camera_set_velocity( &tmp, 0 );
4968 void end_demo_campaign_do()
4970 #if defined(FS2_DEMO)
4971 // show upsell screens
4972 demo_upsell_show_screens();
4973 #elif defined(OEM_BUILD)
4974 // show oem upsell screens
4975 oem_upsell_show_screens();
4978 // drop into main hall
4979 gameseq_post_event( GS_EVENT_MAIN_MENU );
4982 // All code to process events. This is the only place
4983 // that you should change the state of the game.
4984 void game_process_event( int current_state, int event )
4986 mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4989 case GS_EVENT_SIMULATOR_ROOM:
4990 gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4993 case GS_EVENT_MAIN_MENU:
4994 gameseq_set_state(GS_STATE_MAIN_MENU);
4997 case GS_EVENT_OPTIONS_MENU:
4998 gameseq_push_state( GS_STATE_OPTIONS_MENU );
5001 case GS_EVENT_BARRACKS_MENU:
5002 gameseq_set_state(GS_STATE_BARRACKS_MENU);
5005 case GS_EVENT_TECH_MENU:
5006 gameseq_set_state(GS_STATE_TECH_MENU);
5009 case GS_EVENT_TRAINING_MENU:
5010 gameseq_set_state(GS_STATE_TRAINING_MENU);
5013 case GS_EVENT_START_GAME:
5014 Select_default_ship = 0;
5015 Player_multi_died_check = -1;
5016 gameseq_set_state(GS_STATE_CMD_BRIEF);
5019 case GS_EVENT_START_BRIEFING:
5020 gameseq_set_state(GS_STATE_BRIEFING);
5023 case GS_EVENT_DEBRIEF:
5024 // did we end the campaign in the main freespace 2 single player campaign?
5025 if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
5026 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
5028 gameseq_set_state(GS_STATE_DEBRIEF);
5031 Player_multi_died_check = -1;
5034 case GS_EVENT_SHIP_SELECTION:
5035 gameseq_set_state( GS_STATE_SHIP_SELECT );
5038 case GS_EVENT_WEAPON_SELECTION:
5039 gameseq_set_state( GS_STATE_WEAPON_SELECT );
5042 case GS_EVENT_ENTER_GAME:
5044 // maybe start recording a demo
5046 demo_start_record("test.fsd");
5050 if (Game_mode & GM_MULTIPLAYER) {
5051 // if we're respawning, make sure we change the view mode so that the hud shows up
5052 if (current_state == GS_STATE_DEATH_BLEW_UP) {
5056 gameseq_set_state(GS_STATE_GAME_PLAY);
5058 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5061 Player_multi_died_check = -1;
5063 // clear multiplayer button info
5064 extern button_info Multi_ship_status_bi;
5065 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5067 Start_time = f2fl(timer_get_approx_seconds());
5069 mprintf(("Entering game at time = %7.3f\n", Start_time));
5073 case GS_EVENT_START_GAME_QUICK:
5074 Select_default_ship = 1;
5075 gameseq_post_event(GS_EVENT_ENTER_GAME);
5079 case GS_EVENT_END_GAME:
5080 if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5081 (current_state == GS_STATE_DEATH_BLEW_UP) || (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5082 gameseq_set_state(GS_STATE_MAIN_MENU);
5087 Player_multi_died_check = -1;
5090 case GS_EVENT_QUIT_GAME:
5091 main_hall_stop_music();
5092 main_hall_stop_ambient();
5093 gameseq_set_state(GS_STATE_QUIT_GAME);
5095 Player_multi_died_check = -1;
5098 case GS_EVENT_GAMEPLAY_HELP:
5099 gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5102 case GS_EVENT_PAUSE_GAME:
5103 gameseq_push_state(GS_STATE_GAME_PAUSED);
5106 case GS_EVENT_DEBUG_PAUSE_GAME:
5107 gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5110 case GS_EVENT_TRAINING_PAUSE:
5111 gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5114 case GS_EVENT_PREVIOUS_STATE:
5115 gameseq_pop_state();
5118 case GS_EVENT_TOGGLE_FULLSCREEN:
5119 #ifndef HARDWARE_ONLY
5121 if ( gr_screen.mode == GR_SOFTWARE ) {
5122 gr_init( GR_640, GR_DIRECTDRAW );
5123 } else if ( gr_screen.mode == GR_DIRECTDRAW ) {
5124 gr_init( GR_640, GR_SOFTWARE );
5130 case GS_EVENT_TOGGLE_GLIDE:
5132 if ( gr_screen.mode != GR_GLIDE ) {
5133 gr_init( GR_640, GR_GLIDE );
5135 gr_init( GR_640, GR_SOFTWARE );
5140 case GS_EVENT_LOAD_MISSION_MENU:
5141 gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5144 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5145 gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5148 case GS_EVENT_HUD_CONFIG:
5149 gameseq_push_state( GS_STATE_HUD_CONFIG );
5152 case GS_EVENT_CONTROL_CONFIG:
5153 gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5156 case GS_EVENT_DEATH_DIED:
5157 gameseq_set_state( GS_STATE_DEATH_DIED );
5160 case GS_EVENT_DEATH_BLEW_UP:
5161 if ( current_state == GS_STATE_DEATH_DIED ) {
5162 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5163 event_music_player_death();
5165 // multiplayer clients set their extra check here
5166 if(Game_mode & GM_MULTIPLAYER){
5167 // set the multi died absolute last chance check
5168 Player_multi_died_check = time(NULL);
5171 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5175 case GS_EVENT_NEW_CAMPAIGN:
5176 if (!mission_load_up_campaign()){
5177 readyroom_continue_campaign();
5180 Player_multi_died_check = -1;
5183 case GS_EVENT_CAMPAIGN_CHEAT:
5184 if (!mission_load_up_campaign()){
5186 // bash campaign value
5187 extern char Main_hall_campaign_cheat[512];
5190 // look for the mission
5191 for(idx=0; idx<Campaign.num_missions; idx++){
5192 if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5193 Campaign.next_mission = idx;
5194 Campaign.prev_mission = idx - 1;
5201 readyroom_continue_campaign();
5204 Player_multi_died_check = -1;
5207 case GS_EVENT_CAMPAIGN_ROOM:
5208 gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5211 case GS_EVENT_CMD_BRIEF:
5212 gameseq_set_state(GS_STATE_CMD_BRIEF);
5215 case GS_EVENT_RED_ALERT:
5216 gameseq_set_state(GS_STATE_RED_ALERT);
5219 case GS_EVENT_CREDITS:
5220 gameseq_set_state( GS_STATE_CREDITS );
5223 case GS_EVENT_VIEW_MEDALS:
5224 gameseq_push_state( GS_STATE_VIEW_MEDALS );
5227 case GS_EVENT_SHOW_GOALS:
5228 gameseq_push_state( GS_STATE_SHOW_GOALS ); // use push_state() since we might get to this screen through a variety of states
5231 case GS_EVENT_HOTKEY_SCREEN:
5232 gameseq_push_state( GS_STATE_HOTKEY_SCREEN ); // use push_state() since we might get to this screen through a variety of states
5235 // multiplayer stuff follow these comments
5237 case GS_EVENT_MULTI_JOIN_GAME:
5238 gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5241 case GS_EVENT_MULTI_HOST_SETUP:
5242 gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5245 case GS_EVENT_MULTI_CLIENT_SETUP:
5246 gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5249 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5250 gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5253 case GS_EVENT_MULTI_STD_WAIT:
5254 gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5257 case GS_EVENT_STANDALONE_MAIN:
5258 gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5261 case GS_EVENT_MULTI_PAUSE:
5262 gameseq_push_state( GS_STATE_MULTI_PAUSED );
5265 case GS_EVENT_INGAME_PRE_JOIN:
5266 gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5269 case GS_EVENT_EVENT_DEBUG:
5270 gameseq_push_state(GS_STATE_EVENT_DEBUG);
5273 // Start a warpout where player automatically goes 70 no matter what
5274 // and can't cancel out of it.
5275 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5276 Warpout_forced = 1; // If non-zero, bash the player to speed and go through effect
5278 // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5279 Player->saved_viewer_mode = Viewer_mode;
5280 Player->control_mode = PCM_WARPOUT_STAGE1;
5281 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5282 Warpout_time = 0.0f; // Start timer!
5285 case GS_EVENT_PLAYER_WARPOUT_START:
5286 if ( Player->control_mode != PCM_NORMAL ) {
5287 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5289 Player->saved_viewer_mode = Viewer_mode;
5290 Player->control_mode = PCM_WARPOUT_STAGE1;
5291 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5292 Warpout_time = 0.0f; // Start timer!
5293 Warpout_forced = 0; // If non-zero, bash the player to speed and go through effect
5297 case GS_EVENT_PLAYER_WARPOUT_STOP:
5298 if ( Player->control_mode != PCM_NORMAL ) {
5299 if ( !Warpout_forced ) { // cannot cancel forced warpout
5300 Player->control_mode = PCM_NORMAL;
5301 Viewer_mode = Player->saved_viewer_mode;
5302 hud_subspace_notify_abort();
5303 mprintf(( "Player put back to normal mode.\n" ));
5304 if ( Warpout_sound > -1 ) {
5305 snd_stop( Warpout_sound );
5312 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1: // player ship got up to speed
5313 if ( Player->control_mode != PCM_WARPOUT_STAGE1 ) {
5314 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5315 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5317 mprintf(( "Hit target speed. Starting warp effect and moving to stage 2!\n" ));
5318 shipfx_warpout_start( Player_obj );
5319 Player->control_mode = PCM_WARPOUT_STAGE2;
5320 Player->saved_viewer_mode = Viewer_mode;
5321 Viewer_mode |= VM_WARP_CHASE;
5323 vector tmp = Player_obj->pos;
5325 ship_get_eye( &tmp, &tmp_m, Player_obj );
5326 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5327 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5328 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5330 camera_set_position( &tmp );
5331 camera_set_orient( &Player_obj->orient );
5332 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5334 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5335 camera_set_velocity( &tmp_vel, 1);
5339 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2: // player ship got into the warp effect
5340 if ( Player->control_mode != PCM_WARPOUT_STAGE2 ) {
5341 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5342 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5344 mprintf(( "Hit warp effect. Moving to stage 3!\n" ));
5345 Player->control_mode = PCM_WARPOUT_STAGE3;
5349 case GS_EVENT_PLAYER_WARPOUT_DONE: // player ship got through the warp effect
5350 mprintf(( "Player warped out. Going to debriefing!\n" ));
5351 Player->control_mode = PCM_NORMAL;
5352 Viewer_mode = Player->saved_viewer_mode;
5355 // we have a special debriefing screen for multiplayer furballs
5356 if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5357 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5359 // do the normal debriefing for all other situations
5361 gameseq_post_event(GS_EVENT_DEBRIEF);
5365 case GS_EVENT_STANDALONE_POSTGAME:
5366 gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5369 case GS_EVENT_INITIAL_PLAYER_SELECT:
5370 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5373 case GS_EVENT_GAME_INIT:
5374 #if defined(FS2_DEMO) || defined(OEM_BUILD)
5375 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5377 // see if the command line option has been set to use the last pilot, and act acoordingly
5378 if( player_select_get_last_pilot() ) {
5379 // always enter the main menu -- do the automatic network startup stuff elsewhere
5380 // so that we still have valid checks for networking modes, etc.
5381 gameseq_set_state(GS_STATE_MAIN_MENU);
5383 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5388 case GS_EVENT_MULTI_MISSION_SYNC:
5389 gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5392 case GS_EVENT_MULTI_START_GAME:
5393 gameseq_set_state(GS_STATE_MULTI_START_GAME);
5396 case GS_EVENT_MULTI_HOST_OPTIONS:
5397 gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5400 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5401 gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5404 case GS_EVENT_TEAM_SELECT:
5405 gameseq_set_state(GS_STATE_TEAM_SELECT);
5408 case GS_EVENT_END_CAMPAIGN:
5409 gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5412 case GS_EVENT_END_DEMO:
5413 gameseq_set_state(GS_STATE_END_DEMO);
5416 case GS_EVENT_LOOP_BRIEF:
5417 gameseq_set_state(GS_STATE_LOOP_BRIEF);
5426 // Called when a state is being left.
5427 // The current state is still at old_state, but as soon as
5428 // this function leaves, then the current state will become
5429 // new state. You should never try to change the state
5430 // in here... if you think you need to, you probably really
5431 // need to post an event, not change the state.
5432 void game_leave_state( int old_state, int new_state )
5434 int end_mission = 1;
5436 switch (new_state) {
5437 case GS_STATE_GAME_PAUSED:
5438 case GS_STATE_DEBUG_PAUSED:
5439 case GS_STATE_OPTIONS_MENU:
5440 case GS_STATE_CONTROL_CONFIG:
5441 case GS_STATE_MISSION_LOG_SCROLLBACK:
5442 case GS_STATE_DEATH_DIED:
5443 case GS_STATE_SHOW_GOALS:
5444 case GS_STATE_HOTKEY_SCREEN:
5445 case GS_STATE_MULTI_PAUSED:
5446 case GS_STATE_TRAINING_PAUSED:
5447 case GS_STATE_EVENT_DEBUG:
5448 case GS_STATE_GAMEPLAY_HELP:
5449 end_mission = 0; // these events shouldn't end a mission
5453 switch (old_state) {
5454 case GS_STATE_BRIEFING:
5455 brief_stop_voices();
5456 if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5457 && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5458 && (new_state != GS_STATE_TEAM_SELECT) ){
5459 common_select_close();
5460 if ( new_state == GS_STATE_MAIN_MENU ) {
5461 freespace_stop_mission();
5465 // COMMAND LINE OPTION
5466 if (Cmdline_multi_stream_chat_to_file){
5467 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5468 cfclose(Multi_chat_stream);
5472 case GS_STATE_DEBRIEF:
5473 if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5478 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5479 multi_df_debrief_close();
5482 case GS_STATE_LOAD_MISSION_MENU:
5483 mission_load_menu_close();
5486 case GS_STATE_SIMULATOR_ROOM:
5490 case GS_STATE_CAMPAIGN_ROOM:
5491 campaign_room_close();
5494 case GS_STATE_CMD_BRIEF:
5495 if (new_state == GS_STATE_OPTIONS_MENU) {
5500 if (new_state == GS_STATE_MAIN_MENU)
5501 freespace_stop_mission();
5506 case GS_STATE_RED_ALERT:
5510 case GS_STATE_SHIP_SELECT:
5511 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5512 new_state != GS_STATE_HOTKEY_SCREEN &&
5513 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5514 common_select_close();
5515 if ( new_state == GS_STATE_MAIN_MENU ) {
5516 freespace_stop_mission();
5521 case GS_STATE_WEAPON_SELECT:
5522 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5523 new_state != GS_STATE_HOTKEY_SCREEN &&
5524 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5525 common_select_close();
5526 if ( new_state == GS_STATE_MAIN_MENU ) {
5527 freespace_stop_mission();
5532 case GS_STATE_TEAM_SELECT:
5533 if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5534 new_state != GS_STATE_HOTKEY_SCREEN &&
5535 new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5536 common_select_close();
5537 if ( new_state == GS_STATE_MAIN_MENU ) {
5538 freespace_stop_mission();
5543 case GS_STATE_MAIN_MENU:
5544 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5551 case GS_STATE_OPTIONS_MENU:
5552 //game_start_time();
5553 if(new_state == GS_STATE_MULTI_JOIN_GAME){
5554 multi_join_clear_game_list();
5556 options_menu_close();
5559 case GS_STATE_BARRACKS_MENU:
5560 if(new_state != GS_STATE_VIEW_MEDALS){
5565 case GS_STATE_MISSION_LOG_SCROLLBACK:
5566 hud_scrollback_close();
5569 case GS_STATE_TRAINING_MENU:
5570 training_menu_close();
5573 case GS_STATE_GAME_PLAY:
5574 if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5575 player_save_target_and_weapon_link_prefs();
5576 game_stop_looped_sounds();
5579 sound_env_disable();
5580 joy_ff_stop_effects();
5582 // stop game time under certain conditions
5583 if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5588 // shut down any recording or playing demos
5593 // when in multiplayer and going back to the main menu, send a leave game packet
5594 // right away (before calling stop mission). stop_mission was taking to long to
5595 // close mission down and I want people to get notified ASAP.
5596 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5597 multi_quit_game(PROMPT_NONE);
5600 freespace_stop_mission();
5601 Game_time_compression = F1_0;
5605 case GS_STATE_TECH_MENU:
5609 case GS_STATE_TRAINING_PAUSED:
5610 Training_num_lines = 0;
5611 // fall through to GS_STATE_GAME_PAUSED
5613 case GS_STATE_GAME_PAUSED:
5615 if ( end_mission ) {
5620 case GS_STATE_DEBUG_PAUSED:
5623 pause_debug_close();
5627 case GS_STATE_HUD_CONFIG:
5631 // join/start a game
5632 case GS_STATE_MULTI_JOIN_GAME:
5633 if(new_state != GS_STATE_OPTIONS_MENU){
5634 multi_join_game_close();
5638 case GS_STATE_MULTI_HOST_SETUP:
5639 case GS_STATE_MULTI_CLIENT_SETUP:
5640 // if this is just the host going into the options screen, don't do anything
5641 if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5645 // close down the proper state
5646 if(old_state == GS_STATE_MULTI_HOST_SETUP){
5647 multi_create_game_close();
5649 multi_game_client_setup_close();
5652 // COMMAND LINE OPTION
5653 if (Cmdline_multi_stream_chat_to_file){
5654 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5655 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5656 cfclose(Multi_chat_stream);
5661 case GS_STATE_CONTROL_CONFIG:
5662 control_config_close();
5665 case GS_STATE_DEATH_DIED:
5666 Game_mode &= ~GM_DEAD_DIED;
5668 // early end while respawning or blowing up in a multiplayer game
5669 if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5671 freespace_stop_mission();
5675 case GS_STATE_DEATH_BLEW_UP:
5676 Game_mode &= ~GM_DEAD_BLEW_UP;
5678 // for single player, we might reload mission, etc. For multiplayer, look at my new state
5679 // to determine if I should do anything.
5680 if ( !(Game_mode & GM_MULTIPLAYER) ) {
5682 freespace_stop_mission();
5685 // if we are not respawing as an observer or as a player, our new state will not
5686 // be gameplay state.
5687 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5688 game_stop_time(); // hasn't been called yet!!
5689 freespace_stop_mission();
5695 case GS_STATE_CREDITS:
5699 case GS_STATE_VIEW_MEDALS:
5703 case GS_STATE_SHOW_GOALS:
5704 mission_show_goals_close();
5707 case GS_STATE_HOTKEY_SCREEN:
5708 if ( new_state != GS_STATE_OPTIONS_MENU ) {
5709 mission_hotkey_close();
5713 case GS_STATE_MULTI_MISSION_SYNC:
5714 // if we're moving into the options menu, don't do anything
5715 if(new_state == GS_STATE_OPTIONS_MENU){
5719 Assert( Game_mode & GM_MULTIPLAYER );
5721 if ( new_state == GS_STATE_GAME_PLAY ){
5722 // palette_restore_palette();
5724 // change a couple of flags to indicate our state!!!
5725 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5726 send_netplayer_update_packet();
5728 // set the game mode
5729 Game_mode |= GM_IN_MISSION;
5733 case GS_STATE_VIEW_CUTSCENES:
5734 cutscenes_screen_close();
5737 case GS_STATE_MULTI_STD_WAIT:
5738 multi_standalone_wait_close();
5741 case GS_STATE_STANDALONE_MAIN:
5742 standalone_main_close();
5743 if(new_state == GS_STATE_MULTI_STD_WAIT){
5744 init_multiplayer_stats();
5748 case GS_STATE_MULTI_PAUSED:
5749 // if ( end_mission ){
5754 case GS_STATE_INGAME_PRE_JOIN:
5755 multi_ingame_select_close();
5758 case GS_STATE_STANDALONE_POSTGAME:
5759 multi_standalone_postgame_close();
5762 case GS_STATE_INITIAL_PLAYER_SELECT:
5763 player_select_close();
5766 case GS_STATE_MULTI_START_GAME:
5767 multi_start_game_close();
5770 case GS_STATE_MULTI_HOST_OPTIONS:
5771 multi_host_options_close();
5774 case GS_STATE_END_OF_CAMPAIGN:
5775 mission_campaign_end_close();
5778 case GS_STATE_LOOP_BRIEF:
5784 // Called when a state is being entered.
5785 // The current state is set to the state we're entering at
5786 // this point, and old_state is set to the state we're coming
5787 // from. You should never try to change the state
5788 // in here... if you think you need to, you probably really
5789 // need to post an event, not change the state.
5791 void game_enter_state( int old_state, int new_state )
5793 switch (new_state) {
5794 case GS_STATE_MAIN_MENU:
5795 // in multiplayer mode, be sure that we are not doing networking anymore.
5796 if ( Game_mode & GM_MULTIPLAYER ) {
5797 Assert( Net_player != NULL );
5798 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5801 Game_time_compression = F1_0;
5803 // determine which ship this guy is currently based on
5804 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5807 if (Player->on_bastion) {
5815 case GS_STATE_BRIEFING:
5816 main_hall_stop_music();
5817 main_hall_stop_ambient();
5819 if (Game_mode & GM_NORMAL) {
5820 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5821 // MWA: or from options or hotkey screens
5822 // JH: or if the command brief state already did this
5823 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5824 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5825 && (old_state != GS_STATE_CMD_BRIEF) ) {
5826 if ( !game_start_mission() ) // this should put us into a new state on failure!
5830 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5831 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5832 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5834 Game_time_compression = F1_0;
5836 if ( red_alert_mission() ) {
5837 gameseq_post_event(GS_EVENT_RED_ALERT);
5844 case GS_STATE_DEBRIEF:
5845 game_stop_looped_sounds();
5846 mission_goal_fail_incomplete(); // fail all incomplete goals before entering debriefing
5847 if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5852 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5853 multi_df_debrief_init();
5856 case GS_STATE_LOAD_MISSION_MENU:
5857 mission_load_menu_init();
5860 case GS_STATE_SIMULATOR_ROOM:
5864 case GS_STATE_CAMPAIGN_ROOM:
5865 campaign_room_init();
5868 case GS_STATE_RED_ALERT:
5869 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5873 case GS_STATE_CMD_BRIEF: {
5874 int team_num = 0; // team number used as index for which cmd brief to use.
5876 if (old_state == GS_STATE_OPTIONS_MENU) {
5880 main_hall_stop_music();
5881 main_hall_stop_ambient();
5883 if (Game_mode & GM_NORMAL) {
5884 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5885 // MWA: or from options or hotkey screens
5886 // JH: or if the command brief state already did this
5887 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5888 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5889 if ( !game_start_mission() ) // this should put us into a new state on failure!
5894 // maybe play a movie before the briefing. don't play if entering briefing screen from ship or weapon select.
5895 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5896 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5898 cmd_brief_init(team_num);
5904 case GS_STATE_SHIP_SELECT:
5908 case GS_STATE_WEAPON_SELECT:
5909 weapon_select_init();
5912 case GS_STATE_TEAM_SELECT:
5916 case GS_STATE_GAME_PAUSED:
5921 case GS_STATE_DEBUG_PAUSED:
5922 // game_stop_time();
5923 // os_set_title("FreeSpace - PAUSED");
5926 case GS_STATE_TRAINING_PAUSED:
5933 case GS_STATE_OPTIONS_MENU:
5935 options_menu_init();
5938 case GS_STATE_GAME_PLAY:
5939 // coming from the gameplay state or the main menu, we might need to load the mission
5940 if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5941 if ( !game_start_mission() ) // this should put us into a new state.
5946 // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5947 // case of quick start), then do bitmap loads, etc Don't do any of the loading stuff
5948 // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5949 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5950 (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) ) {
5951 // JAS: Used to do all paging here.
5955 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5959 main_hall_stop_music();
5960 main_hall_stop_ambient();
5961 event_music_first_pattern(); // start the first pattern
5964 // special code that restores player ship selection and weapons loadout when doing a quick start
5965 if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP) || (old_state == GS_STATE_GAME_PLAY) ) {
5966 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5967 wss_direct_restore_loadout();
5971 // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5972 if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5973 event_music_first_pattern(); // start the first pattern
5976 if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5977 event_music_first_pattern(); // start the first pattern
5979 player_restore_target_and_weapon_link_prefs();
5981 Game_mode |= GM_IN_MISSION;
5984 // required to truely make mouse deltas zeroed in debug mouse code
5985 void mouse_force_pos(int x, int y);
5986 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5991 // only start time if in single player, or coming from multi wait state
5994 (Game_mode & GM_NORMAL) &&
5995 (old_state != GS_STATE_VIEW_CUTSCENES)
5997 (Game_mode & GM_MULTIPLAYER) && (
5998 (old_state == GS_STATE_MULTI_PAUSED) ||
5999 (old_state == GS_STATE_MULTI_MISSION_SYNC)
6005 // when coming from the multi paused state, reset the timestamps
6006 if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
6007 multi_reset_timestamps();
6010 if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
6011 // initialize all object update details
6012 multi_oo_gameplay_init();
6015 // under certain circumstances, the server should reset the object update rate limiting stuff
6016 if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
6017 (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
6019 // reinitialize the rate limiting system for all clients
6020 multi_oo_rate_init_all();
6023 // multiplayer clients should always re-initialize their control info rate limiting system
6024 if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
6025 multi_oo_rate_init_all();
6029 if(Game_mode & GM_MULTIPLAYER){
6030 multi_ping_reset_players();
6033 Game_subspace_effect = 0;
6034 if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
6035 Game_subspace_effect = 1;
6036 if( !(Game_mode & GM_STANDALONE_SERVER) ){
6037 game_start_subspace_ambient_sound();
6041 sound_env_set(&Game_sound_env);
6042 joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
6044 // clear multiplayer button info i
6045 extern button_info Multi_ship_status_bi;
6046 memset(&Multi_ship_status_bi, 0, sizeof(button_info));
6049 case GS_STATE_HUD_CONFIG:
6053 case GS_STATE_MULTI_JOIN_GAME:
6054 multi_join_clear_game_list();
6056 if (old_state != GS_STATE_OPTIONS_MENU) {
6057 multi_join_game_init();
6062 case GS_STATE_MULTI_HOST_SETUP:
6063 // don't reinitialize if we're coming back from the host options screen
6064 if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6065 multi_create_game_init();
6070 case GS_STATE_MULTI_CLIENT_SETUP:
6071 if (old_state != GS_STATE_OPTIONS_MENU) {
6072 multi_game_client_setup_init();
6077 case GS_STATE_CONTROL_CONFIG:
6078 control_config_init();
6081 case GS_STATE_TECH_MENU:
6085 case GS_STATE_BARRACKS_MENU:
6086 if(old_state != GS_STATE_VIEW_MEDALS){
6091 case GS_STATE_MISSION_LOG_SCROLLBACK:
6092 hud_scrollback_init();
6095 case GS_STATE_DEATH_DIED:
6096 Player_died_time = timestamp(10);
6098 if(!(Game_mode & GM_MULTIPLAYER)){
6099 player_show_death_message();
6101 Game_mode |= GM_DEAD_DIED;
6104 case GS_STATE_DEATH_BLEW_UP:
6105 if ( !popupdead_is_active() ) {
6106 Player_ai->target_objnum = -1;
6109 // stop any local EMP effect
6112 Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING; // Prevent immediate switch to a hostile ship.
6113 Game_mode |= GM_DEAD_BLEW_UP;
6114 Show_viewing_from_self = 0;
6116 // timestamp how long we should wait before displaying the died popup
6117 if ( !popupdead_is_active() ) {
6118 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6122 case GS_STATE_GAMEPLAY_HELP:
6123 gameplay_help_init();
6126 case GS_STATE_CREDITS:
6127 main_hall_stop_music();
6128 main_hall_stop_ambient();
6132 case GS_STATE_VIEW_MEDALS:
6133 medal_main_init(Player);
6136 case GS_STATE_SHOW_GOALS:
6137 mission_show_goals_init();
6140 case GS_STATE_HOTKEY_SCREEN:
6141 mission_hotkey_init();
6144 case GS_STATE_MULTI_MISSION_SYNC:
6145 // if we're coming from the options screen, don't do any
6146 if(old_state == GS_STATE_OPTIONS_MENU){
6150 switch(Multi_sync_mode){
6151 case MULTI_SYNC_PRE_BRIEFING:
6152 // if moving from game forming to the team select state
6155 case MULTI_SYNC_POST_BRIEFING:
6156 // if moving from briefing into the mission itself
6159 // tell everyone that we're now loading data
6160 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6161 send_netplayer_update_packet();
6163 // JAS: Used to do all paging here!!!!
6165 Net_player->state = NETPLAYER_STATE_WAITING;
6166 send_netplayer_update_packet();
6168 Game_time_compression = F1_0;
6170 case MULTI_SYNC_INGAME:
6176 case GS_STATE_VIEW_CUTSCENES:
6177 cutscenes_screen_init();
6180 case GS_STATE_MULTI_STD_WAIT:
6181 multi_standalone_wait_init();
6184 case GS_STATE_STANDALONE_MAIN:
6185 // don't initialize if we're coming from one of these 2 states unless there are no
6186 // players left (reset situation)
6187 if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6188 standalone_main_init();
6192 case GS_STATE_MULTI_PAUSED:
6196 case GS_STATE_INGAME_PRE_JOIN:
6197 multi_ingame_select_init();
6200 case GS_STATE_STANDALONE_POSTGAME:
6201 multi_standalone_postgame_init();
6204 case GS_STATE_INITIAL_PLAYER_SELECT:
6205 player_select_init();
6208 case GS_STATE_MULTI_START_GAME:
6209 multi_start_game_init();
6212 case GS_STATE_MULTI_HOST_OPTIONS:
6213 multi_host_options_init();
6216 case GS_STATE_END_OF_CAMPAIGN:
6217 mission_campaign_end_init();
6220 case GS_STATE_LOOP_BRIEF:
6227 // do stuff that may need to be done regardless of state
6228 void game_do_state_common(int state,int no_networking)
6230 game_maybe_draw_mouse(flFrametime); // determine if to draw the mouse this frame
6231 snd_do_frame(); // update sound system
6232 event_music_do_frame(); // music needs to play across many states
6234 multi_log_process();
6236 if (no_networking) {
6240 // maybe do a multiplayer frame based on game mode and state type
6241 if (Game_mode & GM_MULTIPLAYER) {
6243 case GS_STATE_OPTIONS_MENU:
6244 case GS_STATE_GAMEPLAY_HELP:
6245 case GS_STATE_HOTKEY_SCREEN:
6246 case GS_STATE_HUD_CONFIG:
6247 case GS_STATE_CONTROL_CONFIG:
6248 case GS_STATE_MISSION_LOG_SCROLLBACK:
6249 case GS_STATE_SHOW_GOALS:
6250 case GS_STATE_VIEW_CUTSCENES:
6251 case GS_STATE_EVENT_DEBUG:
6252 multi_maybe_do_frame();
6256 game_do_networking();
6260 // Called once a frame.
6261 // You should never try to change the state
6262 // in here... if you think you need to, you probably really
6263 // need to post an event, not change the state.
6264 int Game_do_state_should_skip = 0;
6265 void game_do_state(int state)
6267 // always lets the do_state_common() function determine if the state should be skipped
6268 Game_do_state_should_skip = 0;
6270 // legal to set the should skip state anywhere in this function
6271 game_do_state_common(state); // do stuff that may need to be done regardless of state
6273 if(Game_do_state_should_skip){
6278 case GS_STATE_MAIN_MENU:
6279 game_set_frametime(GS_STATE_MAIN_MENU);
6280 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6283 main_hall_do(flFrametime);
6287 case GS_STATE_OPTIONS_MENU:
6288 game_set_frametime(GS_STATE_OPTIONS_MENU);
6289 options_menu_do_frame(flFrametime);
6292 case GS_STATE_BARRACKS_MENU:
6293 game_set_frametime(GS_STATE_BARRACKS_MENU);
6294 barracks_do_frame(flFrametime);
6297 case GS_STATE_TRAINING_MENU:
6298 game_set_frametime(GS_STATE_TRAINING_MENU);
6299 training_menu_do_frame(flFrametime);
6302 case GS_STATE_TECH_MENU:
6303 game_set_frametime(GS_STATE_TECH_MENU);
6304 techroom_do_frame(flFrametime);
6307 case GS_STATE_GAMEPLAY_HELP:
6308 game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6309 gameplay_help_do_frame(flFrametime);
6312 case GS_STATE_GAME_PLAY: // do stuff that should be done during gameplay
6316 case GS_STATE_GAME_PAUSED:
6320 case GS_STATE_DEBUG_PAUSED:
6322 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6327 case GS_STATE_TRAINING_PAUSED:
6328 game_training_pause_do();
6331 case GS_STATE_LOAD_MISSION_MENU:
6332 game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6333 mission_load_menu_do();
6336 case GS_STATE_BRIEFING:
6337 game_set_frametime(GS_STATE_BRIEFING);
6338 brief_do_frame(flFrametime);
6341 case GS_STATE_DEBRIEF:
6342 game_set_frametime(GS_STATE_DEBRIEF);
6343 debrief_do_frame(flFrametime);
6346 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6347 game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6348 multi_df_debrief_do();
6351 case GS_STATE_SHIP_SELECT:
6352 game_set_frametime(GS_STATE_SHIP_SELECT);
6353 ship_select_do(flFrametime);
6356 case GS_STATE_WEAPON_SELECT:
6357 game_set_frametime(GS_STATE_WEAPON_SELECT);
6358 weapon_select_do(flFrametime);
6361 case GS_STATE_MISSION_LOG_SCROLLBACK:
6362 game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6363 hud_scrollback_do_frame(flFrametime);
6366 case GS_STATE_HUD_CONFIG:
6367 game_set_frametime(GS_STATE_HUD_CONFIG);
6368 hud_config_do_frame(flFrametime);
6371 case GS_STATE_MULTI_JOIN_GAME:
6372 game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6373 multi_join_game_do_frame();
6376 case GS_STATE_MULTI_HOST_SETUP:
6377 game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6378 multi_create_game_do();
6381 case GS_STATE_MULTI_CLIENT_SETUP:
6382 game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6383 multi_game_client_setup_do_frame();
6386 case GS_STATE_CONTROL_CONFIG:
6387 game_set_frametime(GS_STATE_CONTROL_CONFIG);
6388 control_config_do_frame(flFrametime);
6391 case GS_STATE_DEATH_DIED:
6395 case GS_STATE_DEATH_BLEW_UP:
6399 case GS_STATE_SIMULATOR_ROOM:
6400 game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6401 sim_room_do_frame(flFrametime);
6404 case GS_STATE_CAMPAIGN_ROOM:
6405 game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6406 campaign_room_do_frame(flFrametime);
6409 case GS_STATE_RED_ALERT:
6410 game_set_frametime(GS_STATE_RED_ALERT);
6411 red_alert_do_frame(flFrametime);
6414 case GS_STATE_CMD_BRIEF:
6415 game_set_frametime(GS_STATE_CMD_BRIEF);
6416 cmd_brief_do_frame(flFrametime);
6419 case GS_STATE_CREDITS:
6420 game_set_frametime(GS_STATE_CREDITS);
6421 credits_do_frame(flFrametime);
6424 case GS_STATE_VIEW_MEDALS:
6425 game_set_frametime(GS_STATE_VIEW_MEDALS);
6429 case GS_STATE_SHOW_GOALS:
6430 game_set_frametime(GS_STATE_SHOW_GOALS);
6431 mission_show_goals_do_frame(flFrametime);
6434 case GS_STATE_HOTKEY_SCREEN:
6435 game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6436 mission_hotkey_do_frame(flFrametime);
6439 case GS_STATE_VIEW_CUTSCENES:
6440 game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6441 cutscenes_screen_do_frame();
6444 case GS_STATE_MULTI_STD_WAIT:
6445 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6446 multi_standalone_wait_do();
6449 case GS_STATE_STANDALONE_MAIN:
6450 game_set_frametime(GS_STATE_STANDALONE_MAIN);
6451 standalone_main_do();
6454 case GS_STATE_MULTI_PAUSED:
6455 game_set_frametime(GS_STATE_MULTI_PAUSED);
6459 case GS_STATE_TEAM_SELECT:
6460 game_set_frametime(GS_STATE_TEAM_SELECT);
6464 case GS_STATE_INGAME_PRE_JOIN:
6465 game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6466 multi_ingame_select_do();
6469 case GS_STATE_EVENT_DEBUG:
6471 game_set_frametime(GS_STATE_EVENT_DEBUG);
6472 game_show_event_debug(flFrametime);
6476 case GS_STATE_STANDALONE_POSTGAME:
6477 game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6478 multi_standalone_postgame_do();
6481 case GS_STATE_INITIAL_PLAYER_SELECT:
6482 game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6486 case GS_STATE_MULTI_MISSION_SYNC:
6487 game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6491 case GS_STATE_MULTI_START_GAME:
6492 game_set_frametime(GS_STATE_MULTI_START_GAME);
6493 multi_start_game_do();
6496 case GS_STATE_MULTI_HOST_OPTIONS:
6497 game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6498 multi_host_options_do();
6501 case GS_STATE_END_OF_CAMPAIGN:
6502 mission_campaign_end_do();
6505 case GS_STATE_END_DEMO:
6506 game_set_frametime(GS_STATE_END_DEMO);
6507 end_demo_campaign_do();
6510 case GS_STATE_LOOP_BRIEF:
6511 game_set_frametime(GS_STATE_LOOP_BRIEF);
6515 } // end switch(gs_current_state)
6519 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6520 int game_do_ram_check(int ram_in_bytes)
6522 if ( ram_in_bytes < 30*1024*1024 ) {
6523 int allowed_to_run = 1;
6524 if ( ram_in_bytes < 25*1024*1024 ) {
6529 int Freespace_total_ram_MB;
6530 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6532 if ( allowed_to_run ) {
6534 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);
6539 msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6540 if ( msgbox_rval == IDCANCEL ) {
6547 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);
6549 MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6560 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6561 // If so, copy it over and remove the update directory.
6562 void game_maybe_update_launcher(char *exe_dir)
6565 char src_filename[MAX_PATH];
6566 char dest_filename[MAX_PATH];
6568 strcpy(src_filename, exe_dir);
6569 strcat(src_filename, NOX("\\update\\freespace.exe"));
6571 strcpy(dest_filename, exe_dir);
6572 strcat(dest_filename, NOX("\\freespace.exe"));
6574 // see if src_filename exists
6576 fp = fopen(src_filename, "rb");
6582 SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6584 // copy updated freespace.exe to freespace exe dir
6585 if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6586 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 );
6590 // delete the file in the update directory
6591 DeleteFile(src_filename);
6593 // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6594 char update_dir[MAX_PATH];
6595 strcpy(update_dir, exe_dir);
6596 strcat(update_dir, NOX("\\update"));
6597 RemoveDirectory(update_dir);
6603 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6607 int sub_total_destroyed = 0;
6611 // get the total for all his children
6612 for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling ) {
6613 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6616 // find the # of faces for this _individual_ object
6617 total = submodel_get_num_polys(model_num, sm);
6618 if(strstr(pm->submodel[sm].name, "-destroyed")){
6619 sub_total_destroyed = total;
6623 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6626 *out_total += total + sub_total;
6627 *out_destroyed_total += sub_total_destroyed;
6630 #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);
6631 void game_spew_pof_info()
6633 char *pof_list[1000];
6636 int idx, model_num, i, j;
6638 int total, root_total, model_total, destroyed_total, counted;
6642 num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6644 // spew info on all the pofs
6650 out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6655 for(idx=0; idx<num_files; idx++, counted++){
6656 sprintf(str, "%s.pof", pof_list[idx]);
6657 model_num = model_load(str, 0, NULL);
6659 pm = model_get(model_num);
6661 // if we have a real model
6666 // go through and print all raw submodels
6667 cfputs("RAW\n", out);
6670 for (i=0; i<pm->n_models; i++) {
6671 total = submodel_get_num_polys(model_num, i);
6673 model_total += total;
6674 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6677 sprintf(str, "Model total %d\n", model_total);
6680 // now go through and do it by LOD
6681 cfputs("BY LOD\n\n", out);
6682 for(i=0; i<pm->n_detail_levels; i++){
6683 sprintf(str, "LOD %d\n", i);
6687 root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6689 destroyed_total = 0;
6690 for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling ) {
6691 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6694 sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6697 sprintf(str, "TOTAL: %d\n", total + root_total);
6699 sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6701 sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6704 cfputs("------------------------------------------------------------------------\n\n", out);
6708 if(counted >= MAX_POLYGON_MODELS - 5){
6721 game_spew_pof_info();
6724 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6729 // Don't let more than one instance of Freespace run.
6730 HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6732 SetForegroundWindow(hwnd);
6737 // Find out how much RAM is on this machine
6740 ms.dwLength = sizeof(MEMORYSTATUS);
6741 GlobalMemoryStatus(&ms);
6742 Freespace_total_ram = ms.dwTotalPhys;
6744 if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6748 if ( ms.dwTotalVirtual < 1024 ) {
6749 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6753 if (!vm_init(24*1024*1024)) {
6754 MessageBox( NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK );
6758 char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6760 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);
6768 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6769 dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6770 seem worth bothering with.
6774 lResult = RegOpenKeyEx(
6775 HKEY_LOCAL_MACHINE, // Where it is
6776 "Software\\Microsoft\\DirectX", // name of key
6777 NULL, // DWORD reserved
6778 KEY_QUERY_VALUE, // Allows all changes
6779 &hKey // Location to store key
6782 if (lResult == ERROR_SUCCESS) {
6784 DWORD dwType, dwLen;
6787 lResult = RegQueryValueEx(
6788 hKey, // Handle to key
6789 "Version", // The values name
6790 NULL, // DWORD reserved
6791 &dwType, // What kind it is
6792 (ubyte *) version, // value to set
6793 &dwLen // How many bytes to set
6796 if (lResult == ERROR_SUCCESS) {
6797 dx_version = atoi(strstr(version, ".") + 1);
6801 DWORD dwType, dwLen;
6804 lResult = RegQueryValueEx(
6805 hKey, // Handle to key
6806 "InstalledVersion", // The values name
6807 NULL, // DWORD reserved
6808 &dwType, // What kind it is
6809 (ubyte *) &val, // value to set
6810 &dwLen // How many bytes to set
6813 if (lResult == ERROR_SUCCESS) {
6821 if (dx_version < 3) {
6822 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can get the\n"
6823 "latest version of DirectX at:\n\n"
6824 "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6826 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected. You can install\n"
6827 "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6832 //=====================================================
6833 // Make sure we're running in the right directory.
6837 if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 ) {
6838 char *p = exe_dir + strlen(exe_dir);
6840 // chop off the filename
6841 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') ) {
6847 if ( strlen(exe_dir) > 0 ) {
6848 SetCurrentDirectory(exe_dir);
6851 // check for updated freespace.exe
6852 game_maybe_update_launcher(exe_dir);
6860 extern void windebug_memwatch_init();
6861 windebug_memwatch_init();
6865 parse_cmdline(szCmdLine);
6867 #ifdef STANDALONE_ONLY_BUILD
6869 nprintf(("Network", "Standalone running"));
6872 nprintf(("Network", "Standalone running"));
6880 // maybe spew pof stuff
6881 if(Cmdline_spew_pof_info){
6882 game_spew_pof_info();
6887 // non-demo, non-standalone, play the intro movie
6892 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) ){
6894 #if defined(OEM_BUILD)
6895 game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6897 game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6898 #endif // defined(OEM_BUILD)
6903 if ( !Is_standalone ) {
6905 // release -- movies always play
6908 // 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
6909 movie_play( NOX("intro.mve"), 0 );
6911 // debug version, movie will only play with -showmovies
6912 #elif !defined(NDEBUG)
6914 movie_play( NOX("intro.mve"), 0);
6917 if ( Cmdline_show_movies )
6918 movie_play( NOX("intro.mve"), 0 );
6927 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6929 gameseq_post_event(GS_EVENT_GAME_INIT); // start the game rolling -- check for default pilot, or go to the pilot select screen
6933 // only important for non THREADED mode
6936 state = gameseq_process_events();
6937 if ( state == GS_STATE_QUIT_GAME ){
6944 demo_upsell_show_screens();
6946 #elif defined(OEM_BUILD)
6947 // show upsell screens on exit
6948 oem_upsell_show_screens();
6955 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6961 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6963 __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6965 // Do nothing here - RecordExceptionInfo() has already done
6966 // everything that is needed. Actually this code won't even
6967 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6968 // the __except clause.
6972 nprintf(("WinMain", "exceptions shall fall through"));
6974 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6980 // launcher the fslauncher program on exit
6981 void game_launch_launcher_on_exit()
6985 PROCESS_INFORMATION pi;
6986 char cmd_line[2048];
6987 char original_path[1024] = "";
6989 memset( &si, 0, sizeof(STARTUPINFO) );
6993 _getcwd(original_path, 1023);
6995 // set up command line
6996 strcpy(cmd_line, original_path);
6997 strcat(cmd_line, "\\");
6998 strcat(cmd_line, LAUNCHER_FNAME);
6999 strcat(cmd_line, " -straight_to_update");
7001 BOOL ret = CreateProcess( NULL, // pointer to name of executable module
7002 cmd_line, // pointer to command line string
7003 NULL, // pointer to process security attributes
7004 NULL, // pointer to thread security attributes
7005 FALSE, // handle inheritance flag
7006 CREATE_DEFAULT_ERROR_MODE, // creation flags
7007 NULL, // pointer to new environment block
7008 NULL, // pointer to current directory name
7009 &si, // pointer to STARTUPINFO
7010 &pi // pointer to PROCESS_INFORMATION
7012 // to eliminate build warnings
7022 // This function is called when FreeSpace terminates normally.
7024 void game_shutdown(void)
7030 // don't ever flip a page on the standalone!
7031 if(!(Game_mode & GM_STANDALONE_SERVER)){
7037 // if the player has left the "player select" screen and quit the game without actually choosing
7038 // a player, Player will be NULL, in which case we shouldn't write the player file out!
7039 if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7043 // load up common multiplayer icons
7044 multi_unload_common_icons();
7046 shockwave_close(); // release any memory used by shockwave system
7047 fireball_close(); // free fireball system
7048 ship_close(); // free any memory that was allocated for the ships
7049 hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7050 unload_animating_pointer();// frees the frames used for the animating mouse pointer
7051 bm_unload_all(); // free bitmaps
7052 mission_campaign_close(); // close out the campaign stuff
7053 multi_voice_close(); // close down multiplayer voice (including freeing buffers, etc)
7055 #ifdef MULTI_USE_LAG
7059 // the menu close functions will unload the bitmaps if they were displayed during the game
7060 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7063 training_menu_close();
7066 extern void joy_close();
7069 audiostream_close();
7071 event_music_close();
7075 // HACKITY HACK HACK
7076 // if this flag is set, we should be firing up the launcher when exiting freespace
7077 extern int Multi_update_fireup_launcher_on_exit;
7078 if(Multi_update_fireup_launcher_on_exit){
7079 game_launch_launcher_on_exit();
7083 // game_stop_looped_sounds()
7085 // This function will call the appropriate stop looped sound functions for those
7086 // modules which use looping sounds. It is not enough just to stop a looping sound
7087 // at the DirectSound level, the game is keeping track of looping sounds, and this
7088 // function is used to inform the game that looping sounds are being halted.
7090 void game_stop_looped_sounds()
7092 hud_stop_looped_locking_sounds();
7093 hud_stop_looped_engine_sounds();
7094 afterburner_stop_sounds();
7095 player_stop_looped_sounds();
7096 obj_snd_stop_all(); // stop all object-linked persistant sounds
7097 game_stop_subspace_ambient_sound();
7098 snd_stop(Radar_static_looping);
7099 Radar_static_looping = -1;
7100 snd_stop(Target_static_looping);
7101 shipfx_stop_engine_wash_sound();
7102 Target_static_looping = -1;
7105 //////////////////////////////////////////////////////////////////////////
7107 // Code for supporting an animating mouse pointer
7110 //////////////////////////////////////////////////////////////////////////
7112 typedef struct animating_obj
7121 static animating_obj Animating_mouse;
7123 // ----------------------------------------------------------------------------
7124 // init_animating_pointer()
7126 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7127 // gets properly initialized
7129 void init_animating_pointer()
7131 Animating_mouse.first_frame = -1;
7132 Animating_mouse.num_frames = 0;
7133 Animating_mouse.current_frame = -1;
7134 Animating_mouse.time = 0.0f;
7135 Animating_mouse.elapsed_time = 0.0f;
7138 // ----------------------------------------------------------------------------
7139 // load_animating_pointer()
7141 // Called at game init to load in the frames for the animating mouse pointer
7143 // input: filename => filename of animation file that holds the animation
7145 void load_animating_pointer(char *filename, int dx, int dy)
7150 init_animating_pointer();
7152 am = &Animating_mouse;
7153 am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7154 if ( am->first_frame == -1 )
7155 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7156 am->current_frame = 0;
7157 am->time = am->num_frames / i2fl(fps);
7160 // ----------------------------------------------------------------------------
7161 // unload_animating_pointer()
7163 // Called at game shutdown to free the memory used to store the animation frames
7165 void unload_animating_pointer()
7170 am = &Animating_mouse;
7171 for ( i = 0; i < am->num_frames; i++ ) {
7172 Assert( (am->first_frame+i) >= 0 );
7173 bm_release(am->first_frame + i);
7176 am->first_frame = -1;
7178 am->current_frame = -1;
7181 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7182 void game_render_mouse(float frametime)
7187 // if animating cursor exists, play the next frame
7188 am = &Animating_mouse;
7189 if ( am->first_frame != -1 ) {
7190 mouse_get_pos(&mx, &my);
7191 am->elapsed_time += frametime;
7192 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7193 if ( am->current_frame >= am->num_frames ) {
7194 am->current_frame = 0;
7195 am->elapsed_time = 0.0f;
7197 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7201 // ----------------------------------------------------------------------------
7202 // game_maybe_draw_mouse()
7204 // determines whether to draw the mouse pointer at all, and what frame of
7205 // animation to use if the mouse is animating
7207 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7209 // input: frametime => elapsed frame time in seconds since last call
7211 void game_maybe_draw_mouse(float frametime)
7215 game_state = gameseq_get_state();
7217 switch ( game_state ) {
7218 case GS_STATE_GAME_PAUSED:
7219 // case GS_STATE_MULTI_PAUSED:
7220 case GS_STATE_GAME_PLAY:
7221 case GS_STATE_DEATH_DIED:
7222 case GS_STATE_DEATH_BLEW_UP:
7223 if ( popup_active() || popupdead_is_active() ) {
7235 if ( !Mouse_hidden )
7236 game_render_mouse(frametime);
7240 void game_do_training_checks()
7244 waypoint_list *wplp;
7246 if (Training_context & TRAINING_CONTEXT_SPEED) {
7247 s = (int) Player_obj->phys_info.fspeed;
7248 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7249 if (!Training_context_speed_set) {
7250 Training_context_speed_set = 1;
7251 Training_context_speed_timestamp = timestamp();
7255 Training_context_speed_set = 0;
7258 if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7259 wplp = &Waypoint_lists[Training_context_path];
7260 if (wplp->count > Training_context_goal_waypoint) {
7261 i = Training_context_goal_waypoint;
7263 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7264 if (d <= Training_context_distance) {
7265 Training_context_at_waypoint = i;
7266 if (Training_context_goal_waypoint == i) {
7267 Training_context_goal_waypoint++;
7268 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7275 if (i == wplp->count)
7278 } while (i != Training_context_goal_waypoint);
7282 if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7283 Players_target = Player_ai->target_objnum;
7284 Players_targeted_subsys = Player_ai->targeted_subsys;
7285 Players_target_timestamp = timestamp();
7289 /////////// Following is for event debug view screen
7293 #define EVENT_DEBUG_MAX 5000
7294 #define EVENT_DEBUG_EVENT 0x8000
7296 int Event_debug_index[EVENT_DEBUG_MAX];
7299 void game_add_event_debug_index(int n, int indent)
7301 if (ED_count < EVENT_DEBUG_MAX)
7302 Event_debug_index[ED_count++] = n | (indent << 16);
7305 void game_add_event_debug_sexp(int n, int indent)
7310 if (Sexp_nodes[n].first >= 0) {
7311 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7312 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7316 game_add_event_debug_index(n, indent);
7317 if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7318 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7320 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7323 void game_event_debug_init()
7328 for (e=0; e<Num_mission_events; e++) {
7329 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7330 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7334 void game_show_event_debug(float frametime)
7338 int font_height, font_width;
7340 static int scroll_offset = 0;
7342 k = game_check_key();
7348 if (scroll_offset < 0)
7358 scroll_offset -= 20;
7359 if (scroll_offset < 0)
7364 scroll_offset += 20; // not font-independent, hard-coded since I counted the lines!
7368 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7374 gr_set_color_fast(&Color_bright);
7376 gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7378 gr_set_color_fast(&Color_normal);
7380 gr_get_string_size(&font_width, &font_height, NOX("test"));
7381 y_max = gr_screen.max_h - font_height - 5;
7385 while (k < ED_count) {
7386 if (y_index > y_max)
7389 z = Event_debug_index[k];
7390 if (z & EVENT_DEBUG_EVENT) {
7392 sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7393 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7394 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7395 Mission_events[z].repeat_count, Mission_events[z].interval);
7403 strcat(buf, Sexp_nodes[z & 0x7fff].text);
7404 switch (Sexp_nodes[z & 0x7fff].value) {
7406 strcat(buf, NOX(" (True)"));
7410 strcat(buf, NOX(" (False)"));
7413 case SEXP_KNOWN_TRUE:
7414 strcat(buf, NOX(" (Always true)"));
7417 case SEXP_KNOWN_FALSE:
7418 strcat(buf, NOX(" (Always false)"));
7421 case SEXP_CANT_EVAL:
7422 strcat(buf, NOX(" (Can't eval)"));
7426 case SEXP_NAN_FOREVER:
7427 strcat(buf, NOX(" (Not a number)"));
7432 gr_printf(10, y_index, buf);
7433 y_index += font_height;
7446 extern int Tmap_npixels;
7448 int Tmap_num_too_big = 0;
7449 int Num_models_needing_splitting = 0;
7451 void Time_model( int modelnum )
7453 // mprintf(( "Timing ship '%s'\n", si->name ));
7455 vector eye_pos, model_pos;
7456 matrix eye_orient, model_orient;
7458 polymodel *pm = model_get( modelnum );
7460 int l = strlen(pm->filename);
7462 if ( (l == '/') || (l=='\\') || (l==':')) {
7468 char *pof_file = &pm->filename[l];
7470 int model_needs_splitting = 0;
7472 //fprintf( Texture_fp, "Model: %s\n", pof_file );
7474 for (i=0; i<pm->n_textures; i++ ) {
7475 char filename[1024];
7478 int bmp_num = pm->original_textures[i];
7479 if ( bmp_num > -1 ) {
7480 bm_get_palette(pm->original_textures[i], pal, filename );
7482 bm_get_info( pm->original_textures[i],&w, &h );
7485 if ( (w > 512) || (h > 512) ) {
7486 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7488 model_needs_splitting++;
7491 //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7495 if ( model_needs_splitting ) {
7496 Num_models_needing_splitting++;
7498 eye_orient = model_orient = vmd_identity_matrix;
7499 eye_pos = model_pos = vmd_zero_vector;
7501 eye_pos.xyz.z = -pm->rad*2.0f;
7503 vector eye_to_model;
7505 vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7506 vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7508 fix t1 = timer_get_fixed_seconds();
7511 ta.p = ta.b = ta.h = 0.0f;
7516 int bitmaps_used_this_frame, bitmaps_new_this_frame;
7518 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7520 modelstats_num_polys = modelstats_num_verts = 0;
7522 while( ta.h < PI2 ) {
7525 vm_angles_2_matrix(&m1, &ta );
7526 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7533 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );
7535 model_clear_instance( modelnum );
7536 model_set_detail_level(0); // use highest detail level
7537 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL); //|MR_NO_POLYS );
7545 int k = key_inkey();
7546 if ( k == KEY_ESC ) {
7551 fix t2 = timer_get_fixed_seconds();
7553 bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7554 //bitmaps_used_this_frame /= framecount;
7556 modelstats_num_polys /= framecount;
7557 modelstats_num_verts /= framecount;
7559 Tmap_npixels /=framecount;
7562 mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7563 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 );
7564 // 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 );
7570 int Time_models = 0;
7571 DCF_BOOL( time_models, Time_models );
7573 void Do_model_timings_test()
7577 if ( !Time_models ) return;
7579 mprintf(( "Timing models!\n" ));
7583 ubyte model_used[MAX_POLYGON_MODELS];
7584 int model_id[MAX_POLYGON_MODELS];
7585 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7590 for (i=0; i<Num_ship_types; i++ ) {
7591 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7593 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7594 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7597 Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7598 if ( !Texture_fp ) return;
7600 Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7601 if ( !Time_fp ) return;
7603 fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7604 // fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7606 for (i=0; i<MAX_POLYGON_MODELS; i++ ) {
7607 if ( model_used[i] ) {
7608 Time_model( model_id[i] );
7612 fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7613 fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7622 // Call this function when you want to inform the player that a feature is not
7623 // enabled in the DEMO version of FreSpace
7624 void game_feature_not_in_demo_popup()
7626 popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7629 // format the specified time (fixed point) into a nice string
7630 void game_format_time(fix m_time,char *time_str)
7633 int hours,minutes,seconds;
7636 mtime = f2fl(m_time);
7638 // get the hours, minutes and seconds
7639 hours = (int)(mtime / 3600.0f);
7641 mtime -= (3600.0f * (float)hours);
7643 seconds = (int)mtime%60;
7644 minutes = (int)mtime/60;
7646 // print the hour if necessary
7648 sprintf(time_str,XSTR( "%d:", 201),hours);
7649 // if there are less than 10 minutes, print a leading 0
7651 strcpy(tmp,NOX("0"));
7652 strcat(time_str,tmp);
7656 // print the minutes
7658 sprintf(tmp,XSTR( "%d:", 201),minutes);
7659 strcat(time_str,tmp);
7661 sprintf(time_str,XSTR( "%d:", 201),minutes);
7664 // print the seconds
7666 strcpy(tmp,NOX("0"));
7667 strcat(time_str,tmp);
7669 sprintf(tmp,"%d",seconds);
7670 strcat(time_str,tmp);
7673 // Stuff version string in *str.
7674 void get_version_string(char *str)
7677 if ( FS_VERSION_BUILD == 0 ) {
7678 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7680 sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7683 #if defined (FS2_DEMO)
7685 #elif defined (OEM_BUILD)
7686 strcat(str, " (OEM)");
7692 char myname[_MAX_PATH];
7693 int namelen, major, minor, build, waste;
7694 unsigned int buf_size;
7700 // Find my EXE file name
7701 hMod = GetModuleHandle(NULL);
7702 namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7704 version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7705 infop = (char *)malloc(version_size);
7706 result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7708 // get the product version
7709 result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7710 sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7712 sprintf(str,"Dv%d.%02d",major, minor);
7714 sprintf(str,"v%d.%02d",major, minor);
7719 void get_version_string_short(char *str)
7721 sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7724 // ----------------------------------------------------------------
7726 // OEM UPSELL SCREENS BEGIN
7728 // ----------------------------------------------------------------
7729 #if defined(OEM_BUILD)
7731 #define NUM_OEM_UPSELL_SCREENS 3
7732 #define OEM_UPSELL_SCREEN_DELAY 10000
7734 static int Oem_upsell_bitmaps_loaded = 0;
7735 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7736 static int Oem_upsell_screen_number = 0;
7737 static int Oem_upsell_show_next_bitmap_time;
7740 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] =
7753 static int Oem_normal_cursor = -1;
7754 static int Oem_web_cursor = -1;
7755 //#define OEM_UPSELL_URL "http://www.interplay-store.com/"
7756 #define OEM_UPSELL_URL "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7758 void oem_upsell_next_screen()
7760 Oem_upsell_screen_number++;
7761 if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7762 // extra long delay, mouse shown on last upsell
7763 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7767 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7771 void oem_upsell_load_bitmaps()
7775 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7776 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7780 void oem_upsell_unload_bitmaps()
7784 for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7785 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7786 bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7791 Oem_upsell_bitmaps_loaded = 0;
7794 // clickable hotspot on 3rd OEM upsell screen
7795 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7797 28, 350, 287, 96 // x, y, w, h
7800 45, 561, 460, 152 // x, y, w, h
7804 void oem_upsell_show_screens()
7806 int current_time, k;
7809 if ( !Oem_upsell_bitmaps_loaded ) {
7810 oem_upsell_load_bitmaps();
7811 Oem_upsell_bitmaps_loaded = 1;
7814 // may use upsell screens more than once
7815 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7816 Oem_upsell_screen_number = 0;
7822 int nframes; // used to pass, not really needed (should be 1)
7823 Oem_normal_cursor = gr_get_cursor_bitmap();
7824 Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7825 Assert(Oem_web_cursor >= 0);
7826 if (Oem_web_cursor < 0) {
7827 Oem_web_cursor = Oem_normal_cursor;
7832 //oem_reset_trailer_timer();
7834 current_time = timer_get_milliseconds();
7839 // advance screen on keypress or timeout
7840 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7841 oem_upsell_next_screen();
7844 // check if we are done
7845 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7846 Oem_upsell_screen_number--;
7849 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7854 // show me the upsell
7855 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {
7856 gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7860 // if this is the 3rd upsell, make it clickable, d00d
7861 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7863 int button_state = mouse_get_pos(&mx, &my);
7864 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])
7865 && (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]) )
7868 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7871 if (button_state & MOUSE_LEFT_BUTTON) {
7873 multi_pxo_url(OEM_UPSELL_URL);
7877 // switch cursor back to normal one
7878 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7883 if (gameseq_get_state() != GS_STATE_END_DEMO) {
7893 oem_upsell_unload_bitmaps();
7895 // switch cursor back to normal one
7896 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7900 #endif // defined(OEM_BUILD)
7901 // ----------------------------------------------------------------
7903 // OEM UPSELL SCREENS END
7905 // ----------------------------------------------------------------
7909 // ----------------------------------------------------------------
7911 // DEMO UPSELL SCREENS BEGIN
7913 // ----------------------------------------------------------------
7917 //#define NUM_DEMO_UPSELL_SCREENS 4
7919 #define NUM_DEMO_UPSELL_SCREENS 2
7920 #define DEMO_UPSELL_SCREEN_DELAY 3000
7922 static int Demo_upsell_bitmaps_loaded = 0;
7923 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7924 static int Demo_upsell_screen_number = 0;
7925 static int Demo_upsell_show_next_bitmap_time;
7928 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] =
7941 void demo_upsell_next_screen()
7943 Demo_upsell_screen_number++;
7944 if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7945 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7947 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7951 if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7952 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7953 #ifndef HARDWARE_ONLY
7954 palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7961 void demo_upsell_load_bitmaps()
7965 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7966 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7970 void demo_upsell_unload_bitmaps()
7974 for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7975 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7976 bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7981 Demo_upsell_bitmaps_loaded = 0;
7984 void demo_upsell_show_screens()
7986 int current_time, k;
7989 if ( !Demo_upsell_bitmaps_loaded ) {
7990 demo_upsell_load_bitmaps();
7991 Demo_upsell_bitmaps_loaded = 1;
7994 // may use upsell screens more than once
7995 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7996 Demo_upsell_screen_number = 0;
8003 demo_reset_trailer_timer();
8005 current_time = timer_get_milliseconds();
8012 // don't time out, wait for keypress
8014 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8015 demo_upsell_next_screen();
8020 demo_upsell_next_screen();
8023 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8024 Demo_upsell_screen_number--;
8027 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8032 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8033 gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8038 if (gameseq_get_state() != GS_STATE_END_DEMO) {
8048 demo_upsell_unload_bitmaps();
8053 // ----------------------------------------------------------------
8055 // DEMO UPSELL SCREENS END
8057 // ----------------------------------------------------------------
8060 // ----------------------------------------------------------------
8062 // Subspace Ambient Sound START
8064 // ----------------------------------------------------------------
8066 static int Subspace_ambient_left_channel = -1;
8067 static int Subspace_ambient_right_channel = -1;
8070 void game_start_subspace_ambient_sound()
8072 if ( Subspace_ambient_left_channel < 0 ) {
8073 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8076 if ( Subspace_ambient_right_channel < 0 ) {
8077 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8081 void game_stop_subspace_ambient_sound()
8083 if ( Subspace_ambient_left_channel >= 0 ) {
8084 snd_stop(Subspace_ambient_left_channel);
8085 Subspace_ambient_left_channel = -1;
8088 if ( Subspace_ambient_right_channel >= 0 ) {
8089 snd_stop(Subspace_ambient_right_channel);
8090 Subspace_ambient_right_channel = -1;
8094 // ----------------------------------------------------------------
8096 // Subspace Ambient Sound END
8098 // ----------------------------------------------------------------
8100 // ----------------------------------------------------------------
8102 // CDROM detection code START
8104 // ----------------------------------------------------------------
8106 #define CD_SIZE_72_MINUTE_MAX (697000000)
8108 uint game_get_cd_used_space(char *path)
8112 char use_path[512] = "";
8113 char sub_path[512] = "";
8114 WIN32_FIND_DATA find;
8117 // recurse through all files and directories
8118 strcpy(use_path, path);
8119 strcat(use_path, "*.*");
8120 find_handle = FindFirstFile(use_path, &find);
8123 if(find_handle == INVALID_HANDLE_VALUE){
8129 // subdirectory. make sure to ignore . and ..
8130 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8132 strcpy(sub_path, path);
8133 strcat(sub_path, find.cFileName);
8134 strcat(sub_path, "\\");
8135 total += game_get_cd_used_space(sub_path);
8137 total += (uint)find.nFileSizeLow;
8139 } while(FindNextFile(find_handle, &find));
8142 FindClose(find_handle);
8154 // if volume_name is non-null, the CD name must match that
8155 int find_freespace_cd(char *volume_name)
8158 char oldpath[MAX_PATH];
8162 int volume_match = 0;
8166 GetCurrentDirectory(MAX_PATH, oldpath);
8168 for (i = 0; i < 26; i++)
8174 path[0] = (char)('A'+i);
8175 if (GetDriveType(path) == DRIVE_CDROM) {
8177 if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8178 nprintf(("CD", "CD volume: %s\n", volume));
8180 // check for any CD volume
8181 int volume1_present = 0;
8182 int volume2_present = 0;
8183 int volume3_present = 0;
8185 char full_check[512] = "";
8187 // look for setup.exe
8188 strcpy(full_check, path);
8189 strcat(full_check, "setup.exe");
8190 find_handle = _findfirst(full_check, &find);
8191 if(find_handle != -1){
8192 volume1_present = 1;
8193 _findclose(find_handle);
8196 // look for intro.mve
8197 strcpy(full_check, path);
8198 strcat(full_check, "intro.mve");
8199 find_handle = _findfirst(full_check, &find);
8200 if(find_handle != -1){
8201 volume2_present = 1;
8202 _findclose(find_handle);
8205 // look for endpart1.mve
8206 strcpy(full_check, path);
8207 strcat(full_check, "endpart1.mve");
8208 find_handle = _findfirst(full_check, &find);
8209 if(find_handle != -1){
8210 volume3_present = 1;
8211 _findclose(find_handle);
8214 // see if we have the specific CD we're looking for
8215 if ( volume_name ) {
8217 if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8221 if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8225 if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8229 if ( volume1_present || volume2_present || volume3_present ) {
8234 // 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
8235 if ( volume_match ){
8237 // 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
8238 if(volume2_present || volume3_present) {
8239 // first step - check to make sure its a cdrom
8240 if(GetDriveType(path) != DRIVE_CDROM){
8244 #if !defined(OEM_BUILD)
8245 // oem not on 80 min cds, so dont check tha size
8247 uint used_space = game_get_cd_used_space(path);
8248 if(used_space < CD_SIZE_72_MINUTE_MAX){
8251 #endif // !defined(OEM_BUILD)
8259 #endif // RELEASE_REAL
8265 SetCurrentDirectory(oldpath);
8274 int set_cdrom_path(int drive_num)
8278 if (drive_num < 0) { //no CD
8280 // strcpy(CDROM_dir,"j:\\FreeSpaceCD\\"); //set directory
8283 strcpy(Game_CDROM_dir,""); //set directory
8287 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num ); //set directory
8303 i = find_freespace_cd();
8305 rval = set_cdrom_path(i);
8309 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8311 nprintf(("CD", "FreeSpace CD not found\n"));
8319 int Last_cd_label_found = 0;
8320 char Last_cd_label[256];
8322 int game_cd_changed()
8329 if ( strlen(Game_CDROM_dir) == 0 ) {
8333 found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8335 if ( found != Last_cd_label_found ) {
8336 Last_cd_label_found = found;
8338 mprintf(( "CD '%s' was inserted\n", label ));
8341 mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8345 if ( Last_cd_label_found ) {
8346 if ( !stricmp( Last_cd_label, label )) {
8347 //mprintf(( "CD didn't change\n" ));
8349 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8353 // none found before, none found now.
8354 //mprintf(( "still no CD...\n" ));
8358 Last_cd_label_found = found;
8360 strcpy( Last_cd_label, label );
8362 strcpy( Last_cd_label, "" );
8373 // check if _any_ FreeSpace2 CDs are in the drive
8374 // return: 1 => CD now in drive
8375 // 0 => Could not find CD, they refuse to put it in the drive
8376 int game_do_cd_check(char *volume_name)
8378 #if !defined(GAME_CD_CHECK)
8384 int num_attempts = 0;
8385 int refresh_files = 0;
8387 int path_set_ok, popup_rval;
8389 cd_drive_num = find_freespace_cd(volume_name);
8390 path_set_ok = set_cdrom_path(cd_drive_num);
8391 if ( path_set_ok ) {
8393 if ( refresh_files ) {
8405 // no CD found, so prompt user
8406 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8408 if ( popup_rval != 1 ) {
8413 if ( num_attempts++ > 5 ) {
8424 // check if _any_ FreeSpace2 CDs are in the drive
8425 // return: 1 => CD now in drive
8426 // 0 => Could not find CD, they refuse to put it in the drive
8427 int game_do_cd_check_specific(char *volume_name, int cdnum)
8432 int num_attempts = 0;
8433 int refresh_files = 0;
8435 int path_set_ok, popup_rval;
8437 cd_drive_num = find_freespace_cd(volume_name);
8438 path_set_ok = set_cdrom_path(cd_drive_num);
8439 if ( path_set_ok ) {
8441 if ( refresh_files ) {
8452 // no CD found, so prompt user
8453 #if defined(DVD_MESSAGE_HACK)
8454 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8456 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8459 if ( popup_rval != 1 ) {
8464 if ( num_attempts++ > 5 ) {
8474 // only need to do this in RELEASE_REAL
8475 int game_do_cd_mission_check(char *filename)
8481 fs_builtin_mission *m = game_find_builtin_mission(filename);
8483 // check for changed CD
8484 if(game_cd_changed()){
8489 if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8493 // not builtin, so do a general check (any FS2 CD will do)
8495 return game_do_cd_check();
8498 // does not have any CD requirement, do a general check
8499 if(strlen(m->cd_volume) <= 0){
8500 return game_do_cd_check();
8504 if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8506 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8508 } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8511 return game_do_cd_check();
8514 // did we find the cd?
8515 if(find_freespace_cd(m->cd_volume) >= 0){
8519 // make sure the volume exists
8520 int num_attempts = 0;
8521 int refresh_files = 0;
8523 int path_set_ok, popup_rval;
8525 cd_drive_num = find_freespace_cd(m->cd_volume);
8526 path_set_ok = set_cdrom_path(cd_drive_num);
8527 if ( path_set_ok ) {
8529 if ( refresh_files ) {
8536 // no CD found, so prompt user
8537 #if defined(DVD_MESSAGE_HACK)
8538 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8540 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8544 if ( popup_rval != 1 ) {
8549 if ( num_attempts++ > 5 ) {
8561 // ----------------------------------------------------------------
8563 // CDROM detection code END
8565 // ----------------------------------------------------------------
8567 // ----------------------------------------------------------------
8568 // SHIPS TBL VERIFICATION STUFF
8571 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8572 #define NUM_SHIPS_TBL_CHECKSUMS 1
8575 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8576 1696074201, // FS2 demo
8580 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8581 -463907578, // US - beta 1
8582 1696074201, // FS2 demo
8585 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8586 // -1022810006, // 1.0 FULL
8587 -1254285366 // 1.2 FULL (German)
8591 void verify_ships_tbl()
8595 Game_ships_tbl_valid = 1;
8601 // detect if the packfile exists
8602 CFILE *detect = cfopen("ships.tbl", "rb");
8603 Game_ships_tbl_valid = 0;
8607 Game_ships_tbl_valid = 0;
8611 // get the long checksum of the file
8613 cfseek(detect, 0, SEEK_SET);
8614 cf_chksum_long(detect, &file_checksum);
8618 // now compare the checksum/filesize against known #'s
8619 for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8620 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8621 Game_ships_tbl_valid = 1;
8628 DCF(shipspew, "display the checksum for the current ships.tbl")
8631 CFILE *detect = cfopen("ships.tbl", "rb");
8632 // get the long checksum of the file
8634 cfseek(detect, 0, SEEK_SET);
8635 cf_chksum_long(detect, &file_checksum);
8638 dc_printf("%d", file_checksum);
8641 // ----------------------------------------------------------------
8642 // WEAPONS TBL VERIFICATION STUFF
8645 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8646 #define NUM_WEAPONS_TBL_CHECKSUMS 1
8649 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8650 -266420030, // demo 1
8654 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8655 141718090, // US - beta 1
8656 -266420030, // demo 1
8659 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8660 // 399297860, // 1.0 FULL
8661 -553984927 // 1.2 FULL (german)
8665 void verify_weapons_tbl()
8669 Game_weapons_tbl_valid = 1;
8675 // detect if the packfile exists
8676 CFILE *detect = cfopen("weapons.tbl", "rb");
8677 Game_weapons_tbl_valid = 0;
8681 Game_weapons_tbl_valid = 0;
8685 // get the long checksum of the file
8687 cfseek(detect, 0, SEEK_SET);
8688 cf_chksum_long(detect, &file_checksum);
8692 // now compare the checksum/filesize against known #'s
8693 for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8694 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8695 Game_weapons_tbl_valid = 1;
8702 DCF(wepspew, "display the checksum for the current weapons.tbl")
8705 CFILE *detect = cfopen("weapons.tbl", "rb");
8706 // get the long checksum of the file
8708 cfseek(detect, 0, SEEK_SET);
8709 cf_chksum_long(detect, &file_checksum);
8712 dc_printf("%d", file_checksum);
8715 // if the game is running using hacked data
8716 int game_hacked_data()
8719 if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8727 void display_title_screen()
8729 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8730 ///int title_bitmap;
8733 int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8734 if (title_bitmap == -1) {
8740 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8741 extern void d3d_start_frame();
8747 gr_set_bitmap(title_bitmap);
8754 if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8755 extern void d3d_stop_frame();
8763 bm_unload(title_bitmap);
8764 #endif // FS2_DEMO || OEM_BUILD
8767 // return true if the game is running with "low memory", which is less than 48MB
8768 bool game_using_low_mem()
8770 if (Use_low_mem == 0) {