]> icculus.org git repositories - taylor/freespace2.git/blob - src/freespace2/freespace.cpp
added a few files that needed to be compiled
[taylor/freespace2.git] / src / freespace2 / freespace.cpp
1 /*
2  * $Logfile: /Freespace2/code/Freespace2/FreeSpace.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Freespace main body
8  *
9  * $Log$
10  * Revision 1.3  2002/05/26 23:31:18  relnev
11  * added a few files that needed to be compiled
12  *
13  * freespace.cpp: now compiles
14  *
15  * Revision 1.2  2002/05/07 03:16:44  theoddone33
16  * The Great Newline Fix
17  *
18  * Revision 1.1.1.1  2002/05/03 03:28:09  root
19  * Initial import.
20  *
21  * 
22  * 201   6/16/00 3:15p Jefff
23  * sim of the year dvd version changes, a few german soty localization
24  * fixes
25  * 
26  * 200   11/03/99 11:06a Jefff
27  * 1.2 checksums
28  * 
29  * 199   10/26/99 5:07p Jamest
30  * fixed jeffs dumb debug code
31  * 
32  * 198   10/25/99 5:53p Jefff
33  * call control_config_common_init() on startup
34  * 
35  * 197   10/14/99 10:18a Daveb
36  * Fixed incorrect CD checking problem on standalone server.
37  * 
38  * 196   10/13/99 9:22a Daveb
39  * Fixed Fred jumpnode placing bug. Fixed 1024 glide tiled texture problem
40  * related to movies. Fixed launcher spawning from PXO screen.
41  * 
42  * 195   10/06/99 11:05a Jefff
43  * new oem upsell 3 hotspot coords
44  * 
45  * 194   10/06/99 10:31a Jefff
46  * OEM updates
47  * 
48  * 193   10/01/99 9:10a Daveb
49  * V 1.1 PATCH
50  * 
51  * 192   9/15/99 4:57a Dave
52  * Updated ships.tbl checksum
53  * 
54  * 191   9/15/99 3:58a Dave
55  * Removed framerate warning at all times.
56  * 
57  * 190   9/15/99 3:16a Dave
58  * Remove mt-011.fs2 from the builtin mission list.
59  * 
60  * 189   9/15/99 1:45a Dave
61  * Don't init joystick on standalone. Fixed campaign mode on standalone.
62  * Fixed no-score-report problem in TvT
63  * 
64  * 188   9/14/99 6:08a Dave
65  * Updated (final) single, multi, and campaign list.
66  * 
67  * 187   9/14/99 3:26a Dave
68  * Fixed laser fogging problem in nebula (D3D)> Fixed multiplayer
69  * respawn-too-early problem. Made a few crash points safe.
70  * 
71  * 186   9/13/99 4:52p Dave
72  * RESPAWN FIX
73  * 
74  * 185   9/12/99 8:09p Dave
75  * Fixed problem where skip-training button would cause mission messages
76  * not to get paged out for the current mission.
77  * 
78  * 184   9/10/99 11:53a Dave
79  * Shutdown graphics before sound to eliminate apparent lockups when
80  * Directsound decides to be lame. Fix TOPMOST problem with D3D windows.
81  * 
82  * 183   9/09/99 11:40p Dave
83  * Handle an Assert() in beam code. Added supernova sounds. Play the right
84  * 2 end movies properly, based upon what the player did in the mission.
85  * 
86  * 182   9/08/99 10:29p Dave
87  * Make beam sound pausing and unpausing much safer.
88  * 
89  * 181   9/08/99 10:01p Dave
90  * Make sure game won't run in a drive's root directory. Make sure
91  * standalone routes suqad war messages properly to the host.
92  * 
93  * 180   9/08/99 3:22p Dave
94  * Updated builtin mission list.
95  * 
96  * 179   9/08/99 12:01p Jefff
97  * fixed Game_builtin_mission_list typo on Training-2.fs2
98  * 
99  * 178   9/08/99 9:48a Andsager
100  * Add force feedback for engine wash.
101  * 
102  * 177   9/07/99 4:01p Dave
103  * Fixed up a string.tbl paroblem (self destruct message). Make sure IPX
104  * does everything properly (setting up address when binding). Remove
105  * black rectangle background from UI_INPUTBOX.
106  * 
107  * 176   9/13/99 2:40a Dave
108  * Comment in full 80 minute CD check for RELEASE_REAL builds.
109  * 
110  * 175   9/06/99 6:38p Dave
111  * Improved CD detection code.
112  * 
113  * 174   9/06/99 1:30a Dave
114  * Intermediate checkin. Started on enforcing CD-in-drive to play the
115  * game.
116  * 
117  * 173   9/06/99 1:16a Dave
118  * Make sure the user sees the intro movie.
119  * 
120  * 172   9/04/99 8:00p Dave
121  * Fixed up 1024 and 32 bit movie support.
122  * 
123  * 171   9/03/99 1:32a Dave
124  * CD checking by act. Added support to play 2 cutscenes in a row
125  * seamlessly. Fixed super low level cfile bug related to files in the
126  * root directory of a CD. Added cheat code to set campaign mission # in
127  * main hall.
128  * 
129  * 170   9/01/99 10:49p Dave
130  * Added nice SquadWar checkbox to the client join wait screen.
131  * 
132  * 169   9/01/99 10:14a Dave
133  * Pirate bob.
134  * 
135  * 168   8/29/99 4:51p Dave
136  * Fixed damaged checkin.
137  * 
138  * 167   8/29/99 4:18p Andsager
139  * New "burst" limit for friendly damage.  Also credit more damage done
140  * against large friendly ships.
141  * 
142  * 166   8/27/99 6:38p Alanl
143  * crush the blasted repeating messages bug
144  * 
145  * 164   8/26/99 9:09p Dave
146  * Force framerate check in everything but a RELEASE_REAL build.
147  * 
148  * 163   8/26/99 9:45a Dave
149  * First pass at easter eggs and cheats.
150  * 
151  * 162   8/24/99 8:55p Dave
152  * Make sure nondimming pixels work properly in tech menu.
153  * 
154  * 161   8/24/99 1:49a Dave
155  * Fixed client-side afterburner stuttering. Added checkbox for no version
156  * checking on PXO join. Made button info passing more friendly between
157  * client and server.
158  * 
159  * 160   8/22/99 5:53p Dave
160  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
161  * instead of ship designations for multiplayer players.
162  * 
163  * 159   8/22/99 1:19p Dave
164  * Fixed up http proxy code. Cleaned up scoring code. Reverse the order in
165  * which d3d cards are detected.
166  * 
167  * 158   8/20/99 2:09p Dave
168  * PXO banner cycling.
169  * 
170  * 157   8/19/99 10:59a Dave
171  * Packet loss detection.
172  * 
173  * 156   8/19/99 10:12a Alanl
174  * preload mission-specific messages on machines greater than 48MB
175  * 
176  * 155   8/16/99 4:04p Dave
177  * Big honking checkin.
178  * 
179  * 154   8/11/99 5:54p Dave
180  * Fixed collision problem. Fixed standalone ghost problem.
181  * 
182  * 153   8/10/99 7:59p Jefff
183  * XSTR'ed some stuff
184  * 
185  * 152   8/10/99 6:54p Dave
186  * Mad optimizations. Added paging to the nebula effect.
187  * 
188  * 151   8/10/99 3:44p Jefff
189  * loads Intelligence information on startup
190  * 
191  * 150   8/09/99 3:47p Dave
192  * Fixed incorrect nebula regeneration. Default HUD to low-contrast in
193  * non-nebula missions.
194  * 
195  * 149   8/09/99 2:21p Andsager
196  * Fix patching from multiplayer direct to launcher update tab.
197  * 
198  * 148   8/09/99 10:36a Dave
199  * Version info for game.
200  * 
201  * 147   8/06/99 9:46p Dave
202  * Hopefully final changes for the demo.
203  * 
204  * 146   8/06/99 3:34p Andsager
205  * Make title version info "(D)" -> "D"  show up nicely
206  * 
207  * 145   8/06/99 2:59p Adamp
208  * Fixed NT launcher/update problem.
209  * 
210  * 144   8/06/99 1:52p Dave
211  * Bumped up MAX_BITMAPS for the demo.
212  * 
213  * 143   8/06/99 12:17p Andsager
214  * Demo: down to just 1 demo dog
215  * 
216  * 142   8/05/99 9:39p Dave
217  * Yet another new checksum.
218  * 
219  * 141   8/05/99 6:19p Dave
220  * New demo checksums.
221  * 
222  * 140   8/05/99 5:31p Andsager
223  * Up demo version 1.01
224  * 
225  * 139   8/05/99 4:22p Andsager
226  * No time limit on upsell screens.  Reverse order of display of upsell
227  * bitmaps.
228  * 
229  * 138   8/05/99 4:17p Dave
230  * Tweaks to client interpolation.
231  * 
232  * 137   8/05/99 3:52p Danw
233  * 
234  * 136   8/05/99 3:01p Danw
235  * 
236  * 135   8/05/99 2:43a Anoop
237  * removed duplicate definition.
238  * 
239  * 134   8/05/99 2:13a Dave
240  * Fixed build error.
241  * 
242  * 133   8/05/99 2:05a Dave
243  * Whee.
244  * 
245  * 132   8/05/99 1:22a Andsager
246  * fix upsell bug.
247  * 
248  * 131   8/04/99 9:51p Andsager
249  * Add title screen to demo
250  * 
251  * 130   8/04/99 6:47p Jefff
252  * fixed link error resulting from #ifdefs
253  * 
254  * 129   8/04/99 6:26p Dave
255  * Updated ship tbl checksum.
256  * 
257  * 128   8/04/99 5:40p Andsager
258  * Add multiple demo dogs
259  * 
260  * 127   8/04/99 5:36p Andsager
261  * Show upsell screens at end of demo campaign before returning to main
262  * hall.
263  * 
264  * 126   8/04/99 11:42a Danw
265  * tone down EAX reverb
266  * 
267  * 125   8/04/99 11:23a Dave
268  * Updated demo checksums.
269  * 
270  * 124   8/03/99 11:02p Dave
271  * Maybe fixed sync problems in multiplayer.
272  * 
273  * 123   8/03/99 6:21p Jefff
274  * minor text change
275  * 
276  * 122   8/03/99 3:44p Andsager
277  * Launch laucher if trying to run FS without first having configured
278  * system.
279  * 
280  * 121   8/03/99 12:45p Dave
281  * Update checksums.
282  * 
283  * 120   8/02/99 9:13p Dave
284  * Added popup tips.
285  * 
286  * 119   7/30/99 10:31p Dave
287  * Added comm menu to the configurable hud files.
288  * 
289  * 118   7/30/99 5:17p Andsager
290  * first fs2demo checksums
291  * 
292  * 117   7/29/99 3:09p Anoop
293  * 
294  * 116   7/29/99 12:05a Dave
295  * Nebula speed optimizations.
296  * 
297  * 115   7/27/99 8:59a Andsager
298  * Make major, minor version consistent for all builds.  Only show major
299  * and minor for launcher update window.
300  * 
301  * 114   7/26/99 5:50p Dave
302  * Revised ingame join. Better? We'll see....
303  * 
304  * 113   7/26/99 5:27p Andsager
305  * Add training mission as builtin to demo build
306  * 
307  * 112   7/24/99 1:54p Dave
308  * Hud text flash gauge. Reworked dead popup to use 4 buttons in red-alert
309  * missions.
310  * 
311  * 111   7/22/99 4:00p Dave
312  * Fixed beam weapon muzzle glow rendering. Externalized hud shield info.
313  * 
314  * 110   7/21/99 8:10p Dave
315  * First run of supernova effect.
316  * 
317  * 109   7/20/99 1:49p Dave
318  * Peter Drake build. Fixed some release build warnings.
319  * 
320  * 108   7/19/99 2:26p Andsager
321  * set demo multiplayer missions
322  * 
323  * 107   7/18/99 5:19p Dave
324  * Jump node icon. Fixed debris fogging. Framerate warning stuff.
325  * 
326  * 106   7/16/99 1:50p Dave
327  * 8 bit aabitmaps. yay.
328  * 
329  * 105   7/15/99 3:07p Dave
330  * 32 bit detection support. Mouse coord commandline.
331  * 
332  * 104   7/15/99 2:13p Dave
333  * Added 32 bit detection.
334  * 
335  * 103   7/15/99 9:20a Andsager
336  * FS2_DEMO initial checkin
337  * 
338  * 102   7/14/99 11:02a Dave
339  * Skill level default back to easy. Blech.
340  * 
341  * 101   7/09/99 5:54p Dave
342  * Seperated cruiser types into individual types. Added tons of new
343  * briefing icons. Campaign screen.
344  * 
345  * 100   7/08/99 4:43p Andsager
346  * New check for sparky_hi and print if not found.
347  * 
348  * 99    7/08/99 10:53a Dave
349  * New multiplayer interpolation scheme. Not 100% done yet, but still
350  * better than the old way.
351  * 
352  * 98    7/06/99 4:24p Dave
353  * Mid-level checkin. Starting on some potentially cool multiplayer
354  * smoothness crap.
355  * 
356  * 97    7/06/99 3:35p Andsager
357  * Allow movie to play before red alert mission.
358  * 
359  * 96    7/03/99 5:50p Dave
360  * Make rotated bitmaps draw properly in padlock views.
361  * 
362  * 95    7/02/99 9:55p Dave
363  * Player engine wash sound.
364  * 
365  * 94    7/02/99 4:30p Dave
366  * Much more sophisticated lightning support.
367  * 
368  * 93    6/29/99 7:52p Dave
369  * Put in exception handling in FS2.
370  * 
371  * 92    6/22/99 9:37p Dave
372  * Put in pof spewing.
373  * 
374  * 91    6/16/99 4:06p Dave
375  * New pilot info popup. Added new draw-bitmap-as-poly function.
376  * 
377  * 90    6/15/99 1:56p Andsager
378  * For release builds, allow start up in high res only with
379  * sparky_hi._fs2.vp
380  * 
381  * 89    6/15/99 9:34a Dave
382  * Fixed key checking in single threaded version of the stamp notification
383  * screen. 
384  * 
385  * 88    6/09/99 2:55p Andsager
386  * Allow multiple asteroid subtypes (of large, medium, small) and follow
387  * family.
388  * 
389  * 87    6/08/99 1:14a Dave
390  * Multi colored hud test.
391  * 
392  * 86    6/04/99 9:52a Dave
393  * Fixed some rendering problems.
394  * 
395  * 85    6/03/99 10:15p Dave
396  * Put in temporary main hall screen.
397  * 
398  * 84    6/02/99 6:18p Dave
399  * Fixed TNT lockup problems! Wheeeee!
400  * 
401  * 83    6/01/99 3:52p Dave
402  * View footage screen. Fixed xstrings to not display the & symbol. Popup,
403  * dead popup, pxo find player popup, pxo private room popup.
404  * 
405  * 82    5/26/99 1:28p Jasenw
406  * changed coords for loading ani
407  * 
408  * 81    5/26/99 11:46a Dave
409  * Added ship-blasting lighting and made the randomization of lighting
410  * much more customizable.
411  * 
412  * 80    5/24/99 5:45p Dave
413  * Added detail levels to the nebula, with a decent speedup. Split nebula
414  * lightning into its own section.
415  * 
416  * 
417  */
418
419 #ifndef PLAT_UNIX
420 #include <windows.h>
421 #include <process.h>
422 #include <direct.h>
423 #include <io.h>
424 #else
425 #endif
426
427 #include <stdio.h>
428 #include <stdlib.h>
429 #include <time.h>
430
431 #include "pstypes.h"
432 #include "systemvars.h"
433 #include "key.h"
434 #include "vecmat.h"
435 #include "2d.h"
436 #include "3d.h"
437 #include "starfield.h"
438 #include "lighting.h"
439 #include "weapon.h"
440 #include "ship.h"
441 #include "palman.h"
442 #include "osapi.h"
443 #include "fireballs.h"
444 #include "debris.h"
445 #include "timer.h"
446 #include "fix.h"
447 #include "floating.h"
448 #include "gamesequence.h"
449 #include "radar.h"
450 #include "optionsmenu.h"
451 #include "playermenu.h"
452 #include "trainingmenu.h"
453 #include "techmenu.h"
454 #include "ai.h"
455 #include "hud.h"
456 #include "hudmessage.h"
457 #include "psnet.h"
458 #include "missiongoals.h"
459 #include "missionparse.h"
460 #include "bmpman.h"
461 #include "joy.h"
462 #include "joy_ff.h"
463 #include "multi.h"
464 #include "multiutil.h"
465 #include "multimsgs.h"
466 #include "multiui.h"
467 #include "cfile.h"
468 #include "player.h"
469 #include "freespace.h"
470 #include "managepilot.h"
471 #include "sound.h"
472 #include "contexthelp.h"
473 #include "mouse.h"
474 #include "joy.h"
475 #include "missionbrief.h"
476 #include "missiondebrief.h"
477 #include "ui.h"
478 #include "missionshipchoice.h"
479 #include "model.h"
480 #include "hudconfig.h"
481 #include "controlsconfig.h"
482 #include "missionmessage.h"
483 #include "missiontraining.h"
484 #include "hudets.h"
485 #include "hudtarget.h"
486 #include "gamesnd.h"
487 #include "rbaudio.h"
488 #include "winmidi.h"
489 #include "eventmusic.h"
490 #include "animplay.h"
491 #include "missionweaponchoice.h"
492 #include "missionlog.h"
493 #include "audiostr.h"
494 #include "hudlock.h"
495 #include "missioncampaign.h"
496 #include "credits.h"
497 #include "missionhotkey.h"
498 #include "objectsnd.h"
499 #include "cmeasure.h"
500 #include "ai.h"
501 #include "linklist.h"
502 #include "shockwave.h"
503 #include "afterburner.h"
504 #include "scoring.h"
505 #include "stats.h"
506 #include "cmdline.h"
507 #include "timer.h"
508 #include "stand_gui.h"
509 #include "pcxutils.h"
510 #include "hudtargetbox.h"
511 #include "multi_xfer.h"
512 #include "hudescort.h"
513 #include "multiutil.h"
514 #include "sexp.h"
515 #include "medals.h"
516 #include "multiteamselect.h"
517 #include "ds3d.h"
518 #include "shipfx.h"
519 #include "readyroom.h"
520 #include "mainhallmenu.h"
521 #include "multilag.h"
522 #include "trails.h"
523 #include "particle.h"
524 #include "popup.h"
525 #include "multi_ingame.h"
526 #include "snazzyui.h"
527 #include "asteroid.h"
528 #include "popupdead.h"
529 #include "multi_voice.h"
530 #include "missioncmdbrief.h"
531 #include "redalert.h"
532 #include "gameplayhelp.h"
533 #include "multilag.h"
534 #include "staticrand.h"
535 #include "multi_pmsg.h"
536 #include "levelpaging.h"
537 #include "observer.h"
538 #include "multi_pause.h"
539 #include "multi_endgame.h"
540 #include "cutscenes.h"
541 #include "multi_respawn.h"
542 // #include "movie.h"
543 #include "multi_obj.h"
544 #include "multi_log.h"
545 #include "emp.h"
546 #include "localize.h"
547 #include "osregistry.h"
548 #include "barracks.h"
549 #include "missionpause.h"
550 #include "font.h"
551 #include "alphacolors.h"
552 #include "objcollide.h"
553 #include "flak.h"
554 #include "neb.h"
555 #include "neblightning.h"
556 #include "shipcontrails.h"
557 #include "awacs.h"
558 #include "beam.h"
559 #include "multi_dogfight.h"
560 #include "multi_rate.h"
561 #include "muzzleflash.h"
562 #include "encrypt.h"
563 #include "demo.h"
564 #include "version.h"
565 #include "mainhalltemp.h"
566 #include "exceptionhandler.h"
567 #ifndef PLAT_UNIX
568 #include "glide.h"
569 #endif
570 #include "supernova.h"
571 #include "hudshield.h"
572 // #include "names.h"
573 #include "shiphit.h"
574 #include "missionloopbrief.h"
575
576 #ifdef NDEBUG
577 #ifdef FRED
578 #error macro FRED is defined when trying to build release Fred.  Please undefine FRED macro in build settings
579 #endif
580 #endif
581
582 //      Revision history.
583 //      Full version:
584 //    1.00.04   5/26/98 MWA -- going final (12 pm)
585 //    1.00.03   5/26/98 MWA -- going final (3 am)
586 //    1.00.02   5/25/98 MWA -- going final
587 //    1.00.01   5/25/98 MWA -- going final
588 //              0.90            5/21/98 MWA -- getting ready for final.
589 //              0.10            4/9/98.  Set by MK.
590 //
591 //      Demo version: (obsolete since DEMO codebase split from tree)
592 //              0.03            4/10/98 AL.     Interplay rev
593 //              0.02            4/8/98  MK.     Increased when this system was modified.
594 //              0.01            4/7/98? AL.     First release to Interplay QA.
595 //
596 //      OEM version:
597 //              1.00            5/28/98 AL.     First release to Interplay QA.
598
599 void game_level_init(int seed = -1);
600 void game_post_level_init();
601 void game_do_frame();
602 void game_update_missiontime(); // called from game_do_frame() and navmap_do_frame()
603 void game_reset_time();
604 void game_show_framerate();                     // draws framerate in lower right corner
605
606 int Game_no_clear = 0;
607
608 int Pofview_running = 0;
609 int Nebedit_running = 0;
610
611 typedef struct big_expl_flash {
612         float max_flash_intensity;      // max intensity
613         float cur_flash_intensity;      // cur intensity
614         int     flash_start;            // start time
615 } big_expl_flash;
616
617 #define FRAME_FILTER 16
618
619 #define DEFAULT_SKILL_LEVEL     1
620 int     Game_skill_level = DEFAULT_SKILL_LEVEL;
621
622 #define VIEWER_ZOOM_DEFAULT 0.75f                       //      Default viewer zoom, 0.625 as per multi-lateral agreement on 3/24/97
623 float Viewer_zoom = VIEWER_ZOOM_DEFAULT;
624
625 #define EXE_FNAME                       ("fs2.exe")
626 #define LAUNCHER_FNAME  ("freespace2.exe")
627
628 // JAS: Code for warphole camera.
629 // Needs to be cleaned up.
630 vector Camera_pos = { 0.0f, 0.0f, 0.0f };
631 vector Camera_velocity = { 0.0f, 0.0f, 0.0f };
632 vector Camera_desired_velocity = { 0.0f, 0.0f, 0.0f };
633 matrix Camera_orient = IDENTITY_MATRIX;
634 float Camera_damping = 1.0f;
635 float Camera_time = 0.0f;
636 float Warpout_time = 0.0f;
637 int Warpout_forced = 0;         // Set if this is a forced warpout that cannot be cancelled.
638 int Warpout_sound = -1;
639 void camera_move();
640 int Use_joy_mouse = 0;
641 int Use_palette_flash = 1;
642 #ifndef NDEBUG
643 int Use_fullscreen_at_startup = 0;
644 #endif
645 int Show_area_effect = 0;
646 object  *Last_view_target = NULL;
647
648 int dogfight_blown = 0;
649
650 int     frame_int = -1;
651 float frametimes[FRAME_FILTER];
652 float frametotal = 0.0f;
653 float flFrametime;
654
655 #ifdef RELEASE_REAL
656         int     Show_framerate = 0;
657 #else 
658         int     Show_framerate = 1;
659 #endif
660
661 int     Framerate_cap = 120;
662 int     Show_mem = 0;
663 int     Show_cpu = 0;
664 int     Show_target_debug_info = 0;
665 int     Show_target_weapons = 0;
666 int     Game_font = -1;
667 static int Show_player_pos = 0;         // debug console command to show player world pos on HUD
668
669 int Debug_octant = -1;
670
671 fix Game_time_compression = F1_0;
672
673 // if the ships.tbl the player has is valid
674 int Game_ships_tbl_valid = 0;
675
676 // if the weapons.tbl the player has is valid
677 int Game_weapons_tbl_valid = 0;
678
679 #ifndef NDEBUG
680 int Test_begin = 0;
681 extern int      Player_attacking_enabled;
682 int Show_net_stats;
683 #endif
684
685 int Pre_player_entry;
686
687 int     Fred_running = 0;
688 char Game_current_mission_filename[MAX_FILENAME_LEN];
689 int game_single_step = 0;
690 int last_single_step=0;
691
692 extern int MSG_WINDOW_X_START;  // used to position mission_time and shields output
693 extern int MSG_WINDOW_Y_START;
694 extern int MSG_WINDOW_HEIGHT;
695
696 int game_zbuffer = 1;
697 //static int Game_music_paused;
698 static int Game_paused;
699
700 int Game_level_seed;
701
702 #define EXPIRE_BAD_CHECKSUM                     1
703 #define EXPIRE_BAD_TIME                                 2
704
705 extern void ssm_init();
706 extern void ssm_level_init();
707 extern void ssm_process();
708
709 // static variable to contain the time this version was built
710 // commented out for now until
711 // I figure out how to get the username into the file
712 //LOCAL char freespace_build_time[] = "Compiled on:"__DATE__" "__TIME__" by "__USER__;
713
714 // defines and variables used for dumping frame for making trailers.
715 #ifndef NDEBUG
716 int Debug_dump_frames = 0;                      // Set to 0 to not dump frames, else equal hz to dump. (15 or 30 probably)
717 int Debug_dump_trigger = 0;
718 int Debug_dump_frame_count;
719 int Debug_dump_frame_num = 0;
720 #define DUMP_BUFFER_NUM_FRAMES  1                       // store every 15 frames
721 #endif
722
723 // amount of time to wait after the player has died before we display the death died popup
724 #define PLAYER_DIED_POPUP_WAIT          2500
725 int Player_died_popup_wait = -1;
726 int Player_multi_died_check = -1;
727
728 // builtin mission list stuff
729 #ifdef FS2_DEMO
730         int Game_builtin_mission_count = 6;
731         fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
732                 { "SPDemo-01.fs2",                              (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     ""              },
733                 { "SPDemo-02.fs2",                              (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     ""              },
734                 { "DemoTrain.fs2",                              (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     ""              },
735                 { "Demo.fc2",                                           (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE),                                        ""              },
736                 { "MPDemo-01.fs2",                              (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
737                 { "Demo-DOG-01.fs2",                            (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
738         };
739 #elif defined(PD_BUILD)
740         int Game_builtin_mission_count = 4;
741         fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
742                 { "sm1-01.fs2",                                 (FSB_FROM_VOLITION),                                                                                            ""              },
743                 { "sm1-05.fs2",                                 (FSB_FROM_VOLITION),                                                                                            ""              },              
744                 { "sm1-01",                                                     (FSB_FROM_VOLITION),                                                                                            ""              },
745                 { "sm1-05",                                                     (FSB_FROM_VOLITION),                                                                                            ""              },              
746         };
747 #elif defined(MULTIPLAYER_BETA)
748         int Game_builtin_mission_count = 17;
749         fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
750                 // multiplayer beta
751                 { "md-01.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
752                 { "md-02.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
753                 { "md-03.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
754                 { "md-04.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
755                 { "md-05.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
756                 { "md-06.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
757                 { "md-07.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
758                 { "mt-02.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
759                 { "mt-03.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
760                 { "m-03.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
761                 { "m-04.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
762                 { "m-05.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""              },
763                 { "templar-01.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""              },
764                 { "templar-02.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""              },
765                 { "templar-03a.fs2",                            (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""              },
766                 { "templar-04a.fs2",                            (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""              },
767                 { "templar.fc2",                                        (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE),    ""              },      
768         };
769 #elif defined(OEM_BUILD)
770         int Game_builtin_mission_count = 17;
771         fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
772                 // oem version - act 1 only
773                 { "freespace2oem.fc2",                  (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE),                                        "" },
774                         
775                 // act 1
776                 { "sm1-01.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
777                 { "sm1-02.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
778                 { "sm1-03.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
779                 { "sm1-04.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
780                 { "sm1-05.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
781                 { "sm1-06.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
782                 { "sm1-07.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
783                 { "sm1-08.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
784                 { "sm1-09.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
785                 { "sm1-10.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
786                 { "training-1.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
787                 { "training-2.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
788                 { "training-3.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
789                 { "tsm-104.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
790                 { "tsm-105.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       },
791                 { "tsm-106.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_1       }
792         };
793 #else 
794         int Game_builtin_mission_count = 92;
795         fs_builtin_mission Game_builtin_mission_list[MAX_BUILTIN_MISSIONS] = {
796                 // single player campaign
797                 { "freespace2.fc2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN_FILE),                                        "" },
798                         
799                 // act 1
800                 { "sm1-01.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
801                 { "sm1-02.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
802                 { "sm1-03.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
803                 { "sm1-04.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
804                 { "sm1-05.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
805                 { "sm1-06.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
806                 { "sm1-07.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
807                 { "sm1-08.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
808                 { "sm1-09.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
809                 { "sm1-10.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
810                 { "loop1-1.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
811                 { "loop1-2.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
812                 { "loop1-3.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
813                 { "training-1.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
814                 { "training-2.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
815                 { "training-3.fs2",                             (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
816                 { "tsm-104.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
817                 { "tsm-105.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
818                 { "tsm-106.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_2       },
819
820                 // act 2
821                 { "sm2-01.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
822                 { "sm2-02.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
823                 { "sm2-03.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
824                 { "sm2-04.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
825                 { "sm2-05.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
826                 { "sm2-06.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
827                 { "sm2-07.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
828                 { "sm2-08.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
829                 { "sm2-09.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
830                 { "sm2-10.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
831
832                 // act 3
833                 { "sm3-01.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
834                 { "sm3-02.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
835                 { "sm3-03.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
836                 { "sm3-04.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
837                 { "sm3-05.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
838                 { "sm3-06.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
839                 { "sm3-07.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
840                 { "sm3-08.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
841                 { "sm3-09.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
842                 { "sm3-10.fs2",                                 (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
843                 { "loop2-1.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },              
844                 { "loop2-2.fs2",                                        (FSB_FROM_VOLITION | FSB_CAMPAIGN),                                                     FS_CDROM_VOLUME_3       },
845
846                 // multiplayer missions
847
848                 // gauntlet
849                 { "g-shi.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
850                 { "g-ter.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
851                 { "g-vas.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
852
853                 // coop
854                 { "m-01.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
855                 { "m-02.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
856                 { "m-03.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
857                 { "m-04.fs2",                                           (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
858
859                 // dogfight
860                 { "mdh-01.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
861                 { "mdh-02.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
862                 { "mdh-03.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
863                 { "mdh-04.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
864                 { "mdh-05.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
865                 { "mdh-06.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
866                 { "mdh-07.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
867                 { "mdh-08.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
868                 { "mdh-09.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
869                 { "mdl-01.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
870                 { "mdl-02.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
871                 { "mdl-03.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
872                 { "mdl-04.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
873                 { "mdl-05.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
874                 { "mdl-06.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
875                 { "mdl-07.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
876                 { "mdl-08.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
877                 { "mdl-09.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
878                 { "mdm-01.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
879                 { "mdm-02.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
880                 { "mdm-03.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
881                 { "mdm-04.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
882                 { "mdm-05.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
883                 { "mdm-06.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
884                 { "mdm-07.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
885                 { "mdm-08.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
886                 { "mdm-09.fs2",                                 (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },              
887                 { "osdog.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
888
889                 // TvT          
890                 { "mt-01.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
891                 { "mt-02.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
892                 { "mt-03.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
893                 { "mt-04.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
894                 { "mt-05.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
895                 { "mt-06.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
896                 { "mt-07.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
897                 { "mt-08.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
898                 { "mt-09.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },
899                 { "mt-10.fs2",                                          (FSB_FROM_VOLITION | FSB_MULTI),                                                                ""                                              },                              
900
901                 // campaign
902                 { "templar.fc2",                                (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN_FILE),                                    "" },
903                 { "templar-01.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""                                              },                              
904                 { "templar-02.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""                                              },                              
905                 { "templar-03.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""                                              },                              
906                 { "templar-04.fs2",                             (FSB_FROM_VOLITION | FSB_MULTI | FSB_CAMPAIGN),                 ""                                              },                              
907         };
908 #endif
909
910
911 // Internal function prototypes
912 void game_maybe_draw_mouse(float frametime);
913 void init_animating_pointer();
914 void load_animating_pointer(char *filename, int dx, int dy);
915 void unload_animating_pointer();
916 void game_do_training_checks();
917 void game_shutdown(void);
918 void game_show_event_debug(float frametime);
919 void game_event_debug_init();
920 void game_frame();
921 void demo_upsell_show_screens();
922 void game_start_subspace_ambient_sound();
923 void game_stop_subspace_ambient_sound();
924 void verify_ships_tbl();
925 void verify_weapons_tbl();
926 void display_title_screen();
927
928 // loading background filenames
929 static char *Game_loading_bground_fname[GR_NUM_RESOLUTIONS] = {
930         "LoadingBG",            // GR_640
931         "2_LoadingBG"           // GR_1024
932 };
933
934
935 static char *Game_loading_ani_fname[GR_NUM_RESOLUTIONS] = {
936         "Loading.ani",          // GR_640
937         "2_Loading.ani"         // GR_1024
938 };
939
940 #if defined(FS2_DEMO)
941 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
942         "PreLoad",
943         "2_PreLoad"
944 };
945 #elif defined(OEM_BUILD)
946 static char *Game_demo_title_screen_fname[GR_NUM_RESOLUTIONS] = {
947         "OEMPreLoad",
948         "2_OEMPreLoad"
949 };
950 #endif
951
952 // cdrom stuff
953 char Game_CDROM_dir[MAX_PATH_LEN];
954 int init_cdrom();
955
956 // How much RAM is on this machine. Set in WinMain
957 uint Freespace_total_ram = 0;
958
959 // game flash stuff
960 float Game_flash_red = 0.0f;
961 float Game_flash_green = 0.0f;
962 float Game_flash_blue = 0.0f;
963 float Sun_spot = 0.0f;
964 big_expl_flash Big_expl_flash = {0.0f, 0.0f, 0};
965
966 // game shudder stuff (in ms)
967 int Game_shudder_time = -1;
968 int Game_shudder_total = 0;
969 float Game_shudder_intensity = 0.0f;                    // should be between 0.0 and 100.0
970
971 // EAX stuff
972 sound_env Game_sound_env;
973 //sound_env Game_default_sound_env = {SND_ENV_AUDITORIUM, 0.25f, 0.35f, 3.0f};
974 sound_env Game_default_sound_env = {SND_ENV_GENERIC, 0.2F,0.2F,1.0F};
975
976 int Game_sound_env_update_timestamp;
977
978 // WARPIN CRAP BEGIN --------------------------------------------------------------------------------------------
979
980
981 // WARPIN CRAP END --------------------------------------------------------------------------------------------
982
983 fs_builtin_mission *game_find_builtin_mission(char *filename)
984 {
985         int idx;
986
987         // look through all existing builtin missions
988         for(idx=0; idx<Game_builtin_mission_count; idx++){
989                 if(!stricmp(Game_builtin_mission_list[idx].filename, filename)){
990                         return &Game_builtin_mission_list[idx];
991                 }
992         }
993
994         // didn't find it
995         return NULL;
996 }
997
998 int game_get_default_skill_level()
999 {
1000         return DEFAULT_SKILL_LEVEL;
1001 }
1002
1003 // Resets the flash
1004 void game_flash_reset()
1005 {
1006         Game_flash_red = 0.0f;
1007         Game_flash_green = 0.0f;
1008         Game_flash_blue = 0.0f;
1009         Sun_spot = 0.0f;
1010         Big_expl_flash.max_flash_intensity = 0.0f;
1011         Big_expl_flash.cur_flash_intensity = 0.0f;
1012         Big_expl_flash.flash_start = 0;
1013 }
1014
1015 float Gf_critical = -1.0f;                                      // framerate we should be above on the average for this mission
1016 float Gf_critical_time = 0.0f;                  // how much time we've been at the critical framerate
1017
1018 void game_framerate_check_init()
1019 {
1020         // zero critical time
1021         Gf_critical_time = 0.0f;
1022                 
1023         // nebula missions
1024         if(The_mission.flags & MISSION_FLAG_FULLNEB){
1025                 // if this is a glide card
1026                 if(gr_screen.mode == GR_GLIDE){
1027 #ifndef PLAT_UNIX               
1028                         extern GrHwConfiguration hwconfig;
1029
1030                         // voodoo 2/3
1031                         if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1032                                 Gf_critical = 15.0f;
1033                         }
1034                         // voodoo 1
1035                         else {
1036                                 Gf_critical = 10.0f;
1037                         }
1038 #else
1039                         STUB_FUNCTION;
1040                         
1041                         Gf_critical = 15.0f;
1042 #endif                                          
1043                 }
1044                 // d3d. only care about good cards here I guess (TNT)
1045                 else {
1046                         Gf_critical = 15.0f;                    
1047                 }
1048         } else {
1049                 // if this is a glide card
1050                 if(gr_screen.mode == GR_GLIDE){
1051 #ifndef PLAT_UNIX               
1052                         extern GrHwConfiguration hwconfig;
1053
1054                         // voodoo 2/3
1055                         if(hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam >= 4){
1056                                 Gf_critical = 25.0f;
1057                         }
1058                         // voodoo 1
1059                         else {
1060                                 Gf_critical = 20.0f;
1061                         }
1062 #else
1063                         STUB_FUNCTION;
1064                         
1065                         Gf_critical = 25.0f;
1066 #endif                                          
1067                 }
1068                 // d3d. only care about good cards here I guess (TNT)
1069                 else {
1070                         Gf_critical = 25.0f;
1071                 }
1072         }
1073 }
1074
1075 extern float Framerate;
1076 void game_framerate_check()
1077 {
1078         int y_start = 100;
1079         
1080         // if the current framerate is above the critical level, add frametime
1081         if(Framerate >= Gf_critical){
1082                 Gf_critical_time += flFrametime;
1083         }       
1084
1085         if(!Show_framerate){
1086                 return;
1087         }
1088
1089         // display if we're above the critical framerate
1090         if(Framerate < Gf_critical){
1091                 gr_set_color_fast(&Color_bright_red);
1092                 gr_string(200, y_start, "Framerate warning");
1093
1094                 y_start += 10;
1095         }
1096
1097         // display our current pct of good frametime
1098         if(f2fl(Missiontime) >= 0.0f){
1099                 float pct = (Gf_critical_time / f2fl(Missiontime)) * 100.0f;
1100
1101                 if(pct >= 85.0f){
1102                         gr_set_color_fast(&Color_bright_green);
1103                 } else {
1104                         gr_set_color_fast(&Color_bright_red);
1105                 }
1106
1107                 gr_printf(200, y_start, "%d%%", (int)pct);
1108
1109                 y_start += 10;
1110         }
1111 }
1112
1113
1114 // Adds a flash effect.  These can be positive or negative.
1115 // The range will get capped at around -1 to 1, so stick 
1116 // with a range like that.
1117 void game_flash( float r, float g, float b )
1118 {
1119         Game_flash_red += r;
1120         Game_flash_green += g;
1121         Game_flash_blue += b;
1122
1123         if ( Game_flash_red < -1.0f )   {
1124                 Game_flash_red = -1.0f;
1125         } else if ( Game_flash_red > 1.0f )     {
1126                 Game_flash_red = 1.0f;
1127         }
1128
1129         if ( Game_flash_green < -1.0f ) {
1130                 Game_flash_green = -1.0f;
1131         } else if ( Game_flash_green > 1.0f )   {
1132                 Game_flash_green = 1.0f;
1133         }
1134
1135         if ( Game_flash_blue < -1.0f )  {
1136                 Game_flash_blue = -1.0f;
1137         } else if ( Game_flash_blue > 1.0f )    {
1138                 Game_flash_blue = 1.0f;
1139         }
1140
1141 }
1142
1143 // Adds a flash for Big Ship explosions
1144 // cap range from 0 to 1
1145 void big_explosion_flash(float flash)
1146 {
1147         Big_expl_flash.flash_start = timestamp(1);
1148
1149         if (flash > 1.0f) {
1150                 flash = 1.0f;
1151         } else if (flash < 0.0f) {
1152                 flash = 0.0f;
1153         }
1154
1155         Big_expl_flash.max_flash_intensity = flash;
1156         Big_expl_flash.cur_flash_intensity = 0.0f;
1157 }
1158
1159 //      Amount to diminish palette towards normal, per second.
1160 #define DIMINISH_RATE   0.75f
1161 #define SUN_DIMINISH_RATE       6.00f
1162
1163 int Sun_drew = 0;
1164
1165 float sn_glare_scale = 1.7f;
1166 DCF(sn_glare, "")
1167 {
1168         dc_get_arg(ARG_FLOAT);
1169         sn_glare_scale = Dc_arg_float;
1170 }
1171
1172 float Supernova_last_glare = 0.0f;
1173 void game_sunspot_process(float frametime)
1174 {
1175         int n_lights, idx;
1176         int sn_stage;
1177         float Sun_spot_goal = 0.0f;
1178
1179         // supernova
1180         sn_stage = supernova_active();
1181         if(sn_stage){           
1182                 // sunspot differently based on supernova stage
1183                 switch(sn_stage){
1184                 // approaching. player still in control
1185                 case 1:                 
1186                         float pct;
1187                         pct = (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME));
1188
1189                         vector light_dir;                               
1190                         light_get_global_dir(&light_dir, 0);
1191                         float dot;
1192                         dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec );
1193                         
1194                         if(dot >= 0.0f){
1195                                 // scale it some more
1196                                 dot = dot * (0.5f + (pct * 0.5f));
1197                                 dot += 0.05f;                                   
1198
1199                                 Sun_spot_goal += (dot * sn_glare_scale);
1200                         }
1201
1202                         // draw the sun glow
1203                         if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, 0 ) )    {
1204                                 // draw the glow for this sun
1205                                 stars_draw_sun_glow(0); 
1206                         }
1207
1208                         Supernova_last_glare = Sun_spot_goal;
1209                         break;
1210
1211                 // camera cut. player not in control. note : at this point camera starts out facing the sun. so we can go nice and bright
1212                 case 2:                                         
1213                 case 3:
1214                         Sun_spot_goal = 0.9f;
1215                         Sun_spot_goal += (1.0f - (supernova_time_left() / SUPERNOVA_CUT_TIME)) * 0.1f;
1216
1217                         if(Sun_spot_goal > 1.0f){
1218                                 Sun_spot_goal = 1.0f;
1219                         }
1220
1221                         Sun_spot_goal *= sn_glare_scale;
1222                         Supernova_last_glare = Sun_spot_goal;
1223                         break;          
1224
1225                 // fade to white. display dead popup
1226                 case 4:
1227                 case 5:
1228                         Supernova_last_glare += (2.0f * flFrametime);
1229                         if(Supernova_last_glare > 2.0f){
1230                                 Supernova_last_glare = 2.0f;
1231                         }
1232
1233                         Sun_spot_goal = Supernova_last_glare;
1234                         break;
1235                 }
1236         
1237                 Sun_drew = 0;                           
1238         } else {
1239                 if ( Sun_drew ) {
1240                         // check sunspots for all suns
1241                         n_lights = light_get_global_count();
1242
1243                         // check
1244                         for(idx=0; idx<n_lights; idx++){
1245                                 //(vector *eye_pos, matrix *eye_orient)
1246                                 if ( !shipfx_eye_in_shadow( &Eye_position, Viewer_obj, idx ) )  {
1247
1248                                         vector light_dir;                               
1249                                         light_get_global_dir(&light_dir, idx);
1250
1251                                         float dot = vm_vec_dot( &light_dir, &Eye_matrix.fvec )*0.5f+0.5f;
1252
1253                                         Sun_spot_goal += (float)pow(dot,85.0f);
1254
1255                                         // draw the glow for this sun
1256                                         stars_draw_sun_glow(idx);                               
1257                                 } else {
1258                                         Sun_spot_goal = 0.0f;
1259                                 }
1260                         }
1261
1262                         Sun_drew = 0;
1263                 } else {
1264                         Sun_spot_goal = 0.0f;
1265                 }
1266         }
1267
1268         float dec_amount = frametime*SUN_DIMINISH_RATE;
1269
1270         if ( Sun_spot < Sun_spot_goal ) {
1271                 Sun_spot += dec_amount;
1272                 if ( Sun_spot > Sun_spot_goal ) {
1273                         Sun_spot = Sun_spot_goal;
1274                 }
1275         } else if ( Sun_spot > Sun_spot_goal )  {
1276                 Sun_spot -= dec_amount;
1277                 if ( Sun_spot < Sun_spot_goal ) {
1278                         Sun_spot = Sun_spot_goal;
1279                 }
1280         }
1281 }
1282
1283
1284 // Call once a frame to diminish the
1285 // flash effect to 0.
1286 void game_flash_diminish(float frametime)
1287 {
1288         float dec_amount = frametime*DIMINISH_RATE;
1289
1290         if ( Game_flash_red > 0.0f ) {
1291                 Game_flash_red -= dec_amount;           
1292                 if ( Game_flash_red < 0.0f )
1293                         Game_flash_red = 0.0f;
1294         } else {
1295                 Game_flash_red += dec_amount;           
1296                 if ( Game_flash_red > 0.0f )
1297                         Game_flash_red = 0.0f;
1298         } 
1299
1300         if ( Game_flash_green > 0.0f ) {
1301                 Game_flash_green -= dec_amount;         
1302                 if ( Game_flash_green < 0.0f )
1303                         Game_flash_green = 0.0f;
1304         } else {
1305                 Game_flash_green += dec_amount;         
1306                 if ( Game_flash_green > 0.0f )
1307                         Game_flash_green = 0.0f;
1308         } 
1309
1310         if ( Game_flash_blue > 0.0f ) {
1311                 Game_flash_blue -= dec_amount;          
1312                 if ( Game_flash_blue < 0.0f )
1313                         Game_flash_blue = 0.0f;
1314         } else {
1315                 Game_flash_blue += dec_amount;          
1316                 if ( Game_flash_blue > 0.0f )
1317                         Game_flash_blue = 0.0f;
1318         } 
1319
1320         // update big_explosion_cur_flash
1321 #define TIME_UP         1500
1322 #define TIME_DOWN       2500
1323         int duration = TIME_UP + TIME_DOWN;
1324         int time = timestamp_until(Big_expl_flash.flash_start);
1325         if (time > -duration) {
1326                 time = -time;
1327                 if (time < TIME_UP) {
1328                         Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * time / (float) TIME_UP;
1329                 } else {
1330                         time -= TIME_UP;
1331                         Big_expl_flash.cur_flash_intensity = Big_expl_flash.max_flash_intensity * ((float) TIME_DOWN - time) / (float) TIME_DOWN;
1332                 }
1333         }
1334         
1335         if ( Use_palette_flash )        {
1336                 int r,g,b;
1337 //              static int or=0, og=0, ob=0;
1338
1339                 // Change the 200 to change the color range of colors.
1340                 r = fl2i( Game_flash_red*128.0f );  
1341                 g = fl2i( Game_flash_green*128.0f );   
1342                 b = fl2i( Game_flash_blue*128.0f );  
1343
1344                 if ( Sun_spot > 0.0f )  {
1345                         r += fl2i(Sun_spot*128.0f);
1346                         g += fl2i(Sun_spot*128.0f);
1347                         b += fl2i(Sun_spot*128.0f);
1348                 }
1349
1350                 if ( Big_expl_flash.cur_flash_intensity  > 0.0f ) {
1351                         r += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1352                         g += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1353                         b += fl2i(Big_expl_flash.cur_flash_intensity*128.0f);
1354                 }
1355
1356                 if ( r < 0 ) r = 0; else if ( r > 255 ) r = 255;
1357                 if ( g < 0 ) g = 0; else if ( g > 255 ) g = 255;
1358                 if ( b < 0 ) b = 0; else if ( b > 255 ) b = 255;
1359
1360                 if ( (r!=0) || (g!=0) || (b!=0) ) {
1361                         gr_flash( r, g, b );
1362
1363                         //mprintf(( "Flash! %d,%d,%d\n", r, g, b ));
1364
1365 //                      or = r;
1366 //                      og = g;
1367 //                      ob = b;
1368                 }
1369         }
1370         
1371 }
1372
1373
1374 void game_level_close()
1375 {
1376         // De-Initialize the game subsystems
1377         message_mission_shutdown();
1378         event_music_level_close();
1379         game_stop_looped_sounds();
1380         snd_stop_all();
1381         obj_snd_level_close();                                  // uninit object-linked persistant sounds
1382         gamesnd_unload_gameplay_sounds();       // unload gameplay sounds from memory
1383         anim_level_close();                                             // stop and clean up any anim instances
1384         shockwave_level_close();
1385         fireball_level_close(); 
1386         shield_hit_close();
1387         mission_event_shutdown();
1388         asteroid_level_close();
1389         model_cache_reset();                                            // Reset/free all the model caching stuff
1390         flak_level_close();                                             // unload flak stuff
1391         neb2_level_close();                                             // shutdown gaseous nebula stuff
1392         ct_level_close();
1393         beam_level_close();
1394         mflash_level_close();
1395
1396         audiostream_unpause_all();
1397         Game_paused = 0;
1398 }
1399
1400
1401 // intializes game stuff and loads the mission.  Returns 0 on failure, 1 on success
1402 // input: seed =>       DEFAULT PARAMETER (value -1).  Only set by demo playback code.
1403 void game_level_init(int seed)
1404 {
1405         // seed the random number generator
1406         if ( seed == -1 ) {
1407                 // if no seed was passed, seed the generator either from the time value, or from the
1408                 // netgame security flags -- ensures that all players in multiplayer game will have the
1409                 // same randon number sequence (with static rand functions)
1410                 if ( Game_mode & GM_NORMAL ) {
1411                         Game_level_seed = time(NULL);
1412                 } else {
1413                         Game_level_seed = Netgame.security;
1414                 }
1415         } else {
1416                 // mwa 9/17/98 -- maybe this assert isn't needed????
1417                 Assert( !(Game_mode & GM_MULTIPLAYER) );
1418                 Game_level_seed = seed;
1419         }
1420         srand( Game_level_seed );
1421
1422         // semirand function needs to get re-initted every time in multiplayer
1423         if ( Game_mode & GM_MULTIPLAYER ){
1424                 init_semirand();
1425         }
1426
1427         Framecount = 0;
1428
1429         Key_normal_game = (Game_mode & GM_NORMAL);
1430         Cheats_enabled = 0;
1431
1432         Game_shudder_time = -1;
1433
1434         // Initialize the game subsystems
1435 //      timestamp_reset();                      // Must be inited before everything else
1436         if(!Is_standalone){
1437                 game_reset_time();                      // resets time, and resets saved time too
1438         }
1439         obj_init();                                             // Must be inited before the other systems
1440         model_free_all();                               // Free all existing models
1441         mission_brief_common_init();            // Free all existing briefing/debriefing text
1442         weapon_level_init();
1443         ai_level_init();                                //      Call this before ship_init() because it reads ai.tbl.
1444         ship_level_init();
1445         player_level_init();    
1446         shipfx_flash_init();                    // Init the ship gun flash system.
1447         game_flash_reset();                     // Reset the flash effect
1448         particle_init();                                // Reset the particle system
1449         fireball_init();
1450         debris_init();
1451         cmeasure_init();
1452         shield_hit_init();                              //      Initialize system for showing shield hits
1453         radar_mission_init();
1454         mission_init_goals();
1455         mission_log_init();
1456         messages_init();
1457         obj_snd_level_init();                                   // init object-linked persistant sounds
1458         anim_level_init();
1459         shockwave_level_init();
1460         afterburner_level_init();
1461         scoring_level_init( &Player->stats );
1462         key_level_init();
1463         asteroid_level_init();
1464         control_config_clear_used_status();
1465         collide_ship_ship_sounds_init();
1466         Missiontime = 0;
1467         Pre_player_entry = 1;                   //      Means the player has not yet entered.
1468         Entry_delay_time = 0;                   //      Could get overwritten in mission read.
1469         fireball_preload();                             //      page in warphole bitmaps
1470         observer_init();
1471         flak_level_init();                              // initialize flak - bitmaps, etc
1472         ct_level_init();                                        // initialize ships contrails, etc
1473         awacs_level_init();                             // initialize AWACS
1474         beam_level_init();                              // initialize beam weapons
1475         mflash_level_init();
1476         ssm_level_init();       
1477         supernova_level_init();
1478
1479         // multiplayer dogfight hack
1480         dogfight_blown = 0;
1481
1482         shipfx_engine_wash_level_init();
1483
1484         nebl_level_init();
1485
1486         Last_view_target = NULL;
1487         Game_paused = 0;
1488
1489         Game_no_clear = 0;
1490
1491         // campaign wasn't ended
1492         Campaign_ended_in_mission = 0;
1493 }
1494
1495 // called when a mission is over -- does server specific stuff.
1496 void freespace_stop_mission()
1497 {       
1498         game_level_close();
1499         Game_mode &= ~GM_IN_MISSION;
1500 }
1501
1502 // called at frame interval to process networking stuff
1503 void game_do_networking()
1504 {
1505         Assert( Net_player != NULL );
1506         if (!(Game_mode & GM_MULTIPLAYER)){
1507                 return;
1508         }
1509
1510         // see if this player should be reading/writing data.  Bit is set when at join
1511         // screen onward until quits back to main menu.
1512         if ( !(Net_player->flags & NETINFO_FLAG_DO_NETWORKING) ){
1513                 return;
1514         }
1515
1516         if(gameseq_get_state()!=GS_STATE_MULTI_PAUSED){
1517                 multi_do_frame();
1518         } else {
1519                 multi_pause_do_frame();
1520         }       
1521 }
1522
1523
1524 // Loads the best palette for this level, based
1525 // on nebula color and hud color.  You could just call palette_load_table with
1526 // the appropriate filename, but who wants to do that.
1527 void game_load_palette()
1528 {
1529         char palette_filename[1024];
1530
1531         // We only use 3 hud colors right now
1532         // Assert( HUD_config.color >= 0 );
1533         // Assert( HUD_config.color <= 2 );
1534
1535         Assert( Mission_palette >= 0 );
1536         Assert( Mission_palette <= 98 );
1537
1538         // if ( The_mission.flags & MISSION_FLAG_SUBSPACE )     {
1539                 strcpy( palette_filename, NOX("gamepalette-subspace") );
1540         // } else {
1541                 // sprintf( palette_filename, NOX("gamepalette%d-%02d"), HUD_config.color+1, Mission_palette+1 );
1542         // }
1543
1544         mprintf(( "Loading palette %s\n", palette_filename ));
1545
1546         // palette_load_table(palette_filename);
1547 }
1548
1549 void game_post_level_init()
1550 {
1551         // Stuff which gets called after mission is loaded.  Because player isn't created until
1552         // after mission loads, some things must get initted after the level loads
1553
1554         model_level_post_init();
1555
1556         HUD_init();
1557         hud_setup_escort_list();
1558         mission_hotkey_set_defaults();  // set up the default hotkeys (from mission file)
1559
1560         stars_level_init();     
1561         neb2_level_init();              
1562
1563 #ifndef NDEBUG
1564         game_event_debug_init();
1565 #endif
1566
1567         training_mission_init();
1568         asteroid_create_all();
1569         
1570         game_framerate_check_init();
1571 }
1572
1573
1574 // An estimate as to how high the count passed to game_loading_callback will go.
1575 // This is just a guess, it seems to always be about the same.   The count is
1576 // proportional to the code being executed, not the time, so this works good
1577 // for a bar, assuming the code does about the same thing each time you
1578 // load a level.   You can find this value by looking at the return value
1579 // of game_busy_callback(NULL), which I conveniently print out to the
1580 // debug output window with the '=== ENDING LOAD ==' stuff.   
1581 //#define COUNT_ESTIMATE 3706
1582 #define COUNT_ESTIMATE 1111
1583
1584 int Game_loading_callback_inited = 0;
1585
1586 int Game_loading_background = -1;
1587 anim * Game_loading_ani = NULL;
1588 anim_instance   *Game_loading_ani_instance;
1589 int Game_loading_frame=-1;
1590
1591 static int Game_loading_ani_coords[GR_NUM_RESOLUTIONS][2] = {
1592         {
1593                 63, 316  // GR_640
1594         },
1595         {
1596                 101, 505        // GR_1024
1597         }
1598 };
1599
1600 // This gets called 10x per second and count is the number of times 
1601 // game_busy() has been called since the current callback function
1602 // was set.
1603 void game_loading_callback(int count)
1604 {       
1605         game_do_networking();
1606
1607         Assert( Game_loading_callback_inited==1 );
1608         Assert( Game_loading_ani != NULL );
1609
1610         int framenum = ((Game_loading_ani->total_frames*count) / COUNT_ESTIMATE)+1;
1611         if ( framenum > Game_loading_ani->total_frames-1 )      {
1612                 framenum = Game_loading_ani->total_frames-1;
1613         } else if ( framenum < 0 )      {
1614                 framenum = 0;
1615         }
1616
1617         int cbitmap = -1;
1618         while ( Game_loading_frame < framenum ) {
1619                 Game_loading_frame++;
1620                 cbitmap = anim_get_next_frame(Game_loading_ani_instance);
1621         }
1622
1623
1624         if ( cbitmap > -1 )     {
1625                 if ( Game_loading_background > -1 )     {
1626                         gr_set_bitmap( Game_loading_background );
1627                         gr_bitmap(0,0);
1628                 }
1629
1630                 //mprintf(( "Showing frame %d/%d [ Bitmap=%d ]\n", Game_loading_frame ,  Game_loading_ani->total_frames, cbitmap ));
1631                 gr_set_bitmap( cbitmap );
1632                 gr_bitmap(Game_loading_ani_coords[gr_screen.res][0],Game_loading_ani_coords[gr_screen.res][1]);
1633
1634                 bm_release(cbitmap);
1635         
1636                 gr_flip();
1637         }
1638 }
1639
1640 void game_loading_callback_init()
1641 {
1642         Assert( Game_loading_callback_inited==0 );
1643
1644         Game_loading_background = bm_load(Game_loading_bground_fname[gr_screen.res]);
1645         //common_set_interface_palette("InterfacePalette");  // set the interface palette
1646
1647
1648         Game_loading_ani = anim_load( Game_loading_ani_fname[gr_screen.res]);
1649         Assert( Game_loading_ani != NULL );
1650         Game_loading_ani_instance = init_anim_instance(Game_loading_ani, 16);
1651         Assert( Game_loading_ani_instance != NULL );
1652         Game_loading_frame = -1;
1653
1654         Game_loading_callback_inited = 1;
1655         Mouse_hidden = 1;
1656         game_busy_callback( game_loading_callback, (COUNT_ESTIMATE/Game_loading_ani->total_frames)+1 ); 
1657
1658
1659 }
1660
1661 void game_loading_callback_close()
1662 {
1663         Assert( Game_loading_callback_inited==1 );
1664
1665         // Make sure bar shows all the way over.
1666         game_loading_callback(COUNT_ESTIMATE);
1667         
1668         int real_count = game_busy_callback( NULL );
1669         Mouse_hidden = 0;
1670
1671         Game_loading_callback_inited = 0;
1672         
1673 #ifndef NDEBUG
1674         mprintf(( "=================== ENDING LOAD ================\n" ));
1675         mprintf(( "Real count = %d,  Estimated count = %d\n", real_count, COUNT_ESTIMATE ));
1676         mprintf(( "================================================\n" ));
1677 #else
1678         // to remove warnings in release build
1679         real_count = 0;
1680 #endif
1681
1682         free_anim_instance(Game_loading_ani_instance);
1683         Game_loading_ani_instance = NULL;
1684         anim_free(Game_loading_ani);
1685         Game_loading_ani = NULL;
1686
1687         bm_release( Game_loading_background );
1688         common_free_interface_palette();                // restore game palette
1689         Game_loading_background = -1;
1690
1691         gr_set_font( FONT1 );
1692 }
1693
1694 // Update the sound environment (ie change EAX settings based on proximity to large ships)
1695 //
1696 void game_maybe_update_sound_environment()
1697 {
1698         // do nothing for now
1699 }
1700
1701 // Assign the sound environment for the game, based on the current mission
1702 //
1703 void game_assign_sound_environment()
1704 {
1705         /*
1706         if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
1707                 Game_sound_env.id = SND_ENV_DRUGGED;
1708                 Game_sound_env.volume = 0.800f;
1709                 Game_sound_env.damping = 1.188f;
1710                 Game_sound_env.decay = 6.392f;
1711 #ifndef FS2_DEMO
1712         } else if (Num_asteroids > 30) {
1713                 Game_sound_env.id = SND_ENV_AUDITORIUM;
1714                 Game_sound_env.volume = 0.603f;
1715                 Game_sound_env.damping = 0.5f;
1716                 Game_sound_env.decay = 4.279f;
1717 #endif
1718         } else {
1719                 Game_sound_env = Game_default_sound_env;
1720         }
1721         */
1722
1723         Game_sound_env = Game_default_sound_env;
1724         Game_sound_env_update_timestamp = timestamp(1);
1725 }
1726
1727 // function which gets called before actually entering the mission.  It is broken down into a funciton
1728 // since it will get called in one place from a single player game and from another place for
1729 // a multiplayer game
1730 void freespace_mission_load_stuff()
1731 {
1732         // called if we're not on a freespace dedicated (non rendering, no pilot) server
1733         // IE : we _don't_ want to load any sounds or bitmap/texture info on this machine.
1734         if(!(Game_mode & GM_STANDALONE_SERVER)){        
1735         
1736                 mprintf(( "=================== STARTING LEVEL DATA LOAD ==================\n" ));
1737
1738                 game_loading_callback_init();
1739                 
1740                 event_music_level_init();       // preloads the first 2 seconds for each event music track
1741                 game_busy();
1742
1743                 gamesnd_unload_interface_sounds();              // unload interface sounds from memory
1744                 game_busy();
1745
1746                 gamesnd_preload_common_sounds();                        // load in sounds that are expected to play
1747                 game_busy();
1748
1749                 ship_assign_sound_all();        // assign engine sounds to ships
1750                 game_assign_sound_environment();         // assign the sound environment for this mission
1751                 game_busy();
1752
1753                 // call function in missionparse.cpp to fixup player/ai stuff.
1754                 mission_parse_fixup_players();
1755                 game_busy();
1756
1757                 // Load in all the bitmaps for this level
1758                 level_page_in();
1759
1760                 game_busy();
1761
1762                 game_loading_callback_close();  
1763         } 
1764         // the only thing we need to call on the standalone for now.
1765         else {
1766                 // call function in missionparse.cpp to fixup player/ai stuff.
1767                 mission_parse_fixup_players();
1768
1769                 // Load in all the bitmaps for this level
1770                 level_page_in();
1771         }
1772 }
1773
1774 uint load_gl_init;
1775 uint load_mission_load;
1776 uint load_post_level_init;
1777 uint load_mission_stuff;
1778
1779 // tells the server to load the mission and initialize structures
1780 int game_start_mission()
1781 {       
1782         mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
1783         
1784         load_gl_init = time(NULL);
1785         game_level_init();
1786         load_gl_init = time(NULL) - load_gl_init;
1787         
1788         if (Game_mode & GM_MULTIPLAYER) {
1789                 Player->flags |= PLAYER_FLAGS_IS_MULTI;
1790
1791                 // clear multiplayer stats
1792                 init_multiplayer_stats();
1793         }
1794
1795         load_mission_load = time(NULL);
1796         if (mission_load()) {
1797                 if ( !(Game_mode & GM_MULTIPLAYER) ) {
1798                         popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "Attempt to load the mission failed", 169));
1799                         gameseq_post_event(GS_EVENT_MAIN_MENU);
1800                 } else {
1801                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_LOAD_FAIL);
1802                 }
1803
1804                 return 0;
1805         }
1806         load_mission_load = time(NULL) - load_mission_load;
1807
1808         // If this is a red alert mission in campaign mode, bash wingman status
1809         if ( (Game_mode & GM_CAMPAIGN_MODE) && red_alert_mission() ) {
1810                 red_alert_bash_wingman_status();
1811         }
1812
1813         // the standalone server in multiplayer doesn't do any rendering, so we will not even bother loading the palette
1814         if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
1815                 mprintf(( "=================== LOADING GAME PALETTE ================\n" ));
1816                 // game_load_palette();
1817         }
1818
1819         load_post_level_init = time(NULL);
1820         game_post_level_init();
1821         load_post_level_init = time(NULL) - load_post_level_init;
1822
1823         #ifndef NDEBUG
1824         {
1825                 void Do_model_timings_test();
1826                 Do_model_timings_test();        
1827         }
1828         #endif
1829
1830         load_mission_stuff = time(NULL);
1831         freespace_mission_load_stuff();
1832         load_mission_stuff = time(NULL) - load_mission_stuff;
1833
1834         return 1;
1835 }
1836
1837 int Interface_framerate = 0;
1838 #ifndef NDEBUG
1839
1840 DCF_BOOL( mouse_control, Use_mouse_to_fly )
1841 DCF_BOOL( show_framerate, Show_framerate )
1842 DCF_BOOL( show_target_debug_info, Show_target_debug_info )
1843 DCF_BOOL( show_target_weapons, Show_target_weapons )
1844 DCF_BOOL( lead_target_cheat, Players[Player_num].lead_target_cheat )
1845 DCF_BOOL( sound, Sound_enabled )
1846 DCF_BOOL( zbuffer, game_zbuffer )
1847 DCF_BOOL( shield_system, New_shield_system )
1848 DCF_BOOL( show_shield_mesh, Show_shield_mesh)
1849 DCF_BOOL( player_attacking, Player_attacking_enabled )
1850 DCF_BOOL( show_waypoints, Show_waypoints )
1851 DCF_BOOL( show_area_effect, Show_area_effect )
1852 DCF_BOOL( show_net_stats, Show_net_stats )
1853 DCF_BOOL( log, Log_debug_output_to_file )
1854 DCF_BOOL( training_msg_method, Training_msg_method )
1855 DCF_BOOL( show_player_pos, Show_player_pos )
1856 DCF_BOOL(i_framerate, Interface_framerate )
1857
1858 DCF(show_mem,"Toggles showing mem usage")
1859 {
1860         if ( Dc_command )       {       
1861                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1862                 if ( Dc_arg_type & ARG_TRUE )   Show_mem = 1;   
1863                 else if ( Dc_arg_type & ARG_FALSE ) Show_mem = 0;       
1864                 else if ( Dc_arg_type & ARG_NONE ) Show_mem ^= 1;       
1865
1866                 if ( Show_mem ) {
1867                         Show_cpu = 0;
1868                 }
1869         }       
1870         if ( Dc_help )  dc_printf( "Usage: Show_mem\nSets show_mem to true or false.  If nothing passed, then toggles it.\n" ); 
1871         if ( Dc_status )        {
1872                 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );     
1873                 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );     
1874         }
1875 }
1876
1877 DCF(show_cpu,"Toggles showing cpu usage")
1878 {
1879         if ( Dc_command )       {       
1880                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1881                 if ( Dc_arg_type & ARG_TRUE )   Show_cpu = 1;   
1882                 else if ( Dc_arg_type & ARG_FALSE ) Show_cpu = 0;       
1883                 else if ( Dc_arg_type & ARG_NONE ) Show_cpu ^= 1;       
1884
1885                 if ( Show_cpu ) {
1886                         Show_mem = 0;
1887                 }
1888         }       
1889         if ( Dc_help )  dc_printf( "Usage: Show_cpu\nSets show_cpu to true or false.  If nothing passed, then toggles it.\n" ); 
1890         if ( Dc_status )        {
1891                 dc_printf( "Show_mem is %s\n", (Show_mem?"TRUE":"FALSE") );     
1892                 dc_printf( "Show_cpu is %s\n", (Show_cpu?"TRUE":"FALSE") );     
1893
1894         }
1895 }
1896
1897 #else
1898
1899         // AL 4-8-98: always allow players to display their framerate
1900
1901         #ifdef FS2_DEMO
1902                 DCF_BOOL( show_framerate, Show_framerate )
1903         #endif
1904
1905 #endif  // NDEBUG
1906
1907                         int Game_init_seed;
1908
1909 DCF(use_joy_mouse,"Makes joystick move mouse cursor")
1910 {
1911         if ( Dc_command )       {       
1912                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1913                 if ( Dc_arg_type & ARG_TRUE )   Use_joy_mouse = 1;      
1914                 else if ( Dc_arg_type & ARG_FALSE ) Use_joy_mouse = 0;  
1915                 else if ( Dc_arg_type & ARG_NONE ) Use_joy_mouse ^= 1;  
1916         }       
1917         if ( Dc_help )  dc_printf( "Usage: use_joy_mouse [bool]\nSets use_joy_mouse to true or false.  If nothing passed, then toggles it.\n" );        
1918         if ( Dc_status )        dc_printf( "use_joy_mouse is %s\n", (Use_joy_mouse?"TRUE":"FALSE") );   
1919
1920         os_config_write_uint( NULL, NOX("JoystickMovesCursor"), Use_joy_mouse );
1921 }
1922
1923 DCF(palette_flash,"Toggles palette flash effect on/off")
1924 {
1925         if ( Dc_command )       {       
1926                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1927                 if ( Dc_arg_type & ARG_TRUE )   Use_palette_flash = 1;  
1928                 else if ( Dc_arg_type & ARG_FALSE ) Use_palette_flash = 0;      
1929                 else if ( Dc_arg_type & ARG_NONE ) Use_palette_flash ^= 1;      
1930         }       
1931         if ( Dc_help )  dc_printf( "Usage: palette_flash [bool]\nSets palette_flash to true or false.  If nothing passed, then toggles it.\n" );        
1932         if ( Dc_status )        dc_printf( "palette_flash is %s\n", (Use_palette_flash?"TRUE":"FALSE") );       
1933 }
1934
1935 int Use_low_mem = 0;
1936
1937 DCF(low_mem,"Uses low memory settings regardless of RAM")
1938 {
1939         if ( Dc_command )       {       
1940                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1941                 if ( Dc_arg_type & ARG_TRUE )   Use_low_mem = 1;        
1942                 else if ( Dc_arg_type & ARG_FALSE ) Use_low_mem = 0;    
1943                 else if ( Dc_arg_type & ARG_NONE ) Use_low_mem ^= 1;    
1944         }       
1945         if ( Dc_help )  dc_printf( "Usage: low_mem [bool]\nSets low_mem to true or false.  If nothing passed, then toggles it.\n" );    
1946         if ( Dc_status )        dc_printf( "low_mem is %s\n", (Use_low_mem?"TRUE":"FALSE") );   
1947
1948         os_config_write_uint( NULL, NOX("LowMem"), Use_low_mem );
1949 }
1950
1951
1952 #ifndef NDEBUG
1953
1954 DCF(force_fullscreen, "Forces game to startup in fullscreen mode")
1955 {
1956         if ( Dc_command )       {       
1957                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
1958                 if ( Dc_arg_type & ARG_TRUE )   Use_fullscreen_at_startup = 1;  
1959                 else if ( Dc_arg_type & ARG_FALSE ) Use_fullscreen_at_startup = 0;      
1960                 else if ( Dc_arg_type & ARG_NONE ) Use_fullscreen_at_startup ^= 1;      
1961         }       
1962         if ( Dc_help )  dc_printf( "Usage: force_fullscreen [bool]\nSets force_fullscreen to true or false.  If nothing passed, then toggles it.\n" );  
1963         if ( Dc_status )        dc_printf( "force_fullscreen is %s\n", (Use_fullscreen_at_startup?"TRUE":"FALSE") );    
1964         os_config_write_uint( NULL, NOX("ForceFullscreen"), Use_fullscreen_at_startup );
1965 }
1966 #endif
1967
1968 int     Framerate_delay = 0;
1969
1970 float Freespace_gamma = 1.0f;
1971
1972 DCF(gamma,"Sets Gamma factor")
1973 {
1974         if ( Dc_command )       {
1975                 dc_get_arg(ARG_FLOAT|ARG_NONE);
1976                 if ( Dc_arg_type & ARG_FLOAT )  {
1977                         Freespace_gamma = Dc_arg_float;
1978                 } else {
1979                         dc_printf( "Gamma reset to 1.0f\n" );
1980                         Freespace_gamma = 1.0f;
1981                 }
1982                 if ( Freespace_gamma < 0.1f )   {
1983                         Freespace_gamma = 0.1f;
1984                 } else if ( Freespace_gamma > 5.0f )    {
1985                         Freespace_gamma = 5.0f;
1986                 }
1987                 gr_set_gamma(Freespace_gamma);
1988
1989                 char tmp_gamma_string[32];
1990                 sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
1991                 os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
1992         }
1993
1994         if ( Dc_help )  {
1995                 dc_printf( "Usage: gamma <float>\n" );
1996                 dc_printf( "Sets gamma in range 1-3, no argument resets to default 1.2\n" );
1997                 Dc_status = 0;  // don't print status if help is printed.  Too messy.
1998         }
1999
2000         if ( Dc_status )        {
2001                 dc_printf( "Gamma = %.2f\n", Freespace_gamma );
2002         }
2003 }
2004
2005 void game_init()
2006 {
2007         char *ptr;
2008         int depth = 16;
2009
2010         Game_current_mission_filename[0] = 0;
2011
2012         // seed the random number generator
2013         Game_init_seed = time(NULL);
2014         srand( Game_init_seed );
2015
2016         Framerate_delay = 0;
2017
2018         #ifndef NDEBUG
2019         load_filter_info();
2020         #endif
2021
2022         extern void bm_init();
2023         bm_init();
2024
2025         // encrypt stuff
2026         encrypt_init();
2027
2028         // Initialize the timer before the os
2029         timer_init();
2030
2031         int s1, e1;
2032         // int s2, e2;
2033
2034         char whee[1024];
2035 #ifndef PLAT_UNIX       
2036         GetCurrentDirectory(1024, whee);
2037 #else
2038         strcpy(whee, ".");
2039         STUB_FUNCTION;
2040 #endif
2041         strcat(whee, "\\");
2042         strcat(whee, EXE_FNAME);
2043
2044         //Initialize the libraries
2045         s1 = timer_get_milliseconds();
2046         if(cfile_init(whee, Game_CDROM_dir)){                   // initialize before calling any cfopen stuff!!!
2047                 exit(1);
2048         }               
2049         e1 = timer_get_milliseconds();
2050
2051         // time a bunch of cfopens      
2052         /*
2053         s2 = timer_get_milliseconds();  
2054         CFILE *whee;
2055         for(int idx=0; idx<10000; idx++){
2056                 whee = cfopen("capital01.pof", "rb", CFILE_NORMAL, CF_TYPE_MODELS);
2057                 if(whee != NULL){
2058                         cfclose(whee);
2059                 }
2060                 whee = NULL;
2061                 //cf_exist("capital01.pof", CF_TYPE_MODELS);
2062         }
2063         e2 = timer_get_milliseconds();  
2064         */
2065
2066         if (Is_standalone) {
2067                 std_init_standalone();
2068         } else {                
2069                 os_init( Osreg_class_name, Osreg_app_name );
2070                 os_set_title(Osreg_title);
2071         }
2072
2073         // initialize localization module. Make sure this is down AFTER initialzing OS.
2074 //      int t1 = timer_get_milliseconds();
2075         lcl_init();     
2076         lcl_xstr_init();
2077 //      mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2078
2079         // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2080         verify_ships_tbl();
2081
2082         // verify that he has a valid weapons.tbl
2083         verify_weapons_tbl();
2084
2085         // Output version numbers to registry for auto patching purposes
2086         os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2087         os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2088         os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2089
2090         Use_joy_mouse = 0;              //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2091         //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2092         Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2093
2094 #ifndef NDEBUG
2095         Use_fullscreen_at_startup = os_config_read_uint( NULL, NOX("ForceFullscreen"), 1 );
2096 #endif
2097
2098 #ifndef FS2_DEMO
2099         Asteroids_enabled = 1;          
2100 #endif
2101
2102 /////////////////////////////
2103 // SOUND INIT START
2104 /////////////////////////////
2105
2106         int use_a3d = 0;
2107         int use_eax = 0;
2108
2109         ptr = os_config_read_string(NULL, NOX("Soundcard"), NULL);
2110         mprintf(("soundcard = %s\n", ptr ? ptr : "<nothing>"));
2111         if (ptr) {
2112                 if (!stricmp(ptr, NOX("no sound"))) {
2113                         Cmdline_freespace_no_sound = 1;
2114
2115                 } else if (!stricmp(ptr, NOX("Aureal A3D"))) {
2116                         use_a3d = 1;
2117                 } else if (!stricmp(ptr, NOX("EAX"))) {
2118                         use_eax = 1;
2119                 }
2120         }
2121
2122         if (!Is_standalone) {
2123                 snd_init(use_a3d, use_eax);
2124         }
2125 /////////////////////////////
2126 // SOUND INIT END
2127 /////////////////////////////
2128         
2129         ptr = os_config_read_string(NULL, NOX("Videocard"), NULL);
2130         if (ptr == NULL) {
2131 #ifndef PLAT_UNIX       
2132                 MessageBox((HWND)os_get_window(), XSTR("Please configure your system in the Launcher before running FS2.\n\n The Launcher will now be started!", 1446), XSTR("Attention!", 1447), MB_OK);
2133
2134                 // fire up the UpdateLauncher executable
2135                 STARTUPINFO si;
2136                 PROCESS_INFORMATION pi;
2137
2138                 memset( &si, 0, sizeof(STARTUPINFO) );
2139                 si.cb = sizeof(si);
2140
2141                 BOOL ret = CreateProcess(       LAUNCHER_FNAME, // pointer to name of executable module 
2142                                                                         NULL,                                                   // pointer to command line string
2143                                                                         NULL,                                                   // pointer to process security attributes 
2144                                                                         NULL,                                                   // pointer to thread security attributes 
2145                                                                         FALSE,                                                  // handle inheritance flag 
2146                                                                         CREATE_DEFAULT_ERROR_MODE,              // creation flags 
2147                                                                         NULL,                                                   // pointer to new environment block 
2148                                                                         NULL,   // pointer to current directory name 
2149                                                                         &si,    // pointer to STARTUPINFO 
2150                                                                         &pi     // pointer to PROCESS_INFORMATION  
2151                                                                 );                      
2152
2153                 // If the Launcher could not be started up, let the user know
2154                 if (!ret) {
2155                         MessageBox((HWND)os_get_window(), XSTR("The Launcher could not be restarted.", 1450), XSTR("Error", 1451), MB_OK);
2156                 }
2157 #else
2158                 STUB_FUNCTION;
2159 #endif          
2160                 exit(1);
2161         }
2162
2163         if(!Is_standalone){
2164                 if(!stricmp(ptr, "Aucune accélération 3D") || !stricmp(ptr, "Keine 3D-Beschleunigerkarte") || !stricmp(ptr, "No 3D acceleration")){
2165 #ifndef PLAT_UNIX               
2166                         MessageBox((HWND)os_get_window(), XSTR("Warning, Freespace 2 requires Glide or Direct3D hardware accleration. You will not be able to run Freespace 2 without it.", 1448), XSTR("Warning", 1449), MB_OK);
2167 #else
2168                         STUB_FUNCTION;
2169 #endif                                          
2170                         exit(1);
2171                 }
2172         }
2173
2174         // check for hi res pack file 
2175         int has_sparky_hi = 0;
2176
2177         // check if sparky_hi exists -- access mode 0 means does file exist
2178         char dir[128];
2179         _getcwd(dir, 128);
2180         if ( _access("sparky_hi_fs2.vp", 0) == 0) {
2181                 has_sparky_hi = 1;
2182         } else {
2183                 mprintf(("No sparky_hi_fs2.vp in directory %s\n", dir));
2184         }
2185
2186         // see if we've got 32 bit in the string
2187         if(strstr(ptr, "32 bit")){
2188                 depth = 32;
2189         }
2190
2191         int trying_d3d = 0;
2192         
2193         if (!Is_standalone && ptr && (strstr(ptr, NOX("3DFX Glide")))) {
2194 #ifdef E3_BUILD
2195                 // always 640 for E3
2196                 gr_init(GR_640, GR_GLIDE);
2197 #else
2198                 // regular or hi-res ?
2199 #ifdef NDEBUG
2200                 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2201 #else
2202                 if(strstr(ptr, NOX("(1024x768)"))){
2203 #endif
2204                         gr_init(GR_1024, GR_GLIDE);
2205                 } else {                        
2206                         gr_init(GR_640, GR_GLIDE);
2207                 }
2208 #endif
2209         } else if (!Is_standalone && ptr && (strstr(ptr, NOX("Direct 3D -") ))) {
2210 #ifdef E3_BUILD         
2211                 // always 640 for E3
2212                 trying_d3d = 1;
2213                 gr_init(GR_640, GR_DIRECT3D, depth);            
2214 #else
2215                 // regular or hi-res ?
2216 #ifdef NDEBUG
2217                 if(has_sparky_hi && strstr(ptr, NOX("(1024x768)"))){
2218 #else
2219                 if(strstr(ptr, NOX("(1024x768)"))){
2220 #endif
2221                         // Direct 3D
2222                         trying_d3d = 1;
2223                         gr_init(GR_1024, GR_DIRECT3D, depth);
2224                 } else {
2225                         // Direct 3D
2226                         trying_d3d = 1;
2227                         gr_init(GR_640, GR_DIRECT3D, depth);
2228                 }
2229 #endif
2230         } else {
2231                 // Software
2232                 #ifndef NDEBUG
2233                         if ( Use_fullscreen_at_startup && !Is_standalone)       {               
2234                                 gr_init(GR_640, GR_DIRECTDRAW);
2235                         } else {
2236                                 gr_init(GR_640, GR_SOFTWARE);
2237                         }
2238                 #else
2239                         if ( !Is_standalone ) {
2240                                 gr_init(GR_640, GR_DIRECTDRAW);
2241                         } else {
2242                                 gr_init(GR_640, GR_SOFTWARE);
2243                         }
2244                 #endif
2245         }
2246
2247         // tried d3d ?
2248         extern int Gr_inited;
2249         if(trying_d3d && !Gr_inited){
2250                 extern char Device_init_error[512];
2251 #ifndef PLAT_UNIX               
2252                 MessageBox( NULL, Device_init_error, "Error intializing Direct3D", MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
2253 #lse
2254                 STUB_FUNCTION;
2255 #endif          
2256                 exit(1);
2257                 return;
2258         }
2259
2260         // Set the gamma
2261         ptr = os_config_read_string(NULL,NOX("Gamma"),NOX("1.80"));
2262         Freespace_gamma = (float)atof(ptr);
2263         if ( Freespace_gamma < 0.1f )   {
2264                 Freespace_gamma = 0.1f;
2265         } else if ( Freespace_gamma > 5.0f )    {
2266                 Freespace_gamma = 5.0f;
2267         }
2268         char tmp_gamma_string[32];
2269         sprintf( tmp_gamma_string, NOX("%.2f"), Freespace_gamma );
2270         os_config_write_string( NULL, NOX("Gamma"), tmp_gamma_string );
2271
2272         gr_set_gamma(Freespace_gamma);
2273
2274 #if defined(FS2_DEMO) || defined(OEM_BUILD)
2275         // add title screen
2276         if(!Is_standalone){
2277                 display_title_screen();
2278         }
2279 #endif
2280         
2281         // attempt to load up master tracker registry info (login and password)
2282         Multi_tracker_id = -1;          
2283
2284         // pxo login and password
2285         ptr = os_config_read_string(NOX("PXO"),NOX("Login"),NULL);
2286         if(ptr == NULL){
2287                 nprintf(("Network","Error reading in PXO login data\n"));
2288                 strcpy(Multi_tracker_login,"");
2289         } else {                
2290                 strcpy(Multi_tracker_login,ptr);
2291         }
2292         ptr = os_config_read_string(NOX("PXO"),NOX("Password"),NULL);
2293         if(ptr == NULL){                
2294                 nprintf(("Network","Error reading PXO password\n"));
2295                 strcpy(Multi_tracker_passwd,"");
2296         } else {                
2297                 strcpy(Multi_tracker_passwd,ptr);
2298         }       
2299
2300         // pxo squad name and password
2301         ptr = os_config_read_string(NOX("PXO"),NOX("SquadName"),NULL);
2302         if(ptr == NULL){
2303                 nprintf(("Network","Error reading in PXO squad name\n"));
2304                 strcpy(Multi_tracker_squad_name, "");
2305         } else {                
2306                 strcpy(Multi_tracker_squad_name, ptr);
2307         }
2308
2309         // If less than 48MB of RAM, use low memory model.
2310         if ( (Freespace_total_ram < 48*1024*1024) || Use_low_mem )      {
2311                 mprintf(( "Using normal memory settings...\n" ));
2312                 bm_set_low_mem(1);              // Use every other frame of bitmaps
2313         } else {
2314                 mprintf(( "Using high memory settings...\n" ));
2315                 bm_set_low_mem(0);              // Use all frames of bitmaps
2316         }
2317
2318         // load non-darkening pixel defs
2319         palman_load_pixels();
2320
2321         // hud shield icon stuff
2322         hud_shield_game_init();
2323
2324         control_config_common_init();                           // sets up localization stuff in the control config
2325         parse_rank_tbl();
2326         parse_medal_tbl();
2327         cutscene_init();
2328         key_init();
2329         mouse_init();
2330         gamesnd_parse_soundstbl();
2331         radar_init();
2332         gameseq_init();
2333         multi_init();   
2334
2335         // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2336         if(!Is_standalone){
2337                 joy_init();
2338         }
2339
2340         player_controls_init();
2341         model_init();   
2342
2343         //if(!Is_standalone){
2344                 event_music_init();
2345         //}     
2346
2347         obj_init();     
2348         mflash_game_init();     
2349         weapon_init();  
2350         ai_init();              
2351         ship_init();                                            // read in ships.tbl    
2352         player_init();  
2353         mission_campaign_init();                // load in the default campaign 
2354         anim_init();
2355 //      navmap_init();                                          // init the navigation map system
2356         context_help_init();                    
2357         techroom_intel_init();                  // parse species.tbl, load intel info   
2358         // initialize psnet
2359         psnet_init( Multi_options_g.protocol, Multi_options_g.port );                                           // initialize the networking code               
2360         init_animating_pointer();       
2361         asteroid_init();
2362         mission_brief_common_init();    // Mark all the briefing structures as empty.           
2363         gr_font_init();                                 // loads up all fonts           
2364
2365         neb2_init();                                            // fullneb stuff
2366         nebl_init();
2367         stars_init();
2368         ssm_init();     
2369         player_tips_init();                             // helpful tips
2370         beam_init();
2371         
2372         // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2373         pilot_load_pic_list();  
2374         pilot_load_squad_pic_list();
2375
2376         load_animating_pointer(NOX("cursor"), 0, 0);    
2377
2378         // initialize alpha colors
2379         alpha_colors_init();    
2380
2381         Viewer_mode = 0;
2382 //      Game_music_paused = 0;
2383         Game_paused = 0;
2384
2385 #ifndef PLAT_UNIX
2386         timeBeginPeriod(1);     
2387 #endif
2388
2389         nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2390         nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2391
2392         mprintf(("cfile_init() took %d\n", e1 - s1));
2393         // mprintf(("1000 cfopens() took %d\n", e2 - s2));      
2394 }
2395
2396 char transfer_text[128];
2397
2398 float   Start_time = 0.0f;
2399
2400 float Framerate = 0.0f;
2401
2402 float Timing_total = 0.0f;
2403 float Timing_render2 = 0.0f;
2404 float Timing_render3 = 0.0f;
2405 float Timing_flip = 0.0f;
2406 float Timing_clear = 0.0f;
2407
2408 MONITOR(NumPolysDrawn);
2409 MONITOR(NumPolys);
2410 MONITOR(NumVerts);
2411 MONITOR(BmpUsed);
2412 MONITOR(BmpNew);
2413
2414 void game_get_framerate()
2415 {       
2416         char text[128] = "";
2417
2418         if ( frame_int == -1 )  {
2419                 int i;
2420                 for (i=0; i<FRAME_FILTER; i++ ) {
2421                         frametimes[i] = 0.0f;
2422                 }
2423                 frametotal = 0.0f;
2424                 frame_int = 0;
2425         }
2426         frametotal -= frametimes[frame_int];
2427         frametotal += flFrametime;
2428         frametimes[frame_int] = flFrametime;
2429         frame_int = (frame_int + 1 ) % FRAME_FILTER;
2430
2431         if ( frametotal != 0.0 )        {
2432                 if ( Framecount >= FRAME_FILTER )
2433                         Framerate = FRAME_FILTER / frametotal;
2434                 else
2435                         Framerate = Framecount / frametotal;
2436                 sprintf( text, NOX("FPS: %.1f"), Framerate );
2437         } else {
2438                 sprintf( text, NOX("FPS: ?") );
2439         }
2440         Framecount++;
2441
2442         if (Show_framerate)     {
2443                 gr_set_color_fast(&HUD_color_debug);
2444                 gr_string( 570, 2, text );
2445         }
2446 }
2447
2448 void game_show_framerate()
2449 {       
2450         float   cur_time;
2451
2452         cur_time = f2fl(timer_get_approx_seconds());
2453         if (cur_time - Start_time > 30.0f) {
2454                 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2455                 Start_time += 1000.0f;
2456         }
2457
2458         //mprintf(( "%s\n", text ));
2459
2460 #ifndef NDEBUG
2461         if ( Debug_dump_frames )
2462                 return;
2463 #endif  
2464
2465         // possibly show control checking info
2466         control_check_indicate();
2467
2468 //      int bitmaps_used_this_frame, bitmaps_new_this_frame;
2469 //      bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2470 //      MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2471 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2472
2473 #ifndef NDEBUG
2474         if ( Show_cpu == 1 ) {
2475                 
2476                 int sx,sy,dy;
2477                 sx = 530;
2478                 sy = 15;
2479                 dy = gr_get_font_height() + 1;
2480
2481                 gr_set_color_fast(&HUD_color_debug);
2482
2483                 {
2484                         extern int D3D_textures_in;
2485                         extern int D3D_textures_in_frame;
2486                         extern int Glide_textures_in;
2487                         extern int Glide_textures_in_frame;
2488                         extern int Glide_explosion_vram;
2489                         gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2490                         sy += dy;
2491                         gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame+D3D_textures_in_frame)/1024 );
2492                         sy += dy;
2493                         gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2494                         sy += dy;
2495                 }
2496 //              gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2497 //              sy += dy;
2498                 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2499                 sy += dy;
2500                 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2501                 sy += dy;
2502                 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2503                 sy += dy;
2504                 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2505                 sy += dy;
2506
2507                 {
2508
2509                         extern int Num_pairs;           // Number of object pairs that were checked.
2510                         gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2511                         sy += dy;
2512
2513                         extern int Num_pairs_checked;   // What percent of object pairs were checked.
2514                         gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2515                         sy += dy;
2516                         Num_pairs_checked = 0;
2517
2518                 }
2519
2520                 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2521                 sy += dy;
2522
2523                 if ( Timing_total > 0.01f )     {
2524                         gr_printf(  sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2525                         sy += dy;
2526                         gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2527                         sy += dy;
2528                         gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2529                         sy += dy;
2530                         gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2531                         sy += dy;
2532                         gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2533                         sy += dy;
2534                 }
2535         }
2536                 
2537         if ( Show_mem  ) {
2538                 
2539                 int sx,sy,dy;
2540                 sx = 530;
2541                 sy = 15;
2542                 dy = gr_get_font_height() + 1;
2543
2544                 gr_set_color_fast(&HUD_color_debug);
2545
2546                 {
2547                         extern int TotalRam;
2548                         gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2549                         sy += dy;
2550                 }       
2551
2552                 {
2553                         extern int Model_ram;
2554                         gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2555                         sy += dy;
2556                 }       
2557
2558                 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2559                 sy += dy;
2560                 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 );             // mem used to store game sound
2561                 sy += dy;
2562                 gr_printf( sx, sy, NOX("S-HRAM: %d KB\n"), Snd_hram/1024 );             // mem used to store game sound
2563                 sy += dy;
2564                 {
2565                         extern int D3D_textures_in;
2566                         extern int Glide_textures_in;
2567                         extern int Glide_textures_in_frame;
2568                         extern int Glide_explosion_vram;
2569                         gr_printf( sx, sy, NOX("VRAM: %d KB\n"), (D3D_textures_in+Glide_textures_in)/1024 );
2570                         sy += dy;
2571                         gr_printf( sx, sy, NOX("VRAM: +%d KB\n"), (Glide_textures_in_frame)/1024 );
2572                         sy += dy;
2573                         gr_printf( sx, sy, NOX("EXP VRAM: %dKB\n"), (Glide_explosion_vram)/1024 );
2574                         sy += dy;
2575                 }
2576         }
2577
2578
2579         if ( Show_player_pos ) {
2580                 int sx, sy;
2581                 sx = 320;
2582                 sy = 100;
2583                 gr_printf(sx, sy, NOX("Player Pos: (%d,%d,%d)"), fl2i(Player_obj->pos.x), fl2i(Player_obj->pos.y), fl2i(Player_obj->pos.z));
2584         }
2585
2586         MONITOR_INC(NumPolys, modelstats_num_polys);
2587         MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2588         MONITOR_INC(NumVerts, modelstats_num_verts );
2589
2590         modelstats_num_polys = 0;
2591         modelstats_num_polys_drawn = 0;
2592         modelstats_num_verts = 0;
2593         modelstats_num_sortnorms = 0;
2594 #endif
2595 }
2596
2597 void game_show_standalone_framerate()
2598 {
2599         float frame_rate=30.0f;
2600         if ( frame_int == -1 )  {
2601                 int i;
2602                 for (i=0; i<FRAME_FILTER; i++ ) {
2603                         frametimes[i] = 0.0f;
2604                 }
2605                 frametotal = 0.0f;
2606                 frame_int = 0;
2607         }
2608         frametotal -= frametimes[frame_int];
2609         frametotal += flFrametime;
2610         frametimes[frame_int] = flFrametime;
2611         frame_int = (frame_int + 1 ) % FRAME_FILTER;
2612
2613         if ( frametotal != 0.0 )        {
2614                 if ( Framecount >= FRAME_FILTER ){
2615                         frame_rate = FRAME_FILTER / frametotal;
2616                 } else {
2617                         frame_rate = Framecount / frametotal;
2618                 }
2619         }
2620         std_set_standalone_fps(frame_rate);
2621         Framecount++;
2622 }
2623
2624 // function to show the time remaining in a mission.  Used only when the end-mission sexpression is used
2625 void game_show_time_left()
2626 {
2627         int diff;
2628
2629         // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2630         // mission should end (in fixed seconds).  There is code in missionparse.cpp which actually handles
2631         // checking how much time is left
2632
2633         if ( Mission_end_time == -1 ){
2634                 return;
2635         }
2636
2637         diff = f2i(Mission_end_time - Missiontime);
2638         // be sure to bash to 0.  diff could be negative on frame that we quit mission
2639         if ( diff < 0 ){
2640                 diff = 0;
2641         }
2642
2643         hud_set_default_color();
2644         gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2645 }
2646
2647 //========================================================================================
2648 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2649 //========================================================================================
2650
2651 #ifndef NDEBUG
2652
2653 DCF(ai_pause,"Pauses ai")
2654 {
2655         if ( Dc_command )       {       
2656                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
2657                 if ( Dc_arg_type & ARG_TRUE )   ai_paused = 1;  
2658                 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;      
2659                 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;      
2660
2661                 if (ai_paused)  {       
2662                         obj_init_all_ships_physics();
2663                 }
2664         }       
2665         if ( Dc_help )  dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false.  If nothing passed, then toggles it.\n" );        
2666         if ( Dc_status )        dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );   
2667 }
2668
2669 DCF(single_step,"Single steps the game")
2670 {
2671         if ( Dc_command )       {       
2672                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
2673                 if ( Dc_arg_type & ARG_TRUE )   game_single_step = 1;   
2674                 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;       
2675                 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;        
2676
2677                 last_single_step = 0;   // Make so single step waits a frame before stepping
2678
2679         }       
2680         if ( Dc_help )  dc_printf( "Usage: single_step [bool]\nSets single_step to true or false.  If nothing passed, then toggles it.\n" );    
2681         if ( Dc_status )        dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );  
2682 }
2683
2684 DCF_BOOL(physics_pause, physics_paused)
2685 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2686 DCF_BOOL(ai_firing, Ai_firing_enabled )
2687
2688 // Create some simple aliases to these commands...
2689 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2690 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2691 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2692 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2693 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2694 #endif
2695
2696 //========================================================================================
2697 //========================================================================================
2698
2699
2700 void game_training_pause_do()
2701 {
2702         int key;
2703
2704         key = game_check_key();
2705         if (key > 0){
2706                 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2707         }
2708
2709         gr_flip();
2710 }
2711
2712
2713 void game_increase_skill_level()
2714 {
2715         Game_skill_level++;
2716         if (Game_skill_level >= NUM_SKILL_LEVELS){
2717                 Game_skill_level = 0;
2718         }
2719 }
2720
2721 int     Player_died_time;
2722
2723 int View_percent = 100;
2724
2725
2726 DCF(view, "Sets the percent of the 3d view to render.")
2727 {
2728         if ( Dc_command ) {
2729                 dc_get_arg(ARG_INT);
2730                 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2731                         View_percent = Dc_arg_int;
2732                 } else {
2733                         dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2734                         Dc_help = 1;
2735                 }
2736         }
2737
2738         if ( Dc_help ) {
2739                 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2740         }
2741         
2742         if ( Dc_status ) {
2743                 dc_printf("View is set to %d%%\n", View_percent );
2744         }
2745 }
2746
2747
2748 // Set the clip region for the 3d rendering window
2749 void game_set_view_clip()
2750 {
2751         if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2752                 // Set the clip region for the letterbox "dead view"
2753                 int yborder = gr_screen.max_h/4;
2754
2755                 //      Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2756                 // J.S. I've changed my ways!! See the new "no constants" code!!!
2757                 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 ); 
2758         } else {
2759                 // Set the clip region for normal view
2760                 if ( View_percent >= 100 )      {
2761                         gr_reset_clip();
2762                 } else {
2763                         int xborder, yborder;
2764
2765                         if ( View_percent < 5 ) {
2766                                 View_percent = 5;
2767                         }
2768
2769                         float fp = i2fl(View_percent)/100.0f;
2770                         int fi = fl2i(fl_sqrt(fp)*100.0f);
2771                         if ( fi > 100 ) fi=100;
2772                         
2773                         xborder = ( gr_screen.max_w*(100-fi) )/200;
2774                         yborder = ( gr_screen.max_h*(100-fi) )/200;
2775
2776                         gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2777                 }
2778         }
2779 }
2780
2781
2782 void show_debug_stuff()
2783 {
2784         int     i;
2785         int     laser_count = 0, missile_count = 0;
2786
2787         for (i=0; i<MAX_OBJECTS; i++) {
2788                 if (Objects[i].type == OBJ_WEAPON){
2789                         if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2790                                 laser_count++;
2791                         } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2792                                 missile_count++;
2793                         }
2794                 }
2795         }
2796
2797         nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2798 }
2799
2800 extern int Tool_enabled;
2801 int tst = 0;
2802 int tst_time = 0;
2803 int tst_big = 0;
2804 vector tst_pos;
2805 int tst_bitmap = -1;
2806 float tst_x, tst_y;
2807 float tst_offset, tst_offset_total;
2808 int tst_mode;
2809 int tst_stamp;
2810 void game_tst_frame_pre()
2811 {
2812         // start tst
2813         if(tst == 3){
2814                 tst = 0;
2815
2816                 // screen position
2817                 vertex v;
2818                 g3_rotate_vertex(&v, &tst_pos);
2819                 g3_project_vertex(&v);  
2820         
2821                 // offscreen
2822                 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2823                         return;
2824                 }       
2825
2826                 // big ship? always tst
2827                 if(tst_big){
2828                         // within 3000 meters
2829                         if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2830                                 tst = 2;                                
2831                         }
2832                 } else {                        
2833                         // within 300 meters
2834                         if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2835                                 tst = 2;                                
2836                         } 
2837                 }                       
2838         }
2839
2840 }
2841 void game_tst_frame()
2842 {
2843         int left = 0;
2844
2845         if(!Tool_enabled){
2846                 return;
2847         }
2848         
2849         // setup tst
2850         if(tst == 2){           
2851                 tst_time = time(NULL);
2852
2853                 // load the tst bitmap          
2854                 switch((int)frand_range(0.0f, 3.0)){
2855                 case 0:                 
2856                         tst_bitmap = bm_load("ig_jim");
2857                         left = 1;
2858                         mprintf(("TST 0\n"));
2859                         break;
2860
2861                 case 1:
2862                         tst_bitmap = bm_load("ig_kan");
2863                         left = 0;
2864                         mprintf(("TST 1\n"));
2865                         break;
2866
2867                 case 2:
2868                         tst_bitmap = bm_load("ig_jim");
2869                         left = 1;
2870                         mprintf(("TST 2\n"));
2871                         break;
2872                         
2873                 default:                        
2874                         tst_bitmap = bm_load("ig_kan");
2875                         left = 0;
2876                         mprintf(("TST 3\n"));
2877                         break;
2878                 }
2879
2880                 if(tst_bitmap < 0){
2881                         tst = 0;
2882                         return;
2883                 }               
2884
2885                 // get the tst bitmap dimensions
2886                 int w, h;
2887                 bm_get_info(tst_bitmap, &w, &h);
2888
2889                 // tst y
2890                 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2891
2892                 snd_play(&Snds[SND_VASUDAN_BUP]);
2893
2894                 // tst x and direction
2895                 tst_mode = 0;
2896                 if(left){
2897                         tst_x = (float)-w;
2898                         tst_offset_total = (float)w;
2899                         tst_offset = (float)w;
2900                 } else {
2901                         tst_x = (float)gr_screen.max_w;
2902                         tst_offset_total = (float)-w;
2903                         tst_offset = (float)w;
2904                 }
2905
2906                 tst = 1;
2907         }
2908
2909         // run tst
2910         if(tst == 1){
2911                 float diff = (tst_offset_total / 0.5f) * flFrametime;
2912
2913                 // move the bitmap
2914                 if(tst_mode == 0){
2915                         tst_x += diff;
2916                         
2917                         tst_offset -= fl_abs(diff);
2918                 } else if(tst_mode == 2){
2919                         tst_x -= diff;
2920                         
2921                         tst_offset -= fl_abs(diff);
2922                 }
2923
2924                 // draw the bitmap
2925                 gr_set_bitmap(tst_bitmap);
2926                 gr_bitmap((int)tst_x, (int)tst_y);
2927
2928                 if(tst_mode == 1){
2929                         if(timestamp_elapsed_safe(tst_stamp, 1100)){
2930                                 tst_mode = 2;
2931                         }
2932                 } else {
2933                         // if we passed the switch point
2934                         if(tst_offset <= 0.0f){
2935                                 // switch modes
2936                                 switch(tst_mode){
2937                                 case 0:
2938                                         tst_mode = 1;
2939                                         tst_stamp = timestamp(1000);
2940                                         tst_offset = fl_abs(tst_offset_total);
2941                                         break;                          
2942
2943                                 case 2:                         
2944                                         tst = 0;
2945                                         return;
2946                                 }
2947                         }                               
2948                 }
2949         }
2950 }
2951 void game_tst_mark(object *objp, ship *shipp)
2952 {
2953         ship_info *sip; 
2954
2955         if(!Tool_enabled){
2956                 return;
2957         }
2958
2959         // bogus
2960         if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
2961                 return;
2962         }
2963         sip = &Ship_info[shipp->ship_info_index];
2964
2965         // already tst
2966         if(tst){
2967                 return;
2968         }
2969
2970         tst_pos = objp->pos;
2971         if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
2972                 tst_big = 1;
2973         }
2974         tst = 3;
2975 }
2976
2977 extern void render_shields();
2978
2979 void player_repair_frame(float frametime)
2980 {
2981         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2982                 int idx;
2983                 for(idx=0;idx<MAX_PLAYERS;idx++){
2984                         net_player *np;
2985
2986                         np = &Net_players[idx];
2987
2988                         if(MULTI_CONNECTED(Net_players[idx]) && (Net_player != NULL) && (Net_player->player_id != Net_players[idx].player_id) && (Net_players[idx].player != NULL) && (Net_players[idx].player->objnum >= 0) && (Net_players[idx].player->objnum < MAX_OBJECTS)){
2989
2990                                 // don't rearm/repair if the player is dead or dying/departing
2991                                 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
2992                                         ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
2993                                 }
2994                         }
2995                 }
2996         }       
2997         if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
2998                 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
2999         }
3000 }
3001
3002
3003 #ifndef NDEBUG
3004 #define NUM_FRAMES_TEST         300
3005 #define NUM_MIXED_SOUNDS        16
3006 void do_timing_test(float flFrametime)
3007 {
3008         static int framecount = 0;
3009         static int test_running = 0;
3010         static float test_time = 0.0f;
3011
3012         static int snds[NUM_MIXED_SOUNDS];
3013         int i;
3014
3015         if ( test_running ) {
3016                 framecount++;
3017                 test_time += flFrametime;
3018                 if ( framecount >= NUM_FRAMES_TEST ) {
3019                         test_running = 0;
3020                         nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3021                         for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3022                                 snd_stop(snds[i]);
3023                 }
3024         }
3025
3026         if ( Test_begin == 1 ) {
3027                 framecount = 0;
3028                 test_running = 1;
3029                 test_time = 0.0f;
3030                 Test_begin = 0;
3031
3032                 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3033                         snds[i] = -1;
3034
3035                 // start looping digital sounds
3036                 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3037                         snds[i] = snd_play_looping( &Snds[i], 0.0f, -1, -1);
3038         }
3039         
3040
3041 }
3042 #endif
3043
3044 DCF(dcf_fov, "Change the field of view")
3045 {
3046         if ( Dc_command )       {
3047                 dc_get_arg(ARG_FLOAT|ARG_NONE);
3048                 if ( Dc_arg_type & ARG_NONE )   {
3049                         Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3050                         dc_printf( "Zoom factor reset\n" );
3051                 }
3052                 if ( Dc_arg_type & ARG_FLOAT )  {
3053                         if (Dc_arg_float < 0.25f) {
3054                                 Viewer_zoom = 0.25f;
3055                                 dc_printf("Zoom factor pinned at 0.25.\n");
3056                         } else if (Dc_arg_float > 1.25f) {
3057                                 Viewer_zoom = 1.25f;
3058                                 dc_printf("Zoom factor pinned at 1.25.\n");
3059                         } else {
3060                                 Viewer_zoom = Dc_arg_float;
3061                         }
3062                 }
3063         }
3064
3065         if ( Dc_help )  
3066                 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3067
3068         if ( Dc_status )                                
3069                 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3070 }
3071
3072
3073 DCF(framerate_cap, "Sets the framerate cap")
3074 {
3075         if ( Dc_command ) {
3076                 dc_get_arg(ARG_INT);
3077                 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3078                         Framerate_cap = Dc_arg_int;
3079                 } else {
3080                         dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3081                         Dc_help = 1;
3082                 }
3083         }
3084
3085         if ( Dc_help ) {
3086                 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3087                 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3088                 dc_printf("[n] must be from 1 to 120.\n");
3089         }
3090         
3091         if ( Dc_status ) {
3092                 if ( Framerate_cap )
3093                         dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3094                 else
3095                         dc_printf("There is no framerate cap currently active.\n");
3096         }
3097 }
3098
3099 #define MIN_DIST_TO_DEAD_CAMERA         50.0f
3100 int Show_viewing_from_self = 0;
3101
3102 void say_view_target()
3103 {
3104         object  *view_target;
3105
3106         if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3107                 view_target = &Objects[Player_ai->target_objnum];
3108         else
3109                 view_target = Player_obj;
3110
3111         if (Game_mode & GM_DEAD) {
3112                 if (Player_ai->target_objnum != -1)
3113                         view_target = &Objects[Player_ai->target_objnum];
3114         }
3115
3116         if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3117                 if (view_target != Player_obj){
3118
3119                         char *view_target_name = NULL;
3120                         switch(Objects[Player_ai->target_objnum].type) {
3121                         case OBJ_SHIP:
3122                                 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3123                                 break;
3124                         case OBJ_WEAPON:
3125                                 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3126                                 Viewer_mode &= ~VM_OTHER_SHIP;
3127                                 break;
3128                         case OBJ_JUMP_NODE: {
3129                                 char    jump_node_name[128];
3130                                 strcpy(jump_node_name, XSTR( "jump node", 184));
3131                                 view_target_name = jump_node_name;
3132                                 Viewer_mode &= ~VM_OTHER_SHIP;
3133                                 break;
3134                                 }
3135
3136                         default:
3137                                 Int3();
3138                                 break;
3139                         }
3140
3141                         if ( view_target_name ) {
3142                                 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3143                                 Show_viewing_from_self = 1;
3144                         }
3145                 } else {
3146                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3147                                 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3148                                 Show_viewing_from_self = 1;
3149                         } else {
3150                                 if (Show_viewing_from_self)
3151                                         HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3152                         }
3153                 }
3154         }
3155
3156         Last_view_target = view_target;
3157 }
3158
3159
3160 float Game_hit_x = 0.0f;
3161 float Game_hit_y = 0.0f;
3162
3163 // Reset at the beginning of each frame
3164 void game_whack_reset()
3165 {
3166         Game_hit_x = 0.0f;
3167         Game_hit_y = 0.0f;
3168 }
3169
3170 // Apply a 2d whack to the player
3171 void game_whack_apply( float x, float y )
3172 {
3173         // Do some force feedback
3174         joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3175
3176         // Move the eye 
3177         Game_hit_x += x;
3178         Game_hit_y += y;
3179
3180 //      mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3181 }
3182
3183 // call to apply a "shudder"
3184 void game_shudder_apply(int time, float intensity)
3185 {
3186         Game_shudder_time = timestamp(time);
3187         Game_shudder_total = time;
3188         Game_shudder_intensity = intensity;
3189 }
3190
3191 #define FF_SCALE        10000
3192 void apply_hud_shake(matrix *eye_orient)
3193 {
3194         if (Viewer_obj == Player_obj) {
3195                 physics_info    *pi = &Player_obj->phys_info;
3196
3197                 angles  tangles;
3198
3199                 tangles.p = 0.0f;
3200                 tangles.h = 0.0f;
3201                 tangles.b = 0.0f;
3202
3203                 //      Make eye shake due to afterburner
3204                 if ( !timestamp_elapsed(pi->afterburner_decay) ) {                      
3205                         int             dtime;
3206
3207                         dtime = timestamp_until(pi->afterburner_decay);
3208                         
3209                         int r1 = myrand();
3210                         int r2 = myrand();
3211                         tangles.p += 0.07f * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3212                         tangles.h += 0.07f * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3213                 }
3214
3215                 // Make eye shake due to engine wash
3216                 extern int Wash_on;
3217                 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3218                         int r1 = myrand();
3219                         int r2 = myrand();
3220                         tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-RAND_MAX/2)/RAND_MAX;
3221                         tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-RAND_MAX/2)/RAND_MAX;
3222
3223                         // get the   intensity
3224                         float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3225
3226                         // vector rand_vec
3227                         vector rand_vec;
3228                         vm_vec_rand_vec_quick(&rand_vec);
3229
3230                         // play the effect
3231                         joy_ff_play_dir_effect(intensity*rand_vec.x, intensity*rand_vec.y);
3232                 }
3233
3234         
3235                 // make hud shake due to shuddering
3236                 if(Game_shudder_time != -1){
3237                         // if the timestamp has elapsed
3238                         if(timestamp_elapsed(Game_shudder_time)){
3239                                 Game_shudder_time = -1;
3240                         } 
3241                         // otherwise apply some shudder
3242                         else {
3243                                 int dtime;
3244
3245                                 dtime = timestamp_until(Game_shudder_time);
3246                         
3247                                 int r1 = myrand();
3248                                 int r2 = myrand();
3249                                 tangles.p += (Game_shudder_intensity / 200.0f) * (float) (r1-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3250                                 tangles.h += (Game_shudder_intensity / 200.0f) * (float) (r2-RAND_MAX/2)/RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/(float)Game_shudder_total));
3251                         }
3252                 }
3253
3254                 matrix  tm, tm2;
3255                 vm_angles_2_matrix(&tm, &tangles);
3256                 Assert(vm_vec_mag(&tm.fvec) > 0.0f);
3257                 Assert(vm_vec_mag(&tm.rvec) > 0.0f);
3258                 Assert(vm_vec_mag(&tm.uvec) > 0.0f);
3259                 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3260                 *eye_orient = tm2;
3261         }
3262 }
3263
3264 extern void compute_slew_matrix(matrix *orient, angles *a);     // TODO: move code to proper place and extern in header file
3265
3266 //      Player's velocity just before he blew up.  Used to keep camera target moving.
3267 vector  Dead_player_last_vel = {1.0f, 1.0f, 1.0f};
3268
3269 //      Set eye_pos and eye_orient based on view mode.
3270 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3271 {
3272         vector  eye_dir;
3273
3274         static int last_Viewer_mode = 0;
3275         static int last_Game_mode = 0;
3276         static int last_Viewer_objnum = -1;
3277
3278         // This code is supposed to detect camera "cuts"... like going between
3279         // different views.
3280
3281         // determine if we need to regenerate the nebula
3282         if(     (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) ||                                                   // internal to external 
3283                         ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) ||                                                   // external to internal
3284                         (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) ||                                                 // non dead-view to dead-view
3285                         ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) ||                                                 // dead-view to non dead-view
3286                         (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) ||                                               // non warp-chase to warp-chase
3287                         ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) ||                                               // warp-chase to non warp-chase
3288                         (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) ||                                               // non other-ship to other-ship
3289                         ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) ||                                               // other-ship to non-other ship
3290                         ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum))             // other ship mode, but targets changes
3291                         ) {
3292
3293                 // regenerate the nebula
3294                 neb2_eye_changed();
3295         }               
3296
3297         if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) )       {
3298                 //mprintf(( "************** Camera cut! ************\n" ));
3299                 last_Viewer_mode = Viewer_mode;
3300                 last_Game_mode = Game_mode;
3301
3302                 // Camera moved.  Tell stars & debris to not do blurring.
3303                 stars_camera_cut();             
3304         }
3305
3306         say_view_target();
3307
3308         if ( Viewer_mode & VM_PADLOCK_ANY ) {
3309                 player_display_packlock_view();
3310         }
3311         
3312         game_set_view_clip();
3313
3314         if (Game_mode & GM_DEAD) {
3315                 vector  vec_to_deader, view_pos;
3316                 float           dist;
3317
3318                 Viewer_mode |= VM_DEAD_VIEW;
3319
3320                 if (Player_ai->target_objnum != -1) {
3321                         int view_from_player = 1;
3322
3323                         if (Viewer_mode & VM_OTHER_SHIP) {
3324                                 //      View from target.
3325                                 Viewer_obj = &Objects[Player_ai->target_objnum];
3326
3327                                 last_Viewer_objnum = Player_ai->target_objnum;
3328
3329                                 if ( Viewer_obj->type == OBJ_SHIP ) {
3330                                         ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3331                                         view_from_player = 0;
3332                                 }
3333                         } else {
3334                                 last_Viewer_objnum = -1;
3335                         }
3336
3337                         if ( view_from_player ) {
3338                                 //      View target from player ship.
3339                                 Viewer_obj = NULL;
3340                                 *eye_pos = Player_obj->pos;
3341                                 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3342                                 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3343                         }
3344                 } else {
3345                         dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3346                         
3347                         if (dist < MIN_DIST_TO_DEAD_CAMERA)
3348                                 dist += flFrametime * 16.0f;
3349
3350                         vm_vec_scale(&vec_to_deader, -dist);
3351                         vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3352                         
3353                         view_pos = Player_obj->pos;
3354
3355                         if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3356                                 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3357                                 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3358                                 Dead_player_last_vel = Player_obj->phys_info.vel;
3359                                 //nprintf(("AI", "Player death roll vel = %7.3f %7.3f %7.3f\n", Player_obj->phys_info.vel.x, Player_obj->phys_info.vel.y, Player_obj->phys_info.vel.z));
3360                         } else if (Player_ai->target_objnum != -1) {
3361                                 view_pos = Objects[Player_ai->target_objnum].pos;
3362                         } else {
3363                                 //      Make camera follow explosion, but gradually slow down.
3364                                 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3365                                 view_pos = Player_obj->pos;
3366                                 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3367                                 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3368                         }
3369
3370                         *eye_pos = Dead_camera_pos;
3371
3372                         vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3373
3374                         vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3375                         Viewer_obj = NULL;
3376                 }
3377         } 
3378
3379         // if supernova shockwave
3380         if(supernova_camera_cut()){
3381                 // no viewer obj
3382                 Viewer_obj = NULL;
3383
3384                 // call it dead view
3385                 Viewer_mode |= VM_DEAD_VIEW;
3386
3387                 // set eye pos and orient
3388                 supernova_set_view(eye_pos, eye_orient);
3389         } else {        
3390                 //      If already blown up, these other modes can override.
3391                 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3392                         Viewer_mode &= ~VM_DEAD_VIEW;
3393
3394                         Viewer_obj = Player_obj;
3395  
3396                         if (Viewer_mode & VM_OTHER_SHIP) {
3397                                 if (Player_ai->target_objnum != -1){
3398                                         Viewer_obj = &Objects[Player_ai->target_objnum];
3399                                         last_Viewer_objnum = Player_ai->target_objnum;
3400                                 } else {
3401                                         Viewer_mode &= ~VM_OTHER_SHIP;
3402                                         last_Viewer_objnum = -1;
3403                                 }
3404                         } else {
3405                                 last_Viewer_objnum = -1;
3406                         }
3407
3408                         if (Viewer_mode & VM_EXTERNAL) {
3409                                 matrix  tm, tm2;
3410
3411                                 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3412                                 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3413
3414                                 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3415
3416                                 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3417                                 vm_vec_normalize(&eye_dir);
3418                                 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.uvec, NULL);
3419                                 Viewer_obj = NULL;
3420
3421                                 //      Modify the orientation based on head orientation.
3422                                 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3423
3424                         } else if ( Viewer_mode & VM_CHASE ) {
3425                                 vector  move_dir;
3426
3427                                 if ( Viewer_obj->phys_info.speed < 0.1 )
3428                                         move_dir = Viewer_obj->orient.fvec;
3429                                 else {
3430                                         move_dir = Viewer_obj->phys_info.vel;
3431                                         vm_vec_normalize(&move_dir);
3432                                 }
3433
3434                                 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3435                                 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.uvec, 0.75f * Viewer_obj->radius);
3436                                 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3437                                 vm_vec_normalize(&eye_dir);
3438
3439                                 // JAS: I added the following code because if you slew up using
3440                                 // Descent-style physics, eye_dir and Viewer_obj->orient.uvec are
3441                                 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3442                                 // call because the up and the forward vector are the same.   I fixed
3443                                 // it by adding in a fraction of the right vector all the time to the
3444                                 // up vector.
3445                                 vector tmp_up = Viewer_obj->orient.uvec;
3446                                 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.rvec, 0.00001f );
3447
3448                                 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3449                                 Viewer_obj = NULL;
3450
3451                                 //      Modify the orientation based on head orientation.
3452                                 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3453                         } else if ( Viewer_mode & VM_WARP_CHASE ) {
3454                                         *eye_pos = Camera_pos;
3455
3456                                         ship * shipp = &Ships[Player_obj->instance];
3457
3458                                         vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3459                                         vm_vec_normalize(&eye_dir);
3460                                         vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.uvec, NULL);
3461                                         Viewer_obj = NULL;
3462                         } else {
3463                                 // get an eye position based upon the correct type of object
3464                                 switch(Viewer_obj->type){
3465                                 case OBJ_SHIP:
3466                                         // make a call to get the eye point for the player object
3467                                         ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3468                                         break;
3469                                 case OBJ_OBSERVER:
3470                                         // make a call to get the eye point for the player object
3471                                         observer_get_eye( eye_pos, eye_orient, Viewer_obj );                            
3472                                         break;
3473                                 default :
3474                                         Int3();
3475                                 }
3476
3477                                 #ifdef JOHNS_DEBUG_CODE
3478                                 john_debug_stuff(&eye_pos, &eye_orient);
3479                                 #endif
3480                         }
3481                 }
3482         }
3483
3484         apply_hud_shake(eye_orient);
3485
3486         // setup neb2 rendering
3487         neb2_render_setup(eye_pos, eye_orient);
3488 }
3489
3490 #ifndef NDEBUG
3491 extern void ai_debug_render_stuff();
3492 #endif
3493
3494 int Game_subspace_effect = 0;
3495 DCF_BOOL( subspace, Game_subspace_effect );
3496
3497 // Does everything needed to render a frame
3498 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3499 {
3500         int dont_offset;
3501
3502         g3_start_frame(game_zbuffer);
3503         g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3504
3505         // maybe offset the HUD (jitter stuff)
3506         dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3507         HUD_set_offsets(Viewer_obj, !dont_offset);
3508         
3509         // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array.  Have to
3510         // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3511         // must be done before ships are rendered
3512         if ( MULTIPLAYER_CLIENT ) {
3513                 shield_point_multi_setup();
3514         }
3515
3516         if ( Game_subspace_effect )     {
3517                 stars_draw(0,0,0,1);
3518         } else {
3519                 stars_draw(1,1,1,0);
3520         }
3521
3522         obj_render_all(obj_render);
3523         beam_render_all();                                              // render all beam weapons
3524         particle_render_all();                                  // render particles after everything else.
3525         trail_render_all();                                             // render missilie trails after everything else.        
3526         mflash_render_all();                                            // render all muzzle flashes    
3527
3528         //      Why do we not show the shield effect in these modes?  Seems ok.
3529         //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3530         render_shields();
3531         //}
3532
3533         // render nebula lightning
3534         nebl_render_all();
3535
3536         // render local player nebula
3537         neb2_render_player();   
3538
3539 #ifndef NDEBUG
3540         ai_debug_render_stuff();
3541 #endif
3542
3543 #ifndef RELEASE_REAL
3544         // game_framerate_check();
3545 #endif
3546
3547 #ifndef NDEBUG
3548         extern void snd_spew_debug_info();
3549         snd_spew_debug_info();
3550 #endif
3551
3552         //================ END OF 3D RENDERING STUFF ====================
3553
3554         hud_show_radar();
3555
3556         if( (Game_detail_flags & DETAIL_FLAG_HUD) && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) ) ) {
3557                 hud_maybe_clear_head_area();
3558                 anim_render_all(0, flFrametime);
3559         }
3560
3561         extern int Multi_display_netinfo;
3562         if(Multi_display_netinfo){
3563                 extern void multi_display_netinfo();
3564                 multi_display_netinfo();
3565         }       
3566
3567         game_tst_frame_pre();
3568
3569 #ifndef NDEBUG
3570         do_timing_test(flFrametime);
3571 #endif
3572
3573 #ifndef NDEBUG
3574         extern int OO_update_index;     
3575         multi_rate_display(OO_update_index, 375, 0);
3576 #endif
3577
3578 #ifndef NDEBUG
3579         // test
3580         extern void oo_display();
3581         oo_display();                   
3582 #endif
3583         
3584         g3_end_frame();
3585 }
3586
3587 //#define JOHNS_DEBUG_CODE      1
3588
3589 #ifdef JOHNS_DEBUG_CODE
3590 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3591 {
3592         //if ( keyd_pressed[KEY_LSHIFT] )               
3593         {
3594                 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3595                 if ( tsys )     {
3596                         model_subsystem *turret = tsys->system_info;
3597
3598                         if (turret->type == SUBSYSTEM_TURRET )  {
3599                                 vector fvec, uvec;
3600                                 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3601
3602                                 ship_model_start(tobj);
3603
3604                                 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3605                                 model_find_world_dir(&fvec, &turret->turret_matrix.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3606                                 model_find_world_dir(&uvec, &turret->turret_matrix.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3607                                 
3608                                 vm_vector_2_matrix( eye_orient, &fvec, &uvec, NULL );
3609
3610                                 ship_model_stop(tobj);
3611
3612                                 Viewer_obj = NULL;
3613                         }
3614                 }
3615
3616         }
3617 }
3618 #endif
3619
3620 // following function for dumping frames for purposes of building trailers.
3621 #ifndef NDEBUG
3622
3623 // function to toggle state of dumping every frame into PCX when playing the game
3624 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3625 {
3626         if ( Dc_command )       {
3627
3628                 if ( Debug_dump_frames == 0 )   {
3629                         // Turn it on
3630                         Debug_dump_frames = 15;
3631                         Debug_dump_trigger = 0;
3632                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3633                         dc_printf( "Frame dumping at 15 hz is now ON\n" );
3634                 } else {
3635                         // Turn it off
3636                         Debug_dump_frames = 0;
3637                         Debug_dump_trigger = 0;
3638                         gr_dump_frame_stop();
3639                         dc_printf( "Frame dumping is now OFF\n" );
3640                 }
3641                 
3642         }
3643 }
3644
3645 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3646 {
3647         if ( Dc_command )       {
3648
3649                 if ( Debug_dump_frames == 0 )   {
3650                         // Turn it on
3651                         Debug_dump_frames = 15;
3652                         Debug_dump_trigger = 1;
3653                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3654                         dc_printf( "Frame dumping at 15 hz is now ON\n" );
3655                 } else {
3656                         // Turn it off
3657                         Debug_dump_frames = 0;
3658                         Debug_dump_trigger = 0;
3659                         gr_dump_frame_stop();
3660                         dc_printf( "Frame dumping is now OFF\n" );
3661                 }
3662                 
3663         }
3664 }
3665
3666 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3667 {
3668         if ( Dc_command )       {
3669
3670                 if ( Debug_dump_frames == 0 )   {
3671                         // Turn it on
3672                         Debug_dump_frames = 30;
3673                         Debug_dump_trigger = 0;
3674                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3675                         dc_printf( "Frame dumping at 30 hz is now ON\n" );
3676                 } else {
3677                         // Turn it off
3678                         Debug_dump_frames = 0;
3679                         Debug_dump_trigger = 0;
3680                         gr_dump_frame_stop();
3681                         dc_printf( "Frame dumping is now OFF\n" );
3682                 }
3683                 
3684         }
3685 }
3686
3687 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3688 {
3689         if ( Dc_command )       {
3690
3691                 if ( Debug_dump_frames == 0 )   {
3692                         // Turn it on
3693                         Debug_dump_frames = 30;
3694                         Debug_dump_trigger = 1;
3695                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3696                         dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3697                 } else {
3698                         // Turn it off
3699                         Debug_dump_frames = 0;
3700                         Debug_dump_trigger = 0;
3701                         gr_dump_frame_stop();
3702                         dc_printf( "Triggered frame dumping is now OFF\n" );
3703                 }
3704                 
3705         }
3706 }
3707
3708 void game_maybe_dump_frame()
3709 {
3710         if ( !Debug_dump_frames ){
3711                 return;
3712         }
3713
3714         if( Debug_dump_trigger && !keyd_pressed[KEY_Q] ){
3715                 return;
3716         }
3717
3718         game_stop_time();
3719
3720         gr_dump_frame();
3721         Debug_dump_frame_num++;
3722
3723         game_start_time();
3724 }
3725 #endif
3726
3727 extern int Player_dead_state;
3728
3729 //      Flip the page and time how long it took.
3730 void game_flip_page_and_time_it()
3731 {       
3732         fix t1, t2,d;
3733         int t;
3734         t1 = timer_get_fixed_seconds();
3735         gr_flip();
3736         t2 = timer_get_fixed_seconds();
3737         d = t2 - t1;
3738         t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3739         sprintf( transfer_text, NOX("%d MB/s"), fixmuldiv(t,65,d) );
3740 }
3741
3742 void game_simulation_frame()
3743 {
3744         // blow ships up in multiplayer dogfight
3745         if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT) && (f2fl(Missiontime) >= 2.0f) && !dogfight_blown){
3746                 // blow up all non-player ships
3747                 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3748                 ship *shipp;
3749                 ship_info *sip;
3750                 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3751                         // bogus
3752                         if((moveup->objnum < 0) || (moveup->objnum >= MAX_OBJECTS) || (Objects[moveup->objnum].type != OBJ_SHIP) || (Objects[moveup->objnum].instance < 0) || (Objects[moveup->objnum].instance >= MAX_SHIPS) || (Ships[Objects[moveup->objnum].instance].ship_info_index < 0) || (Ships[Objects[moveup->objnum].instance].ship_info_index >= Num_ship_types)){
3753                                 moveup = GET_NEXT(moveup);
3754                                 continue;
3755                         }
3756                         shipp = &Ships[Objects[moveup->objnum].instance];
3757                         sip = &Ship_info[shipp->ship_info_index];
3758
3759                         // only blow up small ships                     
3760                         if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){                                                      
3761                                 // function to simply explode a ship where it is currently at
3762                                 ship_self_destruct( &Objects[moveup->objnum] );                                 
3763                         }
3764
3765                         moveup = GET_NEXT(moveup);
3766                 }
3767
3768                 dogfight_blown = 1;
3769         }
3770
3771         // process AWACS stuff - do this first thing
3772         awacs_process();
3773
3774         // single player, set Player hits_this_frame to 0
3775         if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3776                 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE  / (0.001f * BURST_DURATION));
3777                 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3778         }
3779
3780         // supernova
3781         supernova_process();
3782         if(supernova_active() >= 5){
3783                 return;
3784         }
3785
3786         // fire targeting lasers now so that 
3787         // 1 - created this frame
3788         // 2 - collide this frame
3789         // 3 - render this frame
3790         // 4 - ignored and deleted next frame
3791         // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3792         // frame
3793         ship_process_targeting_lasers();        
3794
3795         // do this here so that it works for multiplayer
3796         if ( Viewer_obj ) {
3797                 // get viewer direction
3798                 int viewer_direction = PHYSICS_VIEWER_REAR;
3799
3800                 if(Viewer_mode == 0){
3801                         viewer_direction = PHYSICS_VIEWER_FRONT;
3802                 }
3803                 if(Viewer_mode & VM_PADLOCK_UP){
3804                         viewer_direction = PHYSICS_VIEWER_UP;
3805                 }
3806                 else if(Viewer_mode & VM_PADLOCK_REAR){
3807                         viewer_direction = PHYSICS_VIEWER_REAR;
3808                 } 
3809                 else if(Viewer_mode & VM_PADLOCK_LEFT){
3810                         viewer_direction = PHYSICS_VIEWER_LEFT;
3811                 } 
3812                 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3813                         viewer_direction = PHYSICS_VIEWER_RIGHT;
3814                 }
3815
3816                 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3817         } else {
3818                 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3819         }
3820
3821 #define VM_PADLOCK_UP                                   (1 << 7)
3822 #define VM_PADLOCK_REAR                         (1 << 8)
3823 #define VM_PADLOCK_LEFT                         (1 << 9)
3824 #define VM_PADLOCK_RIGHT                                (1 << 10)
3825                 
3826         // evaluate mission departures and arrivals before we process all objects.
3827         if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3828
3829                 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3830                 // ships/wing packets.
3831                 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3832                         mission_parse_eval_stuff();
3833                 }
3834
3835                 // if we're an observer, move ourselves seperately from the standard physics
3836                 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3837                         obj_observer_move(flFrametime);
3838                 }
3839                 
3840                 // move all the objects now
3841                 obj_move_all(flFrametime);
3842
3843                 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3844                 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3845                 //      ship_check_cargo_all();
3846                 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3847                         mission_eval_goals();
3848                 }
3849         }
3850
3851         // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3852         if(!(Game_mode & GM_DEMO_PLAYBACK)){
3853                 training_check_objectives();
3854         }
3855         
3856         // do all interpolation now
3857         if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3858                 // client side processing of warping in effect stages
3859                 multi_do_client_warp(flFrametime);     
3860         
3861                 // client side movement of an observer
3862                 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3863                         obj_observer_move(flFrametime);   
3864                 }
3865
3866                 // move all objects - does interpolation now as well
3867                 obj_move_all(flFrametime);
3868         }
3869
3870         // only process the message queue when the player is "in" the game
3871         if ( !Pre_player_entry ){
3872                 message_queue_process();                                // process any messages send to the player
3873         }
3874
3875         if(!(Game_mode & GM_DEMO_PLAYBACK)){
3876                 message_maybe_distort();                                // maybe distort incoming message if comms damaged
3877                 player_repair_frame(flFrametime);       //      AI objects get repaired in ai_process, called from move code...deal with player.
3878                 player_process_pending_praise();                // maybe send off a delayed praise message to the player
3879                 player_maybe_play_all_alone_msg();      // mabye tell the player he is all alone        
3880         }
3881
3882         if(!(Game_mode & GM_STANDALONE_SERVER)){                
3883                 // process some stuff every frame (before frame is rendered)
3884                 emp_process_local();
3885
3886                 hud_update_frame();                                             // update hud systems
3887
3888                 if (!physics_paused)    {
3889                         // Move particle system
3890                         particle_move_all(flFrametime); 
3891
3892                         // Move missile trails
3893                         trail_move_all(flFrametime);            
3894
3895                         // process muzzle flashes
3896                         mflash_process_all();
3897
3898                         // Flash the gun flashes
3899                         shipfx_flash_do_frame(flFrametime);                     
3900
3901                         shockwave_move_all(flFrametime);        // update all the shockwaves
3902                 }
3903
3904                 // subspace missile strikes
3905                 ssm_process();
3906
3907                 obj_snd_do_frame();                                             // update the object-linked persistant sounds
3908                 game_maybe_update_sound_environment();
3909                 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3910
3911 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3912 #ifndef NDEBUG
3913                 if ( Game_subspace_effect ) {
3914                         game_start_subspace_ambient_sound();
3915                 }
3916 #endif
3917         }               
3918 }
3919
3920 // Maybe render and process the dead-popup
3921 void game_maybe_do_dead_popup(float frametime)
3922 {
3923         if ( popupdead_is_active() ) {
3924                 int leave_popup=1;
3925                 int choice = popupdead_do_frame(frametime);
3926
3927                 if ( Game_mode & GM_NORMAL ) {
3928                         switch(choice) {
3929                         case 0:
3930                                 // CD CHECK                             
3931                                 if(game_do_cd_mission_check(Game_current_mission_filename)){
3932                                         gameseq_post_event(GS_EVENT_ENTER_GAME);
3933                                 } else {
3934                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
3935                                 }                                       
3936                                 break;
3937
3938                         case 1:
3939                                 gameseq_post_event(GS_EVENT_END_GAME);
3940                                 break;
3941
3942                         case 2:
3943                                 // CD CHECK
3944                                 if(game_do_cd_mission_check(Game_current_mission_filename)){
3945                                         gameseq_post_event(GS_EVENT_START_GAME);                                        
3946                                 } else {
3947                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
3948                                 }                                       
3949                                 break;
3950
3951                         // this should only happen during a red alert mission
3952                         case 3:                         
3953                                 // bogus?
3954                                 Assert(The_mission.red_alert);
3955                                 if(!The_mission.red_alert){
3956                                         // CD CHECK
3957                                         if(game_do_cd_mission_check(Game_current_mission_filename)){
3958                                                 gameseq_post_event(GS_EVENT_START_GAME);
3959                                         } else {
3960                                                 gameseq_post_event(GS_EVENT_MAIN_MENU);
3961                                         }
3962                                         break;
3963                                 }
3964                                 
3965                                 // choose the previous mission
3966                                 mission_campaign_previous_mission();
3967                                 // CD CHECK
3968                                 if(game_do_cd_mission_check(Game_current_mission_filename)){
3969                                         gameseq_post_event(GS_EVENT_START_GAME);
3970                                 } else {
3971                                         gameseq_post_event(GS_EVENT_MAIN_MENU);
3972                                 }                               
3973                                 break;
3974
3975                         default:
3976                                 leave_popup=0;
3977                                 break;
3978                         }
3979                 } else {
3980                         switch( choice ) {
3981
3982                         case POPUPDEAD_DO_MAIN_HALL:
3983                                 multi_quit_game(PROMPT_NONE,-1);
3984                                 break;
3985
3986                         case POPUPDEAD_DO_RESPAWN:                              
3987                                 multi_respawn_normal();
3988                                 event_music_player_respawn();
3989                                 break;
3990
3991                         case POPUPDEAD_DO_OBSERVER:
3992                                 multi_respawn_observer();
3993                                 event_music_player_respawn_as_observer();
3994                                 break;
3995
3996                         default:
3997                                 leave_popup = 0;
3998                                 break;
3999                         }
4000                 }
4001
4002                 if ( leave_popup ) {
4003                         popupdead_close();
4004                 }
4005         }
4006 }
4007
4008 // returns true if player is actually in a game_play stats
4009 int game_actually_playing()
4010 {
4011         int state;
4012
4013         state = gameseq_get_state();
4014         if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4015                 return 0;
4016         else
4017                 return 1;
4018 }
4019
4020 // Draw the 2D HUD gauges
4021 void game_render_hud_2d()
4022 {
4023         if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4024                 return;
4025         }
4026         
4027         HUD_render_2d(flFrametime);
4028         gr_reset_clip();
4029 }
4030
4031 // Draw the 3D-dependant HUD gauges
4032 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4033 {
4034         g3_start_frame(0);              // 0 = turn zbuffering off
4035         g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4036
4037         if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4038                 HUD_render_3d(flFrametime);
4039         }
4040
4041         // Do the sunspot
4042         game_sunspot_process(flFrametime);
4043
4044         // Diminish the palette effect
4045         game_flash_diminish(flFrametime);
4046
4047         g3_end_frame();
4048 }
4049
4050
4051 void game_frame()
4052 {
4053         int actually_playing;
4054         fix total_time1, total_time2;
4055         fix render2_time1=0, render2_time2=0;
4056         fix render3_time1=0, render3_time2=0;
4057         fix flip_time1=0, flip_time2=0;
4058         fix clear_time1=0, clear_time2=0;
4059         
4060         vector eye_pos;
4061         matrix eye_orient;
4062
4063 #ifndef NDEBUG
4064         if (Framerate_delay) {
4065                 int     start_time = timer_get_milliseconds();
4066                 while (timer_get_milliseconds() < start_time + Framerate_delay)
4067                         ;
4068         }
4069 #endif
4070
4071 #ifdef DEMO_SYSTEM
4072         demo_do_frame_start();
4073         if(Demo_error){
4074                 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4075                 demo_close();
4076         }
4077 #endif
4078         
4079         // start timing frame
4080         timing_frame_start();
4081
4082         total_time1 = timer_get_fixed_seconds();
4083
4084         // var to hold which state we are in
4085         actually_playing = game_actually_playing();
4086         
4087         if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4088                 if (!(Game_mode & GM_STANDALONE_SERVER)){
4089                         Assert( OBJ_INDEX(Player_obj) >= 0 );
4090                 }
4091         }
4092
4093         if (Missiontime > Entry_delay_time){
4094                 Pre_player_entry = 0;
4095         } else {
4096                 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4097         }
4098
4099         //      Note: These are done even before the player enters, else buffers can overflow.
4100         if (! (Game_mode & GM_STANDALONE_SERVER)){
4101                 radar_frame_init();
4102         }
4103
4104         shield_frame_init();
4105
4106         if ( Player->control_mode != PCM_NORMAL )
4107                 camera_move();
4108
4109         if ( !Pre_player_entry && actually_playing ) {                          
4110                 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4111
4112                         if( (!popup_running_state()) && (!popupdead_is_active()) ){
4113                                 game_process_keys();
4114
4115                                 // don't read flying controls if we're playing a demo back
4116                                 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4117                                         read_player_controls( Player_obj, flFrametime);
4118                                 }
4119                         }
4120                         
4121                         // if we're not the master, we may have to send the server-critical ship status button_info bits
4122                         if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4123                                 multi_maybe_send_ship_status();
4124                         }
4125                 }
4126         }
4127
4128         // Reset the whack stuff
4129         game_whack_reset();
4130
4131         // These two lines must be outside of Pre_player_entry code,
4132         // otherwise too many lights are added.
4133         light_reset();
4134
4135         if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4136                 return;
4137         }
4138         
4139         game_simulation_frame();        
4140
4141         // if not actually in a game play state, then return.  This condition could only be true in 
4142         // a multiplayer game.
4143         if ( !actually_playing ) {
4144                 Assert( Game_mode & GM_MULTIPLAYER );
4145                 return;
4146         }
4147
4148         if (!Pre_player_entry) {
4149                 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4150                         clear_time1 = timer_get_fixed_seconds();
4151                         // clear the screen to black
4152                         gr_reset_clip();
4153                         if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4154                                 gr_clear();
4155                         }
4156
4157                         clear_time2 = timer_get_fixed_seconds();
4158                         render3_time1 = timer_get_fixed_seconds();
4159                         game_render_frame_setup(&eye_pos, &eye_orient);
4160                         game_render_frame( &eye_pos, &eye_orient );
4161
4162                         // save the eye position and orientation
4163                         if ( Game_mode & GM_MULTIPLAYER ) {
4164                                 Net_player->s_info.eye_pos = eye_pos;
4165                                 Net_player->s_info.eye_orient = eye_orient;
4166                         }
4167
4168                         hud_show_target_model();
4169
4170                         // check to see if we should display the death died popup
4171                         if(Game_mode & GM_DEAD_BLEW_UP){                                
4172                                 if(Game_mode & GM_MULTIPLAYER){
4173                                         // catch the situation where we're supposed to be warping out on this transition
4174                                         if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4175                                                 gameseq_post_event(GS_EVENT_DEBRIEF);
4176                                         } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4177                                                 Player_died_popup_wait = -1;
4178                                                 popupdead_start();
4179                                         }
4180                                 } else {
4181                                         if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4182                                                 Player_died_popup_wait = -1;
4183                                                 popupdead_start();
4184                                         }
4185                                 }
4186                         }
4187
4188                         // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4189                         if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4190                                 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4191                                         if(!popupdead_is_active()){
4192                                                 popupdead_start();
4193                                         }
4194
4195                                         Player_multi_died_check = -1;
4196                                 }
4197                         }
4198         
4199                         render3_time2 = timer_get_fixed_seconds();
4200                         render2_time1 = timer_get_fixed_seconds();
4201
4202                         gr_reset_clip();
4203                         game_get_framerate();
4204                         game_show_framerate();          
4205
4206                         game_show_time_left();
4207
4208                         // Draw the 2D HUD gauges
4209                         if(supernova_active() < 3){
4210                                 game_render_hud_2d();
4211                         }
4212
4213                         game_set_view_clip();
4214
4215                         // Draw 3D HUD gauges                   
4216                         game_render_hud_3d(&eye_pos, &eye_orient);                                                                      
4217
4218                         game_tst_frame();
4219
4220                         render2_time2 = timer_get_fixed_seconds();
4221
4222                         // maybe render and process the dead popup
4223                         game_maybe_do_dead_popup(flFrametime);
4224
4225                         // start timing frame
4226                         timing_frame_stop();
4227                         // timing_display(30, 10);                      
4228
4229                         // If a regular popup is active, don't flip (popup code flips)
4230                         if( !popup_running_state() ){
4231                                 flip_time1 = timer_get_fixed_seconds();
4232                                 game_flip_page_and_time_it();
4233                                 flip_time2 = timer_get_fixed_seconds();
4234                         }
4235
4236 #ifndef NDEBUG
4237                         game_maybe_dump_frame();                        // used to dump pcx files for building trailers
4238 #endif          
4239                 } else {
4240                         game_show_standalone_framerate();
4241                 }
4242         }
4243
4244         game_do_training_checks();
4245         asteroid_frame();
4246
4247         // process lightning (nebula only)
4248         nebl_process();
4249
4250         total_time2 = timer_get_fixed_seconds();
4251
4252         // Got some timing numbers
4253         Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4254         Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4255         Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4256         Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4257         Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4258
4259 #ifdef DEMO_SYSTEM
4260         demo_do_frame_end();
4261         if(Demo_error){
4262                 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4263                 demo_close();
4264         }
4265 #endif
4266 }
4267
4268 #define MAX_FRAMETIME   (F1_0/4)                // Frametime gets saturated at this.  Changed by MK on 11/1/97.
4269                                                                                                 //      Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4270                                                                                                 //      died.  This resulted in screwed up death sequences.
4271
4272 fix Last_time = 0;                                              // The absolute time of game at end of last frame (beginning of this frame)
4273 fix Last_delta_time = 0;                                // While game is paused, this keeps track of how much elapsed in the frame before paused.
4274 static int timer_paused=0;
4275 static int stop_count,start_count;
4276 static int time_stopped,time_started;
4277 int saved_timestamp_ticker = -1;
4278
4279 void game_reset_time()
4280 {
4281         if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4282                 return ;
4283         }
4284         
4285         //      Last_time = timer_get_fixed_seconds();
4286         game_start_time();
4287         timestamp_reset();
4288         game_stop_time();
4289 }
4290
4291 void game_stop_time()
4292 {
4293         if (timer_paused==0) {
4294                 fix time;
4295                 time = timer_get_fixed_seconds();
4296                 // Save how much time progressed so far in the frame so we can
4297                 // use it when we unpause.
4298                 Last_delta_time = time - Last_time;             
4299
4300                 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4301                 if (Last_delta_time < 0) {
4302                         #if defined(TIMER_TEST) && !defined(NDEBUG)
4303                         Int3();         //get Matt!!!!
4304                         #endif
4305                         Last_delta_time = 0;
4306                 }
4307                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4308                 time_stopped = time;
4309                 #endif
4310
4311                 // Stop the timer_tick stuff...
4312                 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4313                 saved_timestamp_ticker = timestamp_ticker;
4314         }
4315         timer_paused++;
4316
4317         #if defined(TIMER_TEST) && !defined(NDEBUG)
4318         stop_count++;
4319         #endif
4320 }
4321
4322 void game_start_time()
4323 {
4324         timer_paused--;
4325         Assert(timer_paused >= 0);
4326         if (timer_paused==0) {
4327                 fix time;
4328                 time = timer_get_fixed_seconds();
4329                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4330                 if (Last_time < 0)
4331                         Int3();         //get Matt!!!!
4332                 }
4333                 #endif
4334                 // Take current time, and set it backwards to account for time  
4335                 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4336                 // will be correct when it goes to calculate the frametime next
4337                 // frame.
4338                 Last_time = time - Last_delta_time;             
4339                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4340                 time_started = time;
4341                 #endif
4342
4343                 // Restore the timer_tick stuff...
4344                 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4345                 Assert( saved_timestamp_ticker > -1 );          // Called out of order, get JAS
4346                 timestamp_ticker = saved_timestamp_ticker;
4347                 saved_timestamp_ticker = -1;
4348         }
4349
4350         #if defined(TIMER_TEST) && !defined(NDEBUG)
4351         start_count++;
4352         #endif
4353 }
4354
4355
4356 void game_set_frametime(int state)
4357 {
4358         fix thistime;
4359         float frame_cap_diff;
4360
4361         thistime = timer_get_fixed_seconds();
4362
4363         if ( Last_time == 0 )   
4364                 Frametime = F1_0 / 30;
4365         else
4366                 Frametime = thistime - Last_time;
4367
4368 //      Frametime = F1_0 / 30;
4369
4370         fix     debug_frametime = Frametime;    //      Just used to display frametime.
4371
4372         //      If player hasn't entered mission yet, make frame take 1/4 second.
4373         if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4374                 Frametime = F1_0/4;
4375 #ifndef NDEBUG
4376         else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) {                                // note link to above if!!!!!
4377         
4378                 fix frame_speed = F1_0 / Debug_dump_frames;
4379
4380                 if (Frametime > frame_speed ){
4381                         nprintf(("warning","slow frame: %x\n",Frametime));
4382                 } else {                        
4383                         do {
4384                                 thistime = timer_get_fixed_seconds();
4385                                 Frametime = thistime - Last_time;
4386                         } while (Frametime < frame_speed );                     
4387                 }
4388                 Frametime = frame_speed;
4389         }
4390 #endif
4391
4392         Assert( Framerate_cap > 0 );
4393
4394         // Cap the framerate so it doesn't get too high.
4395         {
4396                 fix cap;
4397
4398                 cap = F1_0/Framerate_cap;
4399                 if (Frametime < cap) {
4400                         thistime = cap - Frametime;
4401                         //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4402                         Sleep( DWORD(f2fl(thistime) * 1000.0f) );
4403                         Frametime = cap;
4404                         thistime = timer_get_fixed_seconds();
4405                 }
4406         }
4407
4408         if((Game_mode & GM_STANDALONE_SERVER) && 
4409                 (f2fl(Frametime) < ((float)1.0/(float)Multi_options_g.std_framecap))){
4410
4411                 frame_cap_diff = ((float)1.0/(float)Multi_options_g.std_framecap) - f2fl(Frametime);            
4412                 Sleep((DWORD)(frame_cap_diff*1000));                            
4413                 
4414                 thistime += fl2f((frame_cap_diff));             
4415
4416                 Frametime = thistime - Last_time;
4417    }
4418
4419         // If framerate is too low, cap it.
4420         if (Frametime > MAX_FRAMETIME)  {
4421 #ifndef NDEBUG
4422                 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4423 #else 
4424                 // to remove warnings in release build
4425                 debug_frametime = fl2f(flFrametime);
4426 #endif
4427                 Frametime = MAX_FRAMETIME;
4428         }
4429
4430         Frametime = fixmul(Frametime, Game_time_compression);
4431
4432         Last_time = thistime;
4433         //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4434
4435         flFrametime = f2fl(Frametime);
4436         //if(!(Game_mode & GM_PLAYING_DEMO)){
4437         timestamp_inc(flFrametime);
4438
4439 /*      if ((Framecount > 0) && (Framecount < 10)) {
4440                 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4441         }
4442 */
4443 }
4444
4445 // This is called from game_do_frame(), and from navmap_do_frame() 
4446 void game_update_missiontime()
4447 {
4448         // TODO JAS: Put in if and move this into game_set_frametime, 
4449         // fix navmap to call game_stop/start_time
4450         //if ( !timer_paused )  
4451                 Missiontime += Frametime;
4452 }
4453
4454 void game_do_frame()
4455 {       
4456         game_set_frametime(GS_STATE_GAME_PLAY);
4457         game_update_missiontime();
4458
4459         if (Game_mode & GM_STANDALONE_SERVER) {
4460                 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4461         }
4462
4463         if ( game_single_step && (last_single_step == game_single_step) ) {
4464                 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4465                 while( key_checkch() == 0 )
4466                         os_sleep(10);
4467                 os_set_title( XSTR( "FreeSpace", 171) );
4468                 Last_time = timer_get_fixed_seconds();
4469         }
4470
4471         last_single_step = game_single_step;
4472
4473         if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4474                 Keep_mouse_centered = 1;  // force mouse to center of our window (so we don't hit movement limits)
4475         }
4476         game_frame();
4477
4478         Keep_mouse_centered = 0;
4479         monitor_update();                       // Update monitor variables
4480 }
4481
4482 void multi_maybe_do_frame()
4483 {
4484         if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4485                 game_do_frame(); 
4486         }
4487 }
4488
4489 int Joymouse_button_status = 0;
4490
4491 // Flush all input devices
4492 void game_flush()
4493 {
4494         key_flush();
4495         mouse_flush();
4496         joy_flush();
4497         snazzy_flush();
4498
4499         Joymouse_button_status = 0;
4500
4501         //mprintf(("Game flush!\n" ));
4502 }
4503
4504 // function for multiplayer only which calls game_do_state_common() when running the
4505 // debug console
4506 void game_do_dc_networking()
4507 {
4508         Assert( Game_mode & GM_MULTIPLAYER );
4509
4510         game_do_state_common( gameseq_get_state() );
4511 }
4512
4513 // Call this whenever in a loop, or when you need to check for a keystroke.
4514 int game_check_key()
4515 {
4516         int k;
4517
4518         k = game_poll();
4519
4520         // convert keypad enter to normal enter
4521         if ((k & KEY_MASK) == KEY_PADENTER)
4522                 k = (k & ~KEY_MASK) | KEY_ENTER;
4523
4524         return k;
4525 }
4526
4527 #ifdef FS2_DEMO
4528
4529 #define DEMO_TRAILER_TIMEOUT_MS         45000                   // 45 seconds of no input, play trailer
4530 static int Demo_show_trailer_timestamp = 0;
4531
4532 void demo_reset_trailer_timer()
4533 {
4534         Demo_show_trailer_timestamp = timer_get_milliseconds();
4535 }
4536
4537 void demo_maybe_show_trailer(int k)
4538 {
4539         /*
4540         // if key pressed, reset demo trailer timer
4541         if ( k > 0 ) {
4542                 demo_reset_trailer_timer();
4543                 return;
4544         }
4545
4546         // if mouse moved, reset demo trailer timer
4547         int dx = 0, dy = 0;
4548
4549         mouse_get_delta(&dx, &dy);
4550         if ( (dx > 0) || (dy > 0) ) {
4551                 demo_reset_trailer_timer();
4552                 return;
4553         }
4554
4555         // if joystick has moved, reset demo trailer timer
4556         dx = 0;
4557         dy = 0;
4558         joy_get_delta(&dx, &dy);
4559         if ( (dx > 0) || (dy > 0) ) {
4560                 demo_reset_trailer_timer();
4561                 return;
4562         }
4563
4564         // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4565         //       the low-level code.  Ugly, I know... but was the simplest and most
4566         //       robust solution.
4567                 
4568         // if 30 seconds since last demo trailer time reset, launch movie
4569         if ( os_foreground() ) {
4570                 int now = timer_get_milliseconds();
4571                 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4572 //              if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4573                         // play movie here
4574                         movie_play( NOX("fstrailer2.mve") );
4575                         demo_reset_trailer_timer();
4576                 }
4577         }
4578         */
4579 }
4580
4581 #endif
4582
4583 // same as game_check_key(), except this is used while actually in the game.  Since there
4584 // generally are differences between game control keys and general UI keys, makes sense to
4585 // have seperate functions for each case.  If you are not checking a game control while in a
4586 // mission, you should probably be using game_check_key() instead.
4587 int game_poll()
4588 {
4589         int k, state;
4590
4591         if (!os_foreground()) {         
4592                 game_stop_time();
4593                 os_sleep(100);
4594                 game_start_time();
4595
4596                 // If we're in a single player game, pause it.
4597                 if (!(Game_mode & GM_MULTIPLAYER)){
4598                         if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) )     {
4599                                 game_process_pause_key();
4600                         }
4601                 }
4602         }
4603
4604    k = key_inkey();
4605
4606 #ifdef FS2_DEMO
4607         demo_maybe_show_trailer(k);
4608 #endif
4609
4610         // Move the mouse cursor with the joystick.
4611         if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) )     {
4612                 // Move the mouse cursor with the joystick
4613                 int mx, my, dx, dy;
4614                 int jx, jy, jz, jr;
4615
4616                 joy_get_pos( &jx, &jy, &jz, &jr );
4617
4618                 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4619                 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4620
4621                 if ( dx || dy ) {
4622                         mouse_get_real_pos( &mx, &my );
4623                         mouse_set_pos( mx+dx, my+dy );
4624                 }
4625
4626                 int j, m;
4627                 j = joy_down(0);
4628                 m = mouse_down(MOUSE_LEFT_BUTTON);
4629
4630                 if ( j != Joymouse_button_status )      {
4631                         //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4632                         Joymouse_button_status = j;
4633                         if ( j && (!m) )        {
4634                                 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4635                         } else if ( (!j) && (m) )       {
4636                                 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4637                         }
4638                 }
4639         }
4640
4641         // if we should be ignoring keys because of some multiplayer situations
4642         if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4643                 return 0;
4644         }
4645
4646         // If a popup is running, don't process all the Fn keys
4647         if( popup_active() ) {
4648                 return k;
4649         }
4650
4651         state = gameseq_get_state();
4652
4653 //      if ( k ) nprintf(( "General", "Key = %x\n", k ));
4654
4655         switch (k) {
4656                 case KEY_DEBUGGED + KEY_BACKSP:
4657                         Int3();
4658                         break;
4659
4660                 case KEY_F1:
4661                         launch_context_help();
4662                         k = 0;
4663                         break;
4664
4665                 case KEY_F2:
4666 //                      if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4667
4668                         // don't allow f2 while warping out in multiplayer      
4669                         if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4670                                 break;
4671                         }
4672
4673                         switch (state) {
4674                                 case GS_STATE_INITIAL_PLAYER_SELECT:
4675                                 case GS_STATE_OPTIONS_MENU:
4676                                 case GS_STATE_HUD_CONFIG:
4677                                 case GS_STATE_CONTROL_CONFIG:
4678                                 case GS_STATE_DEATH_DIED:
4679                                 case GS_STATE_DEATH_BLEW_UP:            
4680                                 case GS_STATE_VIEW_MEDALS:
4681                                         break;
4682
4683                                 default:
4684                                         gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4685                                         k = 0;
4686                                         break;
4687                         }
4688
4689                         break;
4690
4691                         // hotkey selection screen -- only valid from briefing and beyond.
4692                 case KEY_F3:    
4693                         #ifndef FS2_DEMO
4694                                 if ( (state == GS_STATE_TEAM_SELECT) || (state == GS_STATE_BRIEFING) || (state == GS_STATE_SHIP_SELECT) || (state == GS_STATE_WEAPON_SELECT) || (state == GS_STATE_GAME_PLAY) || (state == GS_STATE_GAME_PAUSED) ) {
4695                                         gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4696                                         k = 0;
4697                                 }
4698                         #endif
4699                         break;
4700
4701                 case KEY_DEBUGGED + KEY_F3:
4702                         gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4703                         break;
4704
4705                 case KEY_DEBUGGED + KEY_F4:
4706                         gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4707                         break;
4708                 
4709                 case KEY_F4:
4710                         if(Game_mode & GM_MULTIPLAYER){
4711                                 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4712                                         gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4713                                         k = 0;
4714                                 } 
4715                         } else {
4716                                 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4717                                         gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4718                                         k = 0;
4719                                 }
4720                         }
4721                         break;
4722
4723                 case KEY_ESC | KEY_SHIFTED:
4724                         // make sure to quit properly out of multiplayer
4725                         if(Game_mode & GM_MULTIPLAYER){
4726                                 multi_quit_game(PROMPT_NONE);
4727                         }
4728
4729                         gameseq_post_event( GS_EVENT_QUIT_GAME );
4730                         k = 0;
4731
4732                         break;
4733
4734                 case KEY_DEBUGGED + KEY_P:                      
4735                         break;                  
4736
4737                 case KEY_PRINT_SCRN: 
4738                         {
4739                                 static int counter = 0;
4740                                 char tmp_name[127];
4741
4742                                 game_stop_time();
4743
4744                                 sprintf( tmp_name, NOX("screen%02d"), counter );
4745                                 counter++;
4746                                 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4747                                 gr_print_screen(tmp_name);
4748
4749                                 game_start_time();
4750                         }
4751
4752                         k = 0;
4753                         break;
4754
4755                 case KEY_SHIFTED | KEY_ENTER: {
4756
4757 #if !defined(NDEBUG)
4758
4759                         if ( Game_mode & GM_NORMAL ){
4760                                 game_stop_time();
4761                         }
4762
4763                         // if we're in multiplayer mode, do some special networking
4764                         if(Game_mode & GM_MULTIPLAYER){
4765                                 debug_console(game_do_dc_networking);
4766                         } else {                                
4767                                 debug_console();
4768                         }
4769
4770                         game_flush();
4771
4772                         if ( Game_mode & GM_NORMAL )
4773                                 game_start_time();
4774
4775 #endif
4776
4777                         break;
4778                 }
4779         }
4780
4781         return k;
4782 }
4783
4784 void os_close()
4785 {
4786         gameseq_post_event(GS_EVENT_QUIT_GAME);
4787 }
4788
4789 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4790
4791
4792 void camera_set_position( vector *pos )
4793 {
4794         Camera_pos = *pos;
4795 }
4796
4797 void camera_set_orient( matrix *orient )
4798 {
4799         Camera_orient = *orient;
4800 }
4801
4802 void camera_set_velocity( vector *vel, int instantaneous )
4803 {
4804         Camera_desired_velocity.x = 0.0f;
4805         Camera_desired_velocity.y = 0.0f;
4806         Camera_desired_velocity.z = 0.0f;
4807
4808         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.rvec, vel->x );
4809         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.uvec, vel->y );
4810         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.fvec, vel->z );
4811
4812         if ( instantaneous )    {
4813                 Camera_velocity = Camera_desired_velocity;
4814         }
4815
4816 }
4817
4818 //
4819 void camera_move()
4820 {
4821         vector new_vel, delta_pos;
4822
4823         apply_physics( Camera_damping, Camera_desired_velocity.x, Camera_velocity.x, flFrametime, &new_vel.x, &delta_pos.x );
4824         apply_physics( Camera_damping, Camera_desired_velocity.y, Camera_velocity.y, flFrametime, &new_vel.y, &delta_pos.y );
4825         apply_physics( Camera_damping, Camera_desired_velocity.z, Camera_velocity.z, flFrametime, &new_vel.z, &delta_pos.z );
4826
4827         Camera_velocity = new_vel;
4828
4829 //      mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.x, Camera_velocity.y, Camera_velocity.z ));
4830
4831         vm_vec_add2( &Camera_pos, &delta_pos );
4832
4833         float ot = Camera_time+0.0f;
4834
4835         Camera_time += flFrametime;
4836
4837         if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) )       {
4838                 vector tmp;
4839                 
4840                 tmp.z = 4.739f;         // always go this fast forward.
4841
4842                 // pick x and y velocities so they are always on a 
4843                 // circle with a 25 m radius.
4844
4845                 float tmp_angle = frand()*PI2;
4846         
4847                 tmp.x = 22.0f * (float)sin(tmp_angle);
4848                 tmp.y = -22.0f * (float)cos(tmp_angle);
4849
4850                 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.x, tmp.y ));
4851
4852                 //mprintf(( "Changing velocity!\n" ));
4853                 camera_set_velocity( &tmp, 0 );
4854         }
4855
4856         if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) )  {
4857                 vector tmp = { 0.0f, 0.0f, 0.0f };
4858                 camera_set_velocity( &tmp, 0 );
4859         }
4860         
4861 }
4862
4863 void end_demo_campaign_do()
4864 {
4865 #if defined(FS2_DEMO)
4866         // show upsell screens
4867         demo_upsell_show_screens();
4868 #elif defined(OEM_BUILD)
4869         // show oem upsell screens
4870         oem_upsell_show_screens();
4871 #endif
4872
4873         // drop into main hall
4874         gameseq_post_event( GS_EVENT_MAIN_MENU );
4875 }
4876
4877 // All code to process events.   This is the only place
4878 // that you should change the state of the game.
4879 void game_process_event( int current_state, int event )
4880 {
4881         mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4882
4883         switch (event) {
4884                 case GS_EVENT_SIMULATOR_ROOM:
4885                         gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4886                         break;
4887
4888                 case GS_EVENT_MAIN_MENU:
4889                         gameseq_set_state(GS_STATE_MAIN_MENU);          
4890                         break;
4891
4892                 case GS_EVENT_OPTIONS_MENU:
4893                         gameseq_push_state( GS_STATE_OPTIONS_MENU );
4894                         break;
4895
4896                 case GS_EVENT_BARRACKS_MENU:
4897                         gameseq_set_state(GS_STATE_BARRACKS_MENU);              
4898                         break;
4899
4900                 case GS_EVENT_TECH_MENU:
4901                         gameseq_set_state(GS_STATE_TECH_MENU);          
4902                         break;
4903
4904                 case GS_EVENT_TRAINING_MENU:
4905                         gameseq_set_state(GS_STATE_TRAINING_MENU);              
4906                         break;
4907
4908                 case GS_EVENT_START_GAME:
4909                         Select_default_ship = 0;                        
4910                         Player_multi_died_check = -1;
4911                         gameseq_set_state(GS_STATE_CMD_BRIEF);
4912                         break;
4913
4914                 case GS_EVENT_START_BRIEFING:
4915                         gameseq_set_state(GS_STATE_BRIEFING);           
4916                         break;
4917
4918                 case GS_EVENT_DEBRIEF:
4919                         // did we end the campaign in the main freespace 2 single player campaign?
4920                         if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !stricmp(Campaign.filename, "freespace2")) {
4921                                 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4922                         } else {
4923                                 gameseq_set_state(GS_STATE_DEBRIEF);            
4924                         }
4925
4926                         Player_multi_died_check = -1;
4927                         break;
4928
4929                 case GS_EVENT_SHIP_SELECTION:
4930                         gameseq_set_state( GS_STATE_SHIP_SELECT );
4931                         break;
4932
4933                 case GS_EVENT_WEAPON_SELECTION:
4934                         gameseq_set_state( GS_STATE_WEAPON_SELECT );
4935                         break;
4936
4937                 case GS_EVENT_ENTER_GAME:               
4938 #ifdef DEMO_SYSTEM
4939                         // maybe start recording a demo
4940                         if(Demo_make){
4941                                 demo_start_record("test.fsd");
4942                         }
4943 #endif
4944
4945                         if (Game_mode & GM_MULTIPLAYER) {
4946                                 // if we're respawning, make sure we change the view mode so that the hud shows up
4947                                 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4948                                         Viewer_mode = 0;
4949                                 }
4950
4951                                 gameseq_set_state(GS_STATE_GAME_PLAY);
4952                         } else {
4953                                 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
4954                         }
4955
4956                         Player_multi_died_check = -1;
4957
4958                         // clear multiplayer button info                        
4959                         extern button_info Multi_ship_status_bi;
4960                         memset(&Multi_ship_status_bi, 0, sizeof(button_info));
4961
4962                         Start_time = f2fl(timer_get_approx_seconds());
4963                         //Framecount = 0;
4964                         mprintf(("Entering game at time = %7.3f\n", Start_time));
4965                         break;
4966
4967
4968                 case GS_EVENT_START_GAME_QUICK:
4969                         Select_default_ship = 1;
4970                         gameseq_post_event(GS_EVENT_ENTER_GAME);
4971                         break;
4972
4973
4974                 case GS_EVENT_END_GAME:
4975                         if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
4976                                 (current_state == GS_STATE_DEATH_BLEW_UP) ||    (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
4977                                         gameseq_set_state(GS_STATE_MAIN_MENU);
4978
4979                         } else
4980                                 Int3();
4981
4982                         Player_multi_died_check = -1;
4983                         break;
4984
4985                 case GS_EVENT_QUIT_GAME:
4986                         main_hall_stop_music();
4987                         main_hall_stop_ambient();
4988                         gameseq_set_state(GS_STATE_QUIT_GAME);
4989
4990                         Player_multi_died_check = -1;
4991                         break;
4992
4993                 case GS_EVENT_GAMEPLAY_HELP:
4994                         gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
4995                         break;
4996
4997                 case GS_EVENT_PAUSE_GAME:
4998                         gameseq_push_state(GS_STATE_GAME_PAUSED);
4999                         break;
5000
5001                 case GS_EVENT_DEBUG_PAUSE_GAME:
5002                         gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5003                         break;
5004
5005                 case GS_EVENT_TRAINING_PAUSE:
5006                         gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5007                         break;
5008
5009                 case GS_EVENT_PREVIOUS_STATE:
5010                         gameseq_pop_state();
5011                         break;
5012
5013                 case GS_EVENT_TOGGLE_FULLSCREEN:
5014                         #ifndef HARDWARE_ONLY
5015                                 #ifndef NDEBUG
5016                                 if ( gr_screen.mode == GR_SOFTWARE )    {
5017                                         gr_init( GR_640, GR_DIRECTDRAW );
5018                                 } else if ( gr_screen.mode == GR_DIRECTDRAW )   {
5019                                         gr_init( GR_640, GR_SOFTWARE );
5020                                 }
5021                                 #endif
5022                         #endif
5023                         break;
5024
5025                 case GS_EVENT_TOGGLE_GLIDE:
5026                         #ifndef NDEBUG
5027                         if ( gr_screen.mode != GR_GLIDE )       {
5028                                 gr_init( GR_640, GR_GLIDE );
5029                         } else {
5030                                 gr_init( GR_640, GR_SOFTWARE );
5031                         }
5032                         #endif
5033                         break;                                          
5034  
5035                 case GS_EVENT_LOAD_MISSION_MENU:
5036                         gameseq_set_state(GS_STATE_LOAD_MISSION_MENU);
5037                         break;
5038
5039                 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5040                         gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5041                         break;
5042
5043                 case GS_EVENT_HUD_CONFIG:
5044                         gameseq_push_state( GS_STATE_HUD_CONFIG );
5045                         break;
5046
5047                 case GS_EVENT_CONTROL_CONFIG:
5048                         gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5049                         break;  
5050
5051                 case GS_EVENT_DEATH_DIED:
5052                         gameseq_set_state( GS_STATE_DEATH_DIED );
5053                         break;
5054
5055                 case GS_EVENT_DEATH_BLEW_UP:
5056                         if (  current_state == GS_STATE_DEATH_DIED )    {
5057                                 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5058                                 event_music_player_death();
5059
5060                                 // multiplayer clients set their extra check here
5061                                 if(Game_mode & GM_MULTIPLAYER){
5062                                         // set the multi died absolute last chance check                                        
5063                                         Player_multi_died_check = time(NULL);
5064                                 }                                       
5065                         } else {
5066                                 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5067                         }
5068                         break;
5069
5070                 case GS_EVENT_NEW_CAMPAIGN:
5071                         if (!mission_load_up_campaign()){
5072                                 readyroom_continue_campaign();
5073                         }
5074
5075                         Player_multi_died_check = -1;
5076                         break;
5077
5078                 case GS_EVENT_CAMPAIGN_CHEAT:
5079                         if (!mission_load_up_campaign()){
5080                                 /*
5081                                 // bash campaign value
5082                                 extern char Main_hall_campaign_cheat[512];
5083                                 int idx;
5084                                 
5085                                 // look for the mission
5086                                 for(idx=0; idx<Campaign.num_missions; idx++){
5087                                         if(!stricmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5088                                                 Campaign.next_mission = idx;
5089                                                 Campaign.prev_mission = idx - 1;
5090                                                 break;
5091                                         }
5092                                 }
5093                                 */
5094
5095                                 // continue
5096                                 readyroom_continue_campaign();
5097                         }
5098
5099                         Player_multi_died_check = -1;
5100                         break;
5101
5102                 case GS_EVENT_CAMPAIGN_ROOM:
5103                         gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5104                         break;
5105
5106                 case GS_EVENT_CMD_BRIEF:
5107                         gameseq_set_state(GS_STATE_CMD_BRIEF);
5108                         break;
5109
5110                 case GS_EVENT_RED_ALERT:
5111                         gameseq_set_state(GS_STATE_RED_ALERT);
5112                         break;
5113
5114                 case GS_EVENT_CREDITS:
5115                         gameseq_set_state( GS_STATE_CREDITS );
5116                         break;
5117
5118                 case GS_EVENT_VIEW_MEDALS:
5119                         gameseq_push_state( GS_STATE_VIEW_MEDALS );
5120                         break;
5121
5122                 case GS_EVENT_SHOW_GOALS:
5123                         gameseq_push_state( GS_STATE_SHOW_GOALS );      // use push_state() since we might get to this screen through a variety of states
5124                         break;
5125
5126                 case GS_EVENT_HOTKEY_SCREEN:
5127                         gameseq_push_state( GS_STATE_HOTKEY_SCREEN );   // use push_state() since we might get to this screen through a variety of states
5128                         break;
5129                 
5130         // multiplayer stuff follow these comments
5131
5132                 case GS_EVENT_MULTI_JOIN_GAME:
5133                         gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5134                         break;
5135
5136                 case GS_EVENT_MULTI_HOST_SETUP:
5137                         gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5138                         break;
5139
5140                 case GS_EVENT_MULTI_CLIENT_SETUP:
5141                         gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5142                         break;
5143
5144                 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5145                         gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5146                         break;
5147
5148                 case GS_EVENT_MULTI_STD_WAIT:
5149                         gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5150                         break;
5151
5152                 case GS_EVENT_STANDALONE_MAIN:
5153                         gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5154                         break;   
5155
5156                 case GS_EVENT_MULTI_PAUSE:
5157                         gameseq_push_state( GS_STATE_MULTI_PAUSED );
5158                         break;                  
5159
5160                 case GS_EVENT_INGAME_PRE_JOIN:
5161                         gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5162                         break;
5163                 
5164                 case GS_EVENT_EVENT_DEBUG:
5165                         gameseq_push_state(GS_STATE_EVENT_DEBUG);
5166                         break;
5167
5168                 // Start a warpout where player automatically goes 70 no matter what
5169                 // and can't cancel out of it.
5170                 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5171                         Warpout_forced = 1;                                                     // If non-zero, bash the player to speed and go through effect
5172
5173                         // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5174                         Player->saved_viewer_mode = Viewer_mode;
5175                         Player->control_mode = PCM_WARPOUT_STAGE1;
5176                         Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5177                         Warpout_time = 0.0f;                    // Start timer!
5178                         break;
5179
5180                 case GS_EVENT_PLAYER_WARPOUT_START:
5181                         if ( Player->control_mode != PCM_NORMAL )       {
5182                                 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5183                         } else {
5184                                 Player->saved_viewer_mode = Viewer_mode;
5185                                 Player->control_mode = PCM_WARPOUT_STAGE1;
5186                                 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5187                                 Warpout_time = 0.0f;                    // Start timer!
5188                                 Warpout_forced = 0;                             // If non-zero, bash the player to speed and go through effect
5189                         }
5190                         break;
5191
5192                 case GS_EVENT_PLAYER_WARPOUT_STOP:
5193                         if ( Player->control_mode != PCM_NORMAL )       {
5194                                 if ( !Warpout_forced )  {               // cannot cancel forced warpout
5195                                         Player->control_mode = PCM_NORMAL;
5196                                         Viewer_mode = Player->saved_viewer_mode;
5197                                         hud_subspace_notify_abort();
5198                                         mprintf(( "Player put back to normal mode.\n" ));
5199                                         if ( Warpout_sound > -1 )       {
5200                                                 snd_stop( Warpout_sound );
5201                                                 Warpout_sound = -1;
5202                                         }
5203                                 }
5204                         }
5205                         break;
5206
5207                 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1:               // player ship got up to speed
5208                         if ( Player->control_mode != PCM_WARPOUT_STAGE1 )       {
5209                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5210                                 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5211                         } else {
5212                                 mprintf(( "Hit target speed.  Starting warp effect and moving to stage 2!\n" ));
5213                                 shipfx_warpout_start( Player_obj );
5214                                 Player->control_mode = PCM_WARPOUT_STAGE2;
5215                                 Player->saved_viewer_mode = Viewer_mode;
5216                                 Viewer_mode |= VM_WARP_CHASE;
5217                                 
5218                                 vector tmp = Player_obj->pos;
5219                                 matrix tmp_m;
5220                                 ship_get_eye( &tmp, &tmp_m, Player_obj );
5221                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.rvec, 0.0f );
5222                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.uvec, 0.952f );
5223                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.fvec, -1.782f );
5224                                 Camera_time = 0.0f;
5225                                 camera_set_position( &tmp );
5226                                 camera_set_orient( &Player_obj->orient );
5227                                 vector tmp_vel = { 0.0f, 5.1919f, 14.7f };
5228
5229                                 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5230                                 camera_set_velocity( &tmp_vel, 1);
5231                         }
5232                         break;
5233
5234                 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2:               // player ship got into the warp effect
5235                         if ( Player->control_mode != PCM_WARPOUT_STAGE2 )       {
5236                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5237                                 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5238                         } else {
5239                                 mprintf(( "Hit warp effect.  Moving to stage 3!\n" ));
5240                                 Player->control_mode = PCM_WARPOUT_STAGE3;
5241                         }
5242                         break;
5243
5244                 case GS_EVENT_PLAYER_WARPOUT_DONE:      // player ship got through the warp effect
5245                         mprintf(( "Player warped out.  Going to debriefing!\n" ));
5246                         Player->control_mode = PCM_NORMAL;
5247                         Viewer_mode = Player->saved_viewer_mode;
5248                         Warpout_sound = -1;
5249
5250                         // we have a special debriefing screen for multiplayer furballs
5251                         if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5252                                 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5253                         }
5254                         // do the normal debriefing for all other situations
5255                         else {
5256                                 gameseq_post_event(GS_EVENT_DEBRIEF);
5257                         }
5258                         break;
5259
5260                 case GS_EVENT_STANDALONE_POSTGAME:
5261                         gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5262                         break;
5263
5264                 case GS_EVENT_INITIAL_PLAYER_SELECT:
5265                         gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5266                         break;
5267
5268                 case GS_EVENT_GAME_INIT:
5269         #if defined(FS2_DEMO) || defined(OEM_BUILD)
5270                         gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5271         #else                   
5272                         // see if the command line option has been set to use the last pilot, and act acoordingly
5273                         if( player_select_get_last_pilot() ) {                                                          
5274                                 // always enter the main menu -- do the automatic network startup stuff elsewhere
5275                                 // so that we still have valid checks for networking modes, etc.
5276                                 gameseq_set_state(GS_STATE_MAIN_MENU);
5277                         } else {
5278                                 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5279                         }
5280         #endif
5281                         break;
5282
5283                 case GS_EVENT_MULTI_MISSION_SYNC:
5284                         gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5285                         break;          
5286
5287                 case GS_EVENT_MULTI_START_GAME:
5288                         gameseq_set_state(GS_STATE_MULTI_START_GAME);
5289                         break;
5290
5291                 case GS_EVENT_MULTI_HOST_OPTIONS:
5292                         gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5293                         break;
5294
5295                 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5296                         gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5297                         break;
5298
5299                 case GS_EVENT_TEAM_SELECT:
5300                         gameseq_set_state(GS_STATE_TEAM_SELECT);
5301                         break;
5302
5303                 case GS_EVENT_END_CAMPAIGN:                     
5304                         gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5305                         break;          
5306
5307                 case GS_EVENT_END_DEMO:
5308                         gameseq_set_state(GS_STATE_END_DEMO);
5309                         break;
5310
5311                 case GS_EVENT_LOOP_BRIEF:
5312                         gameseq_set_state(GS_STATE_LOOP_BRIEF);
5313                         break;
5314
5315                 default:
5316                         Int3();
5317                         break;
5318         }
5319 }
5320
5321 // Called when a state is being left.
5322 // The current state is still at old_state, but as soon as
5323 // this function leaves, then the current state will become
5324 // new state.     You should never try to change the state
5325 // in here... if you think you need to, you probably really
5326 // need to post an event, not change the state.
5327 void game_leave_state( int old_state, int new_state )
5328 {
5329         int end_mission = 1;
5330
5331         switch (new_state) {
5332                 case GS_STATE_GAME_PAUSED:
5333                 case GS_STATE_DEBUG_PAUSED:
5334                 case GS_STATE_OPTIONS_MENU:
5335                 case GS_STATE_CONTROL_CONFIG:           
5336                 case GS_STATE_MISSION_LOG_SCROLLBACK:
5337                 case GS_STATE_DEATH_DIED:
5338                 case GS_STATE_SHOW_GOALS:
5339                 case GS_STATE_HOTKEY_SCREEN:            
5340                 case GS_STATE_MULTI_PAUSED:
5341                 case GS_STATE_TRAINING_PAUSED:
5342                 case GS_STATE_EVENT_DEBUG:                              
5343                 case GS_STATE_GAMEPLAY_HELP:
5344                         end_mission = 0;  // these events shouldn't end a mission
5345                         break;
5346         }
5347
5348         switch (old_state) {
5349                 case GS_STATE_BRIEFING:
5350                         brief_stop_voices();
5351                         if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5352                                   && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5353                                   && (new_state != GS_STATE_TEAM_SELECT) ){
5354                                 common_select_close();
5355                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5356                                         freespace_stop_mission();       
5357                                 }
5358                         }
5359                         
5360                         // COMMAND LINE OPTION
5361                         if (Cmdline_multi_stream_chat_to_file){
5362                                 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5363                                 cfclose(Multi_chat_stream);
5364                         }
5365                         break;
5366
5367                 case GS_STATE_DEBRIEF:
5368                         if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5369                                 debrief_close();                                
5370                         }
5371                         break;
5372
5373                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5374                         multi_df_debrief_close();
5375                         break;
5376
5377                 case GS_STATE_LOAD_MISSION_MENU:
5378                         mission_load_menu_close();
5379                         break;
5380
5381                 case GS_STATE_SIMULATOR_ROOM:
5382                         sim_room_close();
5383                         break;
5384
5385                 case GS_STATE_CAMPAIGN_ROOM:
5386                         campaign_room_close();
5387                         break;
5388
5389                 case GS_STATE_CMD_BRIEF:
5390                         if (new_state == GS_STATE_OPTIONS_MENU) {
5391                                 cmd_brief_hold();
5392
5393                         } else {
5394                                 cmd_brief_close();
5395                                 if (new_state == GS_STATE_MAIN_MENU)
5396                                         freespace_stop_mission();       
5397                         }
5398
5399                         break;
5400
5401                 case GS_STATE_RED_ALERT:
5402                         red_alert_close();
5403                         break;
5404
5405                 case GS_STATE_SHIP_SELECT:
5406                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5407                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5408                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5409                                 common_select_close();
5410                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5411                                         freespace_stop_mission();       
5412                                 }
5413                         }
5414                         break;
5415
5416                 case GS_STATE_WEAPON_SELECT:
5417                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5418                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5419                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5420                                 common_select_close();
5421                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5422                                         freespace_stop_mission();       
5423                                 }
5424                         }
5425                         break;
5426
5427                 case GS_STATE_TEAM_SELECT:
5428                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5429                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5430                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5431                                 common_select_close();
5432                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5433                                         freespace_stop_mission();       
5434                                 }
5435                         }                                       
5436                         break;
5437
5438                 case GS_STATE_MAIN_MENU:
5439 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5440                         mht_close();
5441 #else
5442                         main_hall_close();
5443 #endif
5444                         break;
5445
5446                 case GS_STATE_OPTIONS_MENU:
5447                         //game_start_time();
5448                         if(new_state == GS_STATE_MULTI_JOIN_GAME){
5449                                 multi_join_clear_game_list();
5450                         }
5451                         options_menu_close();
5452                         break;
5453
5454                 case GS_STATE_BARRACKS_MENU:
5455                         if(new_state != GS_STATE_VIEW_MEDALS){
5456                                 barracks_close();
5457                         }
5458                         break;
5459
5460                 case GS_STATE_MISSION_LOG_SCROLLBACK:
5461                         hud_scrollback_close();
5462                         break;
5463
5464                 case GS_STATE_TRAINING_MENU:
5465                         training_menu_close();
5466                         break;
5467
5468                 case GS_STATE_GAME_PLAY:
5469                         if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5470                                 player_save_target_and_weapon_link_prefs();
5471                                 game_stop_looped_sounds();
5472                         }
5473
5474                         sound_env_disable();
5475                         joy_ff_stop_effects();
5476
5477                         // stop game time under certain conditions
5478                         if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5479                                 game_stop_time();
5480                         }
5481
5482                         if (end_mission) {
5483                         // shut down any recording or playing demos
5484 #ifdef DEMO_SYSTEM
5485                                 demo_close();
5486 #endif
5487
5488                                 // when in multiplayer and going back to the main menu, send a leave game packet
5489                                 // right away (before calling stop mission).  stop_mission was taking to long to
5490                                 // close mission down and I want people to get notified ASAP.
5491                                 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5492                                         multi_quit_game(PROMPT_NONE);
5493                                 }
5494
5495                                 freespace_stop_mission();                       
5496                                 Game_time_compression = F1_0;
5497                         }
5498                         break;
5499
5500                 case GS_STATE_TECH_MENU:
5501                         techroom_close();
5502                         break;
5503
5504                 case GS_STATE_TRAINING_PAUSED:
5505                         Training_num_lines = 0;
5506                         // fall through to GS_STATE_GAME_PAUSED
5507
5508                 case GS_STATE_GAME_PAUSED:
5509                         game_start_time();
5510                         if ( end_mission ) {
5511                                 pause_close(0);
5512                         }
5513                         break;
5514
5515                 case GS_STATE_DEBUG_PAUSED:
5516                         #ifndef NDEBUG
5517                                 game_start_time();
5518                                 pause_debug_close();
5519                         #endif
5520                         break;
5521
5522                 case GS_STATE_HUD_CONFIG:
5523                         hud_config_close();
5524                         break;
5525
5526                 // join/start a game
5527                 case GS_STATE_MULTI_JOIN_GAME:
5528                         if(new_state != GS_STATE_OPTIONS_MENU){
5529                                 multi_join_game_close();
5530                         }
5531                         break;
5532
5533                 case GS_STATE_MULTI_HOST_SETUP:
5534                 case GS_STATE_MULTI_CLIENT_SETUP:
5535                         // if this is just the host going into the options screen, don't do anything
5536                         if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5537                                 break;
5538                         }
5539
5540                         // close down the proper state
5541                         if(old_state == GS_STATE_MULTI_HOST_SETUP){
5542                                 multi_create_game_close();
5543                         } else {
5544                                 multi_game_client_setup_close();
5545                         }
5546
5547                         // COMMAND LINE OPTION
5548                         if (Cmdline_multi_stream_chat_to_file){
5549                                 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5550                                         cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5551                                         cfclose(Multi_chat_stream);
5552                                 }
5553                         }                       
5554                         break;
5555
5556                 case GS_STATE_CONTROL_CONFIG:
5557                         control_config_close();
5558                         break;
5559
5560                 case GS_STATE_DEATH_DIED:
5561                         Game_mode &= ~GM_DEAD_DIED;
5562                         
5563                         // early end while respawning or blowing up in a multiplayer game
5564                         if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5565                                 game_stop_time();
5566                                 freespace_stop_mission();
5567                         }
5568                         break;
5569
5570                 case GS_STATE_DEATH_BLEW_UP:
5571                         Game_mode &= ~GM_DEAD_BLEW_UP;
5572
5573                         // for single player, we might reload mission, etc.  For multiplayer, look at my new state
5574                         // to determine if I should do anything.
5575                         if ( !(Game_mode & GM_MULTIPLAYER) ) {
5576                                 if ( end_mission ){
5577                                         freespace_stop_mission();
5578                                 }
5579                         } else {
5580                                 // if we are not respawing as an observer or as a player, our new state will not
5581                                 // be gameplay state.
5582                                 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5583                                         game_stop_time();                                                                       // hasn't been called yet!!
5584                                         freespace_stop_mission();
5585                                 }
5586                         }
5587                         break;
5588
5589
5590                 case GS_STATE_CREDITS:
5591                         credits_close();
5592                         break;
5593
5594                 case GS_STATE_VIEW_MEDALS:
5595                         medal_main_close();
5596                         break;
5597
5598                 case GS_STATE_SHOW_GOALS:
5599                         mission_show_goals_close();
5600                         break;
5601
5602                 case GS_STATE_HOTKEY_SCREEN:
5603                         if ( new_state != GS_STATE_OPTIONS_MENU ) {
5604                                 mission_hotkey_close();
5605                         }
5606                         break;
5607
5608                 case GS_STATE_MULTI_MISSION_SYNC:
5609                         // if we're moving into the options menu, don't do anything
5610                         if(new_state == GS_STATE_OPTIONS_MENU){
5611                                 break;
5612                         }
5613
5614                         Assert( Game_mode & GM_MULTIPLAYER );
5615                         multi_sync_close();
5616                         if ( new_state == GS_STATE_GAME_PLAY ){
5617                                 // palette_restore_palette();
5618
5619                                 // change a couple of flags to indicate our state!!!
5620                                 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5621                                 send_netplayer_update_packet();
5622
5623                                 // set the game mode
5624                                 Game_mode |= GM_IN_MISSION;
5625                         }                       
5626                         break;          
5627    
5628                 case GS_STATE_VIEW_CUTSCENES:
5629                         cutscenes_screen_close();
5630                         break;
5631
5632                 case GS_STATE_MULTI_STD_WAIT:
5633                         multi_standalone_wait_close();
5634                         break;
5635
5636                 case GS_STATE_STANDALONE_MAIN:                  
5637                         standalone_main_close();
5638                         if(new_state == GS_STATE_MULTI_STD_WAIT){               
5639                                 init_multiplayer_stats();                                                                               
5640                         }                       
5641                         break;
5642
5643                 case GS_STATE_MULTI_PAUSED:
5644                         // if ( end_mission ){
5645                                 pause_close(1);
5646                         // }
5647                         break;                  
5648
5649                 case GS_STATE_INGAME_PRE_JOIN:
5650                         multi_ingame_select_close();
5651                         break;
5652
5653                 case GS_STATE_STANDALONE_POSTGAME:
5654                         multi_standalone_postgame_close();
5655                         break;
5656
5657                 case GS_STATE_INITIAL_PLAYER_SELECT:                    
5658                         player_select_close();                  
5659                         break;          
5660
5661                 case GS_STATE_MULTI_START_GAME:
5662                         multi_start_game_close();
5663                         break;
5664
5665                 case GS_STATE_MULTI_HOST_OPTIONS:
5666                         multi_host_options_close();
5667                         break;                          
5668
5669                 case GS_STATE_END_OF_CAMPAIGN:
5670                         mission_campaign_end_close();
5671                         break;
5672
5673                 case GS_STATE_LOOP_BRIEF:
5674                         loop_brief_close();
5675                         break;
5676         }
5677 }
5678
5679 // Called when a state is being entered.
5680 // The current state is set to the state we're entering at
5681 // this point, and old_state is set to the state we're coming
5682 // from.    You should never try to change the state
5683 // in here... if you think you need to, you probably really
5684 // need to post an event, not change the state.
5685
5686 void game_enter_state( int old_state, int new_state )
5687 {
5688         switch (new_state) {
5689                 case GS_STATE_MAIN_MENU:                                
5690                         // in multiplayer mode, be sure that we are not doing networking anymore.
5691                         if ( Game_mode & GM_MULTIPLAYER ) {
5692                                 Assert( Net_player != NULL );
5693                                 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5694                         }
5695
5696                         Game_time_compression = F1_0;
5697         
5698                         // determine which ship this guy is currently based on
5699 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5700                         mht_init();
5701 #else
5702                         if (Player->on_bastion) {
5703                                 main_hall_init(1);
5704                         } else {
5705                                 main_hall_init(0);
5706                         }
5707 #endif
5708                         break;
5709
5710                 case GS_STATE_BRIEFING:
5711                         main_hall_stop_music();
5712                         main_hall_stop_ambient();
5713                         
5714                         if (Game_mode & GM_NORMAL) {
5715                                 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5716                                 // MWA: or from options or hotkey screens
5717                                 // JH: or if the command brief state already did this
5718                                 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5719                                         && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5720                                         && (old_state != GS_STATE_CMD_BRIEF) ) {
5721                                         if ( !game_start_mission() )                    // this should put us into a new state on failure!
5722                                                 break;
5723                                 }
5724                         }
5725                         // maybe play a movie before the briefing.  don't play if entering briefing screen from ship or weapon select.
5726                         if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5727                                 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5728
5729                         Game_time_compression = F1_0;
5730
5731                         if ( red_alert_mission() ) {
5732                                 gameseq_post_event(GS_EVENT_RED_ALERT);
5733                         } else {
5734                                 brief_init();
5735                         }
5736
5737                         break;
5738
5739                 case GS_STATE_DEBRIEF:
5740                         game_stop_looped_sounds();
5741                         mission_goal_fail_incomplete();                         // fail all incomplete goals before entering debriefing
5742                         if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5743                                 debrief_init();
5744                         }
5745                         break;
5746
5747                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5748                         multi_df_debrief_init();
5749                         break;
5750
5751                 case GS_STATE_LOAD_MISSION_MENU:
5752                         mission_load_menu_init();
5753                         break;
5754
5755                 case GS_STATE_SIMULATOR_ROOM:
5756                         sim_room_init();
5757                         break;
5758
5759                 case GS_STATE_CAMPAIGN_ROOM:
5760                         campaign_room_init();
5761                         break;
5762
5763                 case GS_STATE_RED_ALERT:
5764                         mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5765                         red_alert_init();
5766                         break;
5767
5768                 case GS_STATE_CMD_BRIEF: {
5769                         int team_num = 0;  // team number used as index for which cmd brief to use.
5770
5771                         if (old_state == GS_STATE_OPTIONS_MENU) {
5772                                 cmd_brief_unhold();
5773
5774                         } else {
5775                                 main_hall_stop_music();
5776                                 main_hall_stop_ambient();
5777
5778                                 if (Game_mode & GM_NORMAL) {
5779                                         // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5780                                         // MWA: or from options or hotkey screens
5781                                         // JH: or if the command brief state already did this
5782                                         if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5783                                                 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5784                                                 if ( !game_start_mission() )                    // this should put us into a new state on failure!
5785                                                         break;
5786                                         }
5787                                 }
5788
5789                                 // maybe play a movie before the briefing.  don't play if entering briefing screen from ship or weapon select.
5790                                 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5791                                         mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5792
5793                                 cmd_brief_init(team_num);
5794                         }
5795
5796                         break;
5797                 }
5798
5799                 case GS_STATE_SHIP_SELECT:
5800                         ship_select_init();
5801                         break;
5802
5803                 case GS_STATE_WEAPON_SELECT:
5804                         weapon_select_init();
5805                         break;
5806
5807                 case GS_STATE_TEAM_SELECT:              
5808                         multi_ts_init();
5809                         break;
5810
5811                 case GS_STATE_GAME_PAUSED:
5812                         game_stop_time();
5813                         pause_init(0);
5814                         break;
5815
5816                 case GS_STATE_DEBUG_PAUSED:
5817         //              game_stop_time();
5818         //              os_set_title("FreeSpace - PAUSED");
5819         //              break;
5820         //
5821                 case GS_STATE_TRAINING_PAUSED:
5822                         #ifndef NDEBUG
5823                                 game_stop_time();
5824                                 pause_debug_init();
5825                         #endif
5826                         break;
5827
5828                 case GS_STATE_OPTIONS_MENU:
5829                         //game_stop_time();
5830                         options_menu_init();
5831                         break;
5832  
5833                 case GS_STATE_GAME_PLAY:
5834                         // coming from the gameplay state or the main menu, we might need to load the mission
5835                         if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5836                                 if ( !game_start_mission() )            // this should put us into a new state.
5837                                         // Failed!!!
5838                                         break;
5839                         }
5840
5841                         // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5842                         // case of quick start), then do bitmap loads, etc  Don't do any of the loading stuff
5843                         // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5844                         if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5845                                 (old_state == GS_STATE_WEAPON_SELECT) || (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_MULTI_STD_WAIT)    || (old_state == GS_STATE_SIMULATOR_ROOM) ) {
5846                                         // JAS: Used to do all paging here.
5847
5848                                         #ifndef NDEBUG
5849                                         //XSTR:OFF
5850                                                 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5851                                         //XSTR:ON
5852                                         #endif
5853
5854                                         main_hall_stop_music();
5855                                         main_hall_stop_ambient();
5856                                         event_music_first_pattern();    // start the first pattern
5857                         }
5858
5859                         // special code that restores player ship selection and weapons loadout when doing a quick start
5860                         if ( !(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP)  || (old_state == GS_STATE_GAME_PLAY) ) {
5861                                 if ( !stricmp(Player_loadout.filename, Game_current_mission_filename) ) {
5862                                         wss_direct_restore_loadout();
5863                                 }
5864                         }
5865
5866                         // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5867                         if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5868                                 event_music_first_pattern();    // start the first pattern
5869                         }
5870
5871                         if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5872                                 event_music_first_pattern();    // start the first pattern
5873                         }                       
5874                         player_restore_target_and_weapon_link_prefs();
5875
5876                         Game_mode |= GM_IN_MISSION;
5877
5878 #ifndef NDEBUG
5879                         // required to truely make mouse deltas zeroed in debug mouse code
5880 void mouse_force_pos(int x, int y);
5881                         mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5882 #endif
5883
5884                         game_flush();
5885
5886                         // only start time if in single player, or coming from multi wait state
5887                         if (
5888                                         (
5889                                                 (Game_mode & GM_NORMAL) && 
5890                                                 (old_state != GS_STATE_VIEW_CUTSCENES)
5891                                         ) || (
5892                                                 (Game_mode & GM_MULTIPLAYER) && (
5893                                                         (old_state == GS_STATE_MULTI_PAUSED) ||
5894                                                         (old_state == GS_STATE_MULTI_MISSION_SYNC)
5895                                                 )
5896                                         )
5897                                 )
5898                                         game_start_time();
5899
5900                         // when coming from the multi paused state, reset the timestamps
5901                         if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5902                                 multi_reset_timestamps();
5903                         }
5904
5905                         if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5906                                 // initialize all object update details
5907                                 multi_oo_gameplay_init();
5908                         }
5909         
5910                         // under certain circumstances, the server should reset the object update rate limiting stuff
5911                         if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5912                                  (old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC) ){
5913                                 
5914                                 // reinitialize the rate limiting system for all clients
5915                                 multi_oo_rate_init_all();
5916                         }
5917
5918                         // multiplayer clients should always re-initialize their control info rate limiting system                      
5919                         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5920                                 multi_oo_rate_init_all();
5921                         }
5922                         
5923                         // reset ping times
5924                         if(Game_mode & GM_MULTIPLAYER){
5925                                 multi_ping_reset_players();
5926                         }
5927
5928                         Game_subspace_effect = 0;
5929                         if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5930                                 Game_subspace_effect = 1;
5931                                 if( !(Game_mode & GM_STANDALONE_SERVER) ){      
5932                                         game_start_subspace_ambient_sound();
5933                                 }
5934                         }
5935
5936                         sound_env_set(&Game_sound_env);
5937                         joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5938
5939                         // clear multiplayer button info                        i
5940                         extern button_info Multi_ship_status_bi;
5941                         memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5942                         break;
5943
5944                 case GS_STATE_HUD_CONFIG:
5945                         hud_config_init();
5946                         break;
5947
5948                 case GS_STATE_MULTI_JOIN_GAME:
5949                         multi_join_clear_game_list();
5950
5951                         if (old_state != GS_STATE_OPTIONS_MENU) {
5952                                 multi_join_game_init();
5953                         }
5954
5955                         break;
5956
5957                 case GS_STATE_MULTI_HOST_SETUP:         
5958                         // don't reinitialize if we're coming back from the host options screen
5959                         if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
5960                                 multi_create_game_init();
5961                         }
5962
5963                         break;
5964
5965                 case GS_STATE_MULTI_CLIENT_SETUP:               
5966                         if (old_state != GS_STATE_OPTIONS_MENU) {
5967                                 multi_game_client_setup_init();
5968                         }
5969
5970                         break;
5971
5972                 case GS_STATE_CONTROL_CONFIG:
5973                         control_config_init();
5974                         break;
5975
5976                 case GS_STATE_TECH_MENU:
5977                         techroom_init();
5978                         break;
5979
5980                 case GS_STATE_BARRACKS_MENU:
5981                         if(old_state != GS_STATE_VIEW_MEDALS){
5982                                 barracks_init();
5983                         }
5984                         break;
5985
5986                 case GS_STATE_MISSION_LOG_SCROLLBACK:
5987                         hud_scrollback_init();
5988                         break;
5989
5990                 case GS_STATE_DEATH_DIED:
5991                         Player_died_time = timestamp(10);
5992
5993                         if(!(Game_mode & GM_MULTIPLAYER)){
5994                                 player_show_death_message();
5995                         }
5996                         Game_mode |= GM_DEAD_DIED;
5997                         break;
5998
5999                 case GS_STATE_DEATH_BLEW_UP:
6000                         if ( !popupdead_is_active() ) {
6001                                 Player_ai->target_objnum = -1;
6002                         }
6003
6004                         // stop any local EMP effect
6005                         emp_stop_local();
6006
6007                         Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING;      //      Prevent immediate switch to a hostile ship.
6008                         Game_mode |= GM_DEAD_BLEW_UP;           
6009                         Show_viewing_from_self = 0;
6010
6011                         // timestamp how long we should wait before displaying the died popup
6012                         if ( !popupdead_is_active() ) {
6013                                 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6014                         }
6015                         break;
6016
6017                 case GS_STATE_GAMEPLAY_HELP:
6018                         gameplay_help_init();
6019                         break;
6020
6021                 case GS_STATE_CREDITS:
6022                         main_hall_stop_music();
6023                         main_hall_stop_ambient();
6024                         credits_init();
6025                         break;
6026
6027                 case GS_STATE_VIEW_MEDALS:
6028                         medal_main_init(Player);
6029                         break;
6030
6031                 case GS_STATE_SHOW_GOALS:
6032                         mission_show_goals_init();
6033                         break;
6034
6035                 case GS_STATE_HOTKEY_SCREEN:
6036                         mission_hotkey_init();
6037                         break;
6038
6039                 case GS_STATE_MULTI_MISSION_SYNC:
6040                         // if we're coming from the options screen, don't do any
6041                         if(old_state == GS_STATE_OPTIONS_MENU){
6042                                 break;
6043                         }
6044
6045                         switch(Multi_sync_mode){
6046                         case MULTI_SYNC_PRE_BRIEFING:
6047                                 // if moving from game forming to the team select state                                         
6048                                 multi_sync_init();                      
6049                                 break;
6050                         case MULTI_SYNC_POST_BRIEFING:
6051                                 // if moving from briefing into the mission itself                      
6052                                 multi_sync_init();
6053                         
6054                                 // tell everyone that we're now loading data
6055                                 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6056                                 send_netplayer_update_packet();
6057
6058                                 // JAS: Used to do all paging here!!!!
6059                                                                 
6060                                 Net_player->state = NETPLAYER_STATE_WAITING;                    
6061                                 send_netplayer_update_packet();                         
6062                                 Missiontime = 0;
6063                                 Game_time_compression = F1_0;
6064                                 break;
6065                         case MULTI_SYNC_INGAME:
6066                                 multi_sync_init();
6067                                 break;
6068                         }
6069                         break;          
6070    
6071                 case GS_STATE_VIEW_CUTSCENES:
6072                         cutscenes_screen_init();
6073                         break;
6074
6075                 case GS_STATE_MULTI_STD_WAIT:
6076                         multi_standalone_wait_init();
6077                         break;
6078
6079                 case GS_STATE_STANDALONE_MAIN:
6080                         // don't initialize if we're coming from one of these 2 states unless there are no 
6081                         // players left (reset situation)
6082                         if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6083                                 standalone_main_init();
6084                         }
6085                         break;  
6086
6087                 case GS_STATE_MULTI_PAUSED:
6088                         pause_init(1);
6089                         break;
6090                 
6091                 case GS_STATE_INGAME_PRE_JOIN:
6092                         multi_ingame_select_init();
6093                         break;
6094
6095                 case GS_STATE_STANDALONE_POSTGAME:
6096                         multi_standalone_postgame_init();
6097                         break;
6098
6099                 case GS_STATE_INITIAL_PLAYER_SELECT:
6100                         player_select_init();
6101                         break;          
6102
6103                 case GS_STATE_MULTI_START_GAME:
6104                         multi_start_game_init();
6105                         break;
6106
6107                 case GS_STATE_MULTI_HOST_OPTIONS:
6108                         multi_host_options_init();
6109                         break;          
6110
6111                 case GS_STATE_END_OF_CAMPAIGN:
6112                         mission_campaign_end_init();
6113                         break;          
6114
6115                 case GS_STATE_LOOP_BRIEF:
6116                         loop_brief_init();
6117                         break;
6118
6119         } // end switch
6120 }
6121
6122 // do stuff that may need to be done regardless of state
6123 void game_do_state_common(int state,int no_networking)
6124 {
6125         game_maybe_draw_mouse(flFrametime);             // determine if to draw the mouse this frame
6126         snd_do_frame();                                                         // update sound system
6127         event_music_do_frame();                                         // music needs to play across many states
6128
6129         multi_log_process();    
6130
6131         if (no_networking) {
6132                 return;
6133         }
6134
6135         // maybe do a multiplayer frame based on game mode and state type       
6136         if (Game_mode & GM_MULTIPLAYER) {
6137                 switch (state) {
6138                         case GS_STATE_OPTIONS_MENU:
6139                         case GS_STATE_GAMEPLAY_HELP:
6140                         case GS_STATE_HOTKEY_SCREEN:
6141                         case GS_STATE_HUD_CONFIG:
6142                         case GS_STATE_CONTROL_CONFIG:
6143                         case GS_STATE_MISSION_LOG_SCROLLBACK:
6144                         case GS_STATE_SHOW_GOALS:
6145                         case GS_STATE_VIEW_CUTSCENES:
6146                         case GS_STATE_EVENT_DEBUG:
6147                                 multi_maybe_do_frame();
6148                                 break;
6149                 }
6150                 
6151                 game_do_networking();
6152         }
6153 }
6154
6155 // Called once a frame.
6156 // You should never try to change the state
6157 // in here... if you think you need to, you probably really
6158 // need to post an event, not change the state.
6159 int Game_do_state_should_skip = 0;
6160 void game_do_state(int state)
6161 {
6162         // always lets the do_state_common() function determine if the state should be skipped
6163         Game_do_state_should_skip = 0;
6164         
6165         // legal to set the should skip state anywhere in this function
6166         game_do_state_common(state);    // do stuff that may need to be done regardless of state
6167
6168         if(Game_do_state_should_skip){
6169                 return;
6170         }
6171         
6172         switch (state) {
6173                 case GS_STATE_MAIN_MENU:
6174                         game_set_frametime(GS_STATE_MAIN_MENU);
6175 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6176                         mht_do();
6177 #else
6178                         main_hall_do(flFrametime);
6179 #endif
6180                         break;
6181
6182                 case GS_STATE_OPTIONS_MENU:
6183                         game_set_frametime(GS_STATE_OPTIONS_MENU);
6184                         options_menu_do_frame(flFrametime);
6185                         break;
6186
6187                 case GS_STATE_BARRACKS_MENU:
6188                         game_set_frametime(GS_STATE_BARRACKS_MENU);
6189                         barracks_do_frame(flFrametime);
6190                         break;
6191
6192                 case GS_STATE_TRAINING_MENU:
6193                         game_set_frametime(GS_STATE_TRAINING_MENU);
6194                         training_menu_do_frame(flFrametime);
6195                         break;
6196
6197                 case GS_STATE_TECH_MENU:
6198                         game_set_frametime(GS_STATE_TECH_MENU);
6199                         techroom_do_frame(flFrametime);
6200                         break;
6201
6202                 case GS_STATE_GAMEPLAY_HELP:
6203                         game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6204                         gameplay_help_do_frame(flFrametime);
6205                         break;
6206
6207                 case GS_STATE_GAME_PLAY:        // do stuff that should be done during gameplay
6208                         game_do_frame();
6209                         break;
6210
6211                 case GS_STATE_GAME_PAUSED:
6212                         pause_do(0);
6213                         break;
6214
6215                 case GS_STATE_DEBUG_PAUSED:
6216                         #ifndef NDEBUG
6217                                 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6218                                 pause_debug_do();
6219                         #endif
6220                         break;
6221
6222                 case GS_STATE_TRAINING_PAUSED:
6223                         game_training_pause_do();
6224                         break;
6225
6226                 case GS_STATE_LOAD_MISSION_MENU:
6227                         game_set_frametime(GS_STATE_LOAD_MISSION_MENU);
6228                         mission_load_menu_do();
6229                         break;
6230                 
6231                 case GS_STATE_BRIEFING:
6232                         game_set_frametime(GS_STATE_BRIEFING);
6233                         brief_do_frame(flFrametime);
6234                         break;
6235
6236                 case GS_STATE_DEBRIEF:
6237                         game_set_frametime(GS_STATE_DEBRIEF);
6238                         debrief_do_frame(flFrametime);
6239                         break;
6240
6241                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6242                         game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6243                         multi_df_debrief_do();
6244                         break;
6245
6246                 case GS_STATE_SHIP_SELECT:
6247                         game_set_frametime(GS_STATE_SHIP_SELECT);
6248                         ship_select_do(flFrametime);
6249                         break;
6250
6251                 case GS_STATE_WEAPON_SELECT:
6252                         game_set_frametime(GS_STATE_WEAPON_SELECT);
6253                         weapon_select_do(flFrametime);
6254                         break;
6255
6256                 case GS_STATE_MISSION_LOG_SCROLLBACK:
6257                         game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6258                         hud_scrollback_do_frame(flFrametime);
6259                         break;
6260
6261                 case GS_STATE_HUD_CONFIG:
6262                         game_set_frametime(GS_STATE_HUD_CONFIG);
6263                         hud_config_do_frame(flFrametime);
6264                         break;
6265
6266                 case GS_STATE_MULTI_JOIN_GAME:
6267                         game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6268                         multi_join_game_do_frame();
6269                         break;
6270
6271                 case GS_STATE_MULTI_HOST_SETUP:
6272                         game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6273                         multi_create_game_do();
6274                         break;
6275
6276                 case GS_STATE_MULTI_CLIENT_SETUP:
6277                         game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6278                         multi_game_client_setup_do_frame();
6279                         break;
6280
6281                 case GS_STATE_CONTROL_CONFIG:
6282                         game_set_frametime(GS_STATE_CONTROL_CONFIG);
6283                         control_config_do_frame(flFrametime);
6284                         break;  
6285
6286                 case GS_STATE_DEATH_DIED:
6287                         game_do_frame();                        
6288                         break;
6289
6290                 case GS_STATE_DEATH_BLEW_UP:
6291                         game_do_frame();
6292                         break;
6293
6294                 case GS_STATE_SIMULATOR_ROOM:
6295                         game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6296                         sim_room_do_frame(flFrametime);
6297                         break;
6298
6299                 case GS_STATE_CAMPAIGN_ROOM:
6300                         game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6301                         campaign_room_do_frame(flFrametime);
6302                         break;
6303
6304                 case GS_STATE_RED_ALERT:
6305                         game_set_frametime(GS_STATE_RED_ALERT);
6306                         red_alert_do_frame(flFrametime);
6307                         break;
6308
6309                 case GS_STATE_CMD_BRIEF:
6310                         game_set_frametime(GS_STATE_CMD_BRIEF);
6311                         cmd_brief_do_frame(flFrametime);
6312                         break;
6313
6314                 case GS_STATE_CREDITS:
6315                         game_set_frametime(GS_STATE_CREDITS);
6316                         credits_do_frame(flFrametime);
6317                         break;
6318
6319                 case GS_STATE_VIEW_MEDALS:
6320                         game_set_frametime(GS_STATE_VIEW_MEDALS);
6321                         medal_main_do();
6322                         break;
6323
6324                 case GS_STATE_SHOW_GOALS:
6325                         game_set_frametime(GS_STATE_SHOW_GOALS);
6326                         mission_show_goals_do_frame(flFrametime);
6327                         break;
6328
6329                 case GS_STATE_HOTKEY_SCREEN:
6330                         game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6331                         mission_hotkey_do_frame(flFrametime);
6332                         break;  
6333    
6334                 case GS_STATE_VIEW_CUTSCENES:
6335                         game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6336                         cutscenes_screen_do_frame();
6337                         break;
6338
6339                 case GS_STATE_MULTI_STD_WAIT:
6340                         game_set_frametime(GS_STATE_STANDALONE_MAIN);
6341                         multi_standalone_wait_do();
6342                         break;
6343
6344                 case GS_STATE_STANDALONE_MAIN:
6345                         game_set_frametime(GS_STATE_STANDALONE_MAIN);
6346                         standalone_main_do();
6347                         break;  
6348
6349                 case GS_STATE_MULTI_PAUSED:
6350                         game_set_frametime(GS_STATE_MULTI_PAUSED);
6351                         pause_do(1);
6352                         break;
6353
6354                 case GS_STATE_TEAM_SELECT:
6355                         game_set_frametime(GS_STATE_TEAM_SELECT);
6356                         multi_ts_do();
6357                         break;
6358
6359                 case GS_STATE_INGAME_PRE_JOIN:
6360                         game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6361                         multi_ingame_select_do();
6362                         break;
6363
6364                 case GS_STATE_EVENT_DEBUG:
6365         #ifndef NDEBUG
6366                         game_set_frametime(GS_STATE_EVENT_DEBUG);
6367                         game_show_event_debug(flFrametime);
6368         #endif
6369                         break;
6370
6371                 case GS_STATE_STANDALONE_POSTGAME:
6372                         game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6373                         multi_standalone_postgame_do();
6374                         break;
6375
6376                 case GS_STATE_INITIAL_PLAYER_SELECT:
6377                         game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6378                         player_select_do();
6379                         break;
6380
6381                 case GS_STATE_MULTI_MISSION_SYNC:
6382                         game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6383                         multi_sync_do();
6384                         break;          
6385
6386                 case GS_STATE_MULTI_START_GAME:
6387                         game_set_frametime(GS_STATE_MULTI_START_GAME);
6388                         multi_start_game_do();
6389                         break;
6390                 
6391                 case GS_STATE_MULTI_HOST_OPTIONS:
6392                         game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6393                         multi_host_options_do();
6394                         break;          
6395
6396                 case GS_STATE_END_OF_CAMPAIGN:
6397                         mission_campaign_end_do();
6398                         break;          
6399
6400                 case GS_STATE_END_DEMO:
6401                         game_set_frametime(GS_STATE_END_DEMO);
6402                         end_demo_campaign_do();
6403                         break;
6404
6405                 case GS_STATE_LOOP_BRIEF:
6406                         game_set_frametime(GS_STATE_LOOP_BRIEF);
6407                         loop_brief_do();
6408                         break;
6409
6410    } // end switch(gs_current_state)
6411 }
6412
6413
6414 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6415 int game_do_ram_check(int ram_in_bytes)
6416 {
6417         if ( ram_in_bytes < 30*1024*1024 )      {
6418                 int allowed_to_run = 1;
6419                 if ( ram_in_bytes < 25*1024*1024 ) {
6420                         allowed_to_run = 0;
6421                 }
6422
6423                 char tmp[1024];
6424                 int Freespace_total_ram_MB;
6425                 Freespace_total_ram_MB = fl2i(ram_in_bytes/(1024*1024));
6426
6427                 if ( allowed_to_run ) {
6428
6429                         sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run.  If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE).  Any memory allocated to SmartDrive is not usable by applications\n\nPress 'OK' to continue running with less than the minimum required memory\n", 193), Freespace_total_ram_MB, Freespace_total_ram_MB);
6430
6431                         int msgbox_rval;
6432 #ifndef PLAT_UNIX                       
6433                         msgbox_rval = MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OKCANCEL );
6434                         if ( msgbox_rval == IDCANCEL ) {
6435                                 return -1;
6436                         }
6437 #else
6438                         STUB_FUNCTION;
6439 #endif                  
6440                 } else {
6441                         sprintf( tmp, XSTR( "FreeSpace has detected that you only have %dMB of free memory.\n\nFreeSpace requires at least 32MB of memory to run.  If you think you have more than %dMB of physical memory, ensure that you aren't running SmartDrive (SMARTDRV.EXE).  Any memory allocated to SmartDrive is not usable by applications\n", 195), Freespace_total_ram_MB, Freespace_total_ram_MB);
6442 #ifndef PLAT_UNIX
6443                         MessageBox( NULL, tmp, XSTR( "Not Enough RAM", 194), MB_OK );
6444 #else
6445                         STUB_FUNCTION;
6446 #endif                  
6447                         return -1;
6448                 }
6449         }
6450
6451         return 0;
6452 }
6453
6454 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6455 // If so, copy it over and remove the update directory.
6456 void game_maybe_update_launcher(char *exe_dir)
6457 {
6458 #ifndef PLAT_UNIX
6459         char src_filename[MAX_PATH];
6460         char dest_filename[MAX_PATH];
6461
6462         strcpy(src_filename, exe_dir);
6463         strcat(src_filename, NOX("\\update\\freespace.exe"));
6464
6465         strcpy(dest_filename, exe_dir);
6466         strcat(dest_filename, NOX("\\freespace.exe"));
6467
6468         // see if src_filename exists
6469         FILE *fp;
6470         fp = fopen(src_filename, "rb");
6471         if ( !fp ) {
6472                 return;
6473         }
6474         fclose(fp);
6475
6476         SetFileAttributes(dest_filename, FILE_ATTRIBUTE_NORMAL);
6477
6478         // copy updated freespace.exe to freespace exe dir
6479         if ( CopyFile(src_filename, dest_filename, 0) == 0 ) {
6480                 MessageBox( NULL, XSTR("Unable to copy freespace.exe from update directory to installed directory.  You should copy freespace.exe from the update directory (located in your FreeSpace install directory) to your install directory", 988), NULL, MB_OK|MB_TASKMODAL|MB_SETFOREGROUND );
6481                 return;
6482         }
6483
6484         // delete the file in the update directory
6485         DeleteFile(src_filename);
6486
6487         // safe to assume directory is empty, since freespace.exe should only be the file ever in the update dir
6488         char update_dir[MAX_PATH];
6489         strcpy(update_dir, exe_dir);
6490         strcat(update_dir, NOX("\\update"));
6491         RemoveDirectory(update_dir);
6492 #else
6493         STUB_FUNCTION;
6494 #endif  
6495 }
6496
6497 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6498 {
6499         int i;
6500         int sub_total = 0;
6501         int sub_total_destroyed = 0;
6502         int total = 0;
6503         char str[255] = "";             
6504         
6505         // get the total for all his children
6506         for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling )   {
6507                 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6508         }       
6509
6510         // find the # of faces for this _individual_ object     
6511         total = submodel_get_num_polys(model_num, sm);
6512         if(strstr(pm->submodel[sm].name, "-destroyed")){
6513                 sub_total_destroyed = total;
6514         }
6515         
6516         // write out total
6517         sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6518         cfputs(str, out);               
6519
6520         *out_total += total + sub_total;
6521         *out_destroyed_total += sub_total_destroyed;
6522 }
6523
6524 #define BAIL()                  do { int idx; for(idx=0; idx<num_files; idx++){ if(pof_list[idx] != NULL){free(pof_list[idx]); pof_list[idx] = NULL;}} return;} while(0);
6525 void game_spew_pof_info()
6526 {
6527         char *pof_list[1000];
6528         int num_files;  
6529         CFILE *out;
6530         int idx, model_num, i, j;
6531         polymodel *pm;
6532         int total, root_total, model_total, destroyed_total, counted;
6533         char str[255] = "";
6534
6535         // get file list
6536         num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6537
6538         // spew info on all the pofs
6539         if(!num_files){
6540                 return;
6541         }
6542
6543         // go
6544         out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6545         if(out == NULL){
6546                 BAIL();
6547         }       
6548         counted = 0;    
6549         for(idx=0; idx<num_files; idx++, counted++){
6550                 sprintf(str, "%s.pof", pof_list[idx]);
6551                 model_num = model_load(str, 0, NULL);
6552                 if(model_num >= 0){
6553                         pm = model_get(model_num);
6554
6555                         // if we have a real model
6556                         if(pm != NULL){                         
6557                                 cfputs(str, out);
6558                                 cfputs("\n", out);
6559                                 
6560                                 // go through and print all raw submodels
6561                                 cfputs("RAW\n", out);
6562                                 total = 0;
6563                                 model_total = 0;                                
6564                                 for (i=0; i<pm->n_models; i++)  {                                       
6565                                         total = submodel_get_num_polys(model_num, i);                                   
6566                                         
6567                                         model_total += total;
6568                                         sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6569                                         cfputs(str, out);
6570                                 }                               
6571                                 sprintf(str, "Model total %d\n", model_total);                          
6572                                 cfputs(str, out);                               
6573
6574                                 // now go through and do it by LOD
6575                                 cfputs("BY LOD\n\n", out);                              
6576                                 for(i=0; i<pm->n_detail_levels; i++){
6577                                         sprintf(str, "LOD %d\n", i);
6578                                         cfputs(str, out);
6579
6580                                         // submodels
6581                                         root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6582                                         total = 0;
6583                                         destroyed_total = 0;
6584                                         for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling )        {
6585                                                 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6586                                         }
6587
6588                                         sprintf(str, "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6589                                         cfputs(str, out);
6590
6591                                         sprintf(str, "TOTAL: %d\n", total + root_total);                                        
6592                                         cfputs(str, out);
6593                                         sprintf(str, "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6594                                         cfputs(str, out);
6595                                         sprintf(str, "TOTAL destroyed faces %d\n\n", destroyed_total);
6596                                         cfputs(str, out);
6597                                 }                               
6598                                 cfputs("------------------------------------------------------------------------\n\n", out);                            
6599                         }
6600                 }
6601
6602                 if(counted >= MAX_POLYGON_MODELS - 5){
6603                         model_free_all();
6604                         counted = 0;
6605                 }
6606         }
6607
6608         cfclose(out);
6609         model_free_all();
6610         BAIL();
6611 }
6612
6613 DCF(pofspew, "")
6614 {
6615         game_spew_pof_info();
6616 }
6617
6618 int PASCAL WinMainSub(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6619 {
6620         int state;              
6621
6622 #ifndef PLAT_UNIX
6623         // Don't let more than one instance of Freespace run.
6624         HWND hwnd = FindWindow( NOX( "FreeSpaceClass" ), NULL );
6625         if ( hwnd )     {
6626                 SetForegroundWindow(hwnd);
6627                 return 0;
6628         }
6629 #endif
6630
6631         // Find out how much RAM is on this machine
6632 #ifndef PLAT_UNIX
6633         MEMORYSTATUS ms;
6634         ms.dwLength = sizeof(MEMORYSTATUS);
6635         GlobalMemoryStatus(&ms);
6636         Freespace_total_ram = ms.dwTotalPhys;
6637
6638         if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6639                 return 0;
6640         }
6641
6642         if ( ms.dwTotalVirtual < 1024 ) {
6643                 MessageBox( NULL, XSTR( "FreeSpace requires virtual memory to run.\r\n", 196), XSTR( "No Virtual Memory", 197), MB_OK );
6644                 return 0;
6645         }
6646
6647         if (!vm_init(24*1024*1024)) {
6648                 MessageBox( NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK );
6649                 return 0;
6650         }
6651                 
6652         char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6653         if (!tmp_mem) {
6654                 MessageBox(NULL, XSTR( "Not enough memory to run Freespace.\r\nTry closing down some other applications.\r\n", 198), XSTR( "Not Enough Memory", 199), MB_OK);
6655                 return 0;
6656         }
6657
6658         free(tmp_mem);
6659         tmp_mem = NULL;
6660 #else
6661         STUB_FUNCTION;
6662 #endif
6663         
6664 /* this code doesn't work, and we will hit an error about being unable to load the direct draw
6665         dll before we get here anyway if it's not installed (unless we load it manually, which doesn't
6666         seem worth bothering with.
6667
6668         LONG lResult;
6669
6670         lResult = RegOpenKeyEx(
6671                 HKEY_LOCAL_MACHINE,                                     // Where it is
6672                 "Software\\Microsoft\\DirectX", // name of key
6673                 NULL,                                                                           // DWORD reserved
6674                 KEY_QUERY_VALUE,                                                // Allows all changes
6675                 &hKey                                                                           // Location to store key
6676         );
6677
6678         if (lResult == ERROR_SUCCESS) {
6679                 char version[32];
6680                 DWORD dwType, dwLen;
6681
6682                 dwLen = 32;
6683                 lResult = RegQueryValueEx(
6684                         hKey,                                                                   // Handle to key
6685                         "Version",                                                      // The values name
6686                         NULL,                                                                   // DWORD reserved
6687                         &dwType,                                                                // What kind it is
6688                         (ubyte *) version,                              // value to set
6689                         &dwLen                                                          // How many bytes to set
6690                 );
6691
6692                 if (lResult == ERROR_SUCCESS) {
6693                         dx_version = atoi(strstr(version, ".") + 1);
6694
6695                 } else {
6696                         int val;
6697                         DWORD dwType, dwLen;
6698
6699                         dwLen = 4;
6700                         lResult = RegQueryValueEx(
6701                                 hKey,                                                                   // Handle to key
6702                                 "InstalledVersion",                             // The values name
6703                                 NULL,                                                                   // DWORD reserved
6704                                 &dwType,                                                                // What kind it is
6705                                 (ubyte *) &val,                                 // value to set
6706                                 &dwLen                                                          // How many bytes to set
6707                         );
6708
6709                         if (lResult == ERROR_SUCCESS) {
6710                                 dx_version = val;
6711                         }
6712                 }
6713
6714                 RegCloseKey(hKey);
6715         }
6716
6717         if (dx_version < 3) {
6718                 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected.  You can get the\n"
6719                         "latest version of DirectX at:\n\n"
6720                         "http://www.microsoft.com/msdownload/directx/dxf/enduser5.0/default.htm", "DirectX required", MB_OK);
6721
6722                 MessageBox(NULL, "DirectX 3.0 or higher is required and wasn't detected.  You can install\n"
6723                         "DirectX 5.2 by pressing the 'Install DirectX' button on the FreeSpace Launcher", "DirectX required", MB_OK);
6724
6725                 return 0;
6726         }
6727 */
6728         //=====================================================
6729         // Make sure we're running in the right directory.
6730 #ifndef PLAT_UNIX
6731         char exe_dir[1024];
6732
6733         if ( GetModuleFileName( hInst, exe_dir, 1023 ) > 0 )    {
6734                 char *p = exe_dir + strlen(exe_dir);
6735
6736                 // chop off the filename
6737                 while( (p>exe_dir) && (*p!='\\') && (*p!='/') && (*p!=':') )    {
6738                         p--;
6739                 }
6740                 *p = 0;
6741
6742                 // Set directory
6743                 if ( strlen(exe_dir) > 0 )      {
6744                         SetCurrentDirectory(exe_dir);
6745                 }
6746
6747                 // check for updated freespace.exe
6748                 game_maybe_update_launcher(exe_dir);
6749         }
6750 #else
6751         STUB_FUNCTION;
6752 #endif
6753         
6754         #ifndef NDEBUG                          
6755         {
6756                 extern void windebug_memwatch_init();
6757                 windebug_memwatch_init();
6758         }
6759         #endif
6760         
6761         parse_cmdline(szCmdLine);       
6762
6763 #ifdef STANDALONE_ONLY_BUILD
6764         Is_standalone = 1;
6765         nprintf(("Network", "Standalone running"));
6766 #else
6767         if (Is_standalone){
6768                 nprintf(("Network", "Standalone running"));
6769         }
6770 #endif
6771
6772         init_cdrom();
6773         game_init();
6774         game_stop_time();
6775
6776         // maybe spew pof stuff
6777         if(Cmdline_spew_pof_info){
6778                 game_spew_pof_info();
6779                 game_shutdown();
6780                 return 1;
6781         }
6782
6783         // non-demo, non-standalone, play the intro movie
6784         if(!Is_standalone){
6785 #ifndef DEMO
6786 #ifdef RELEASE_REAL
6787                 char *plist[5];
6788                 if( (cf_get_file_list(2, plist, CF_TYPE_MULTI_PLAYERS, NOX("*.plr"))    <= 0) && (cf_get_file_list(2, plist, CF_TYPE_SINGLE_PLAYERS, NOX("*.plr"))      <= 0) ){
6789                         // prompt for cd 2
6790 #if defined(OEM_BUILD)
6791                         game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
6792 #else
6793                         game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
6794 #endif // defined(OEM_BUILD)
6795                 }
6796 #endif
6797         }
6798
6799         if ( !Is_standalone ) {
6800
6801                 // release -- movies always play
6802                 #if defined(NDEBUG)
6803
6804                 // in RELEASE_REAL builds make the user stick in CD2 if there are no pilots on disk so that we guarantee he plays the movie
6805                 // no soup for you!
6806                 // movie_play( NOX("intro.mve"), 0 );
6807
6808                 // debug version, movie will only play with -showmovies
6809                 #elif !defined(NDEBUG)
6810                 
6811                 // no soup for you!
6812                 // movie_play( NOX("intro.mve"), 0);
6813 /*
6814 #ifndef NDEBUG
6815                 if ( Cmdline_show_movies )
6816                         movie_play( NOX("intro.mve"), 0 );
6817 #endif
6818 */
6819                 #endif
6820         }
6821
6822 #endif  
6823
6824         if (Is_standalone){
6825                 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6826         } else {
6827                 gameseq_post_event(GS_EVENT_GAME_INIT);         // start the game rolling -- check for default pilot, or go to the pilot select screen
6828         }
6829
6830         while (1) {
6831                 // only important for non THREADED mode
6832                 os_poll();
6833
6834                 state = gameseq_process_events();
6835                 if ( state == GS_STATE_QUIT_GAME ){
6836                         break;
6837                 }
6838         } 
6839
6840 #ifdef FS2_DEMO
6841         if(!Is_standalone){
6842                 demo_upsell_show_screens();
6843         }
6844 #elif defined(OEM_BUILD)
6845         // show upsell screens on exit
6846         oem_upsell_show_screens();
6847 #endif
6848
6849         game_shutdown();
6850         return 1;
6851 }
6852
6853 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
6854 {
6855         int result = -1;
6856 #ifndef PLAT_UNIX
6857         __try
6858         {
6859                 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6860         }
6861         __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
6862         {
6863                 // Do nothing here - RecordExceptionInfo() has already done
6864                 // everything that is needed. Actually this code won't even
6865                 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
6866                 // the __except clause.
6867         }
6868         return result;
6869 #else
6870         STUB_FUNCTION;
6871         
6872         fprintf(stderr, "WinMain: exceptions shall fall through\n");
6873         result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
6874 #endif  
6875 }
6876
6877 // launcher the fslauncher program on exit
6878 void game_launch_launcher_on_exit()
6879 {
6880 #ifndef PLAT_UNIX
6881         STARTUPINFO si;
6882         PROCESS_INFORMATION pi;
6883         char cmd_line[2048];
6884         char original_path[1024] = "";
6885         
6886         memset( &si, 0, sizeof(STARTUPINFO) );
6887         si.cb = sizeof(si);
6888
6889         // directory
6890         _getcwd(original_path, 1023);
6891
6892         // set up command line
6893         strcpy(cmd_line, original_path);
6894         strcat(cmd_line, "\\");
6895         strcat(cmd_line, LAUNCHER_FNAME);
6896         strcat(cmd_line, " -straight_to_update");               
6897
6898         BOOL ret = CreateProcess(       NULL,                                                                   // pointer to name of executable module 
6899                                                                                 cmd_line,                                                       // pointer to command line string
6900                                                                                 NULL,                                                                   // pointer to process security attributes 
6901                                                                                 NULL,                                                                   // pointer to thread security attributes 
6902                                                                                 FALSE,                                                          // handle inheritance flag 
6903                                                                                 CREATE_DEFAULT_ERROR_MODE,              // creation flags 
6904                                                                                 NULL,                                                                   // pointer to new environment block 
6905                                                                                 NULL,                                                                   // pointer to current directory name 
6906                                                                                 &si,                                                                    // pointer to STARTUPINFO 
6907                                                                                 &pi                                                                     // pointer to PROCESS_INFORMATION  
6908                                                                                 );                      
6909         // to eliminate build warnings
6910         ret;
6911 #else
6912         STUB_FUNCTION;
6913 #endif          
6914 }
6915
6916
6917 // game_shutdown()
6918 //
6919 // This function is called when FreeSpace terminates normally.  
6920 //
6921 void game_shutdown(void)
6922 {
6923 #ifndef PLAT_UNIX
6924         timeEndPeriod(1);
6925 #endif
6926
6927         // don't ever flip a page on the standalone!
6928         if(!(Game_mode & GM_STANDALONE_SERVER)){
6929                 gr_reset_clip();
6930                 gr_clear();
6931                 gr_flip();
6932         }
6933
6934    // if the player has left the "player select" screen and quit the game without actually choosing
6935         // a player, Player will be NULL, in which case we shouldn't write the player file out!
6936         if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6937                 write_pilot_file();
6938         }
6939
6940         // load up common multiplayer icons
6941         multi_unload_common_icons();
6942         
6943         shockwave_close();                      // release any memory used by shockwave system  
6944         fireball_close();                               // free fireball system
6945         ship_close();                                   // free any memory that was allocated for the ships
6946         hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6947         unload_animating_pointer();// frees the frames used for the animating mouse pointer
6948         bm_unload_all();                                // free bitmaps
6949         mission_campaign_close();       // close out the campaign stuff
6950         multi_voice_close();                    // close down multiplayer voice (including freeing buffers, etc)
6951         multi_log_close();
6952 #ifdef MULTI_USE_LAG
6953         multi_lag_close();
6954 #endif
6955
6956         // the menu close functions will unload the bitmaps if they were displayed during the game
6957 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6958         main_hall_close();
6959 #endif
6960         training_menu_close();
6961         gr_close();
6962
6963         extern void joy_close();
6964         joy_close();
6965
6966         audiostream_close();
6967         snd_close();
6968         event_music_close();
6969         psnet_close();
6970         os_cleanup();
6971
6972         // HACKITY HACK HACK
6973         // if this flag is set, we should be firing up the launcher when exiting freespace
6974         extern int Multi_update_fireup_launcher_on_exit;
6975         if(Multi_update_fireup_launcher_on_exit){
6976                 game_launch_launcher_on_exit();
6977         }
6978 }
6979
6980 // game_stop_looped_sounds()
6981 //
6982 // This function will call the appropriate stop looped sound functions for those
6983 // modules which use looping sounds.  It is not enough just to stop a looping sound
6984 // at the DirectSound level, the game is keeping track of looping sounds, and this
6985 // function is used to inform the game that looping sounds are being halted.
6986 //
6987 void game_stop_looped_sounds()
6988 {
6989         hud_stop_looped_locking_sounds();
6990         hud_stop_looped_engine_sounds();
6991         afterburner_stop_sounds();
6992         player_stop_looped_sounds();
6993         obj_snd_stop_all();             // stop all object-linked persistant sounds
6994         game_stop_subspace_ambient_sound();
6995         snd_stop(Radar_static_looping);
6996         Radar_static_looping = -1;
6997         snd_stop(Target_static_looping);
6998         shipfx_stop_engine_wash_sound();
6999         Target_static_looping = -1;
7000 }
7001
7002 //////////////////////////////////////////////////////////////////////////
7003 //
7004 // Code for supporting an animating mouse pointer
7005 //
7006 //
7007 //////////////////////////////////////////////////////////////////////////
7008
7009 typedef struct animating_obj
7010 {
7011         int     first_frame;
7012         int     num_frames;
7013         int     current_frame;
7014         float time;
7015         float elapsed_time;
7016 } animating_obj;
7017
7018 static animating_obj Animating_mouse;
7019
7020 // ----------------------------------------------------------------------------
7021 // init_animating_pointer()
7022 //
7023 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7024 // gets properly initialized
7025 //
7026 void init_animating_pointer()
7027 {
7028         Animating_mouse.first_frame     = -1;
7029         Animating_mouse.num_frames              = 0;
7030         Animating_mouse.current_frame   = -1;
7031         Animating_mouse.time                            = 0.0f;
7032         Animating_mouse.elapsed_time    = 0.0f;
7033 }
7034
7035 // ----------------------------------------------------------------------------
7036 // load_animating_pointer()
7037 //
7038 // Called at game init to load in the frames for the animating mouse pointer
7039 //
7040 // input:       filename        =>      filename of animation file that holds the animation
7041 // 
7042 void load_animating_pointer(char *filename, int dx, int dy)
7043 {
7044         int                             fps;
7045         animating_obj *am;
7046
7047         init_animating_pointer();
7048
7049         am = &Animating_mouse;
7050         am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7051         if ( am->first_frame == -1 ) 
7052                 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7053         am->current_frame = 0;
7054         am->time = am->num_frames / i2fl(fps);
7055 }
7056
7057 // ----------------------------------------------------------------------------
7058 // unload_animating_pointer()
7059 //
7060 // Called at game shutdown to free the memory used to store the animation frames
7061 //
7062 void unload_animating_pointer()
7063 {
7064         int                             i;
7065         animating_obj   *am;
7066
7067         am = &Animating_mouse;
7068         for ( i = 0; i < am->num_frames; i++ ) {
7069                 Assert( (am->first_frame+i) >= 0 );
7070                 bm_release(am->first_frame + i);
7071         }
7072
7073         am->first_frame = -1;
7074         am->num_frames          = 0;
7075         am->current_frame = -1;
7076 }
7077
7078 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7079 void game_render_mouse(float frametime)
7080 {
7081         int                             mx, my;
7082         animating_obj   *am;
7083
7084         // if animating cursor exists, play the next frame
7085         am = &Animating_mouse;
7086         if ( am->first_frame != -1 ) {
7087                 mouse_get_pos(&mx, &my);
7088                 am->elapsed_time += frametime;
7089                 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7090                 if ( am->current_frame >= am->num_frames ) {
7091                         am->current_frame = 0;
7092                         am->elapsed_time = 0.0f;
7093                 }
7094                 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7095         }
7096 }
7097
7098 // ----------------------------------------------------------------------------
7099 // game_maybe_draw_mouse()
7100 //
7101 // determines whether to draw the mouse pointer at all, and what frame of
7102 // animation to use if the mouse is animating
7103 //
7104 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7105 //
7106 // input:       frametime => elapsed frame time in seconds since last call
7107 //
7108 void game_maybe_draw_mouse(float frametime)
7109 {
7110         int game_state;
7111
7112         game_state = gameseq_get_state();
7113
7114         switch ( game_state ) {
7115                 case GS_STATE_GAME_PAUSED:
7116                 // case GS_STATE_MULTI_PAUSED:
7117                 case GS_STATE_GAME_PLAY:
7118                 case GS_STATE_DEATH_DIED:
7119                 case GS_STATE_DEATH_BLEW_UP:
7120                         if ( popup_active() || popupdead_is_active() ) {
7121                                 Mouse_hidden = 0;
7122                         } else {
7123                                 Mouse_hidden = 1;       
7124                         }
7125                         break;
7126
7127                 default:
7128                         Mouse_hidden = 0;
7129                         break;
7130         }       // end switch
7131
7132         if ( !Mouse_hidden ) 
7133                 game_render_mouse(frametime);
7134
7135 }
7136
7137 void game_do_training_checks()
7138 {
7139         int i, s;
7140         float d;
7141         waypoint_list *wplp;
7142
7143         if (Training_context & TRAINING_CONTEXT_SPEED) {
7144                 s = (int) Player_obj->phys_info.fspeed;
7145                 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7146                         if (!Training_context_speed_set) {
7147                                 Training_context_speed_set = 1;
7148                                 Training_context_speed_timestamp = timestamp();
7149                         }
7150
7151                 } else
7152                         Training_context_speed_set = 0;
7153         }
7154
7155         if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7156                 wplp = &Waypoint_lists[Training_context_path];
7157                 if (wplp->count > Training_context_goal_waypoint) {
7158                         i = Training_context_goal_waypoint;
7159                         do {
7160                                 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7161                                 if (d <= Training_context_distance) {
7162                                         Training_context_at_waypoint = i;
7163                                         if (Training_context_goal_waypoint == i) {
7164                                                 Training_context_goal_waypoint++;
7165                                                 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7166                                         }
7167
7168                                         break;
7169                                 }
7170
7171                                 i++;
7172                                 if (i == wplp->count)
7173                                         i = 0;
7174
7175                         } while (i != Training_context_goal_waypoint);
7176                 }
7177         }
7178
7179         if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7180                 Players_target = Player_ai->target_objnum;
7181                 Players_targeted_subsys = Player_ai->targeted_subsys;
7182                 Players_target_timestamp = timestamp();
7183         }
7184 }
7185
7186 /////////// Following is for event debug view screen
7187
7188 #ifndef NDEBUG
7189
7190 #define EVENT_DEBUG_MAX 5000
7191 #define EVENT_DEBUG_EVENT 0x8000
7192
7193 int Event_debug_index[EVENT_DEBUG_MAX];
7194 int ED_count;
7195
7196 void game_add_event_debug_index(int n, int indent)
7197 {
7198         if (ED_count < EVENT_DEBUG_MAX)
7199                 Event_debug_index[ED_count++] = n | (indent << 16);
7200 }
7201
7202 void game_add_event_debug_sexp(int n, int indent)
7203 {
7204         if (n < 0)
7205                 return;
7206
7207         if (Sexp_nodes[n].first >= 0) {
7208                 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7209                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7210                 return;
7211         }
7212
7213         game_add_event_debug_index(n, indent);
7214         if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7215                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7216         else
7217                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7218 }
7219
7220 void game_event_debug_init()
7221 {
7222         int e;
7223
7224         ED_count = 0;
7225         for (e=0; e<Num_mission_events; e++) {
7226                 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7227                 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7228         }
7229 }
7230
7231 void game_show_event_debug(float frametime) 
7232 {
7233         char buf[256];
7234         int i, k, z;
7235         int font_height, font_width;    
7236         int y_index, y_max;
7237         static int scroll_offset = 0;
7238         
7239         k = game_check_key();
7240         if (k)
7241                 switch (k) {
7242                         case KEY_UP:
7243                         case KEY_PAD8:
7244                                 scroll_offset--;
7245                                 if (scroll_offset < 0)
7246                                         scroll_offset = 0;
7247                                 break;
7248
7249                         case KEY_DOWN:
7250                         case KEY_PAD2:
7251                                 scroll_offset++;
7252                                 break;
7253
7254                         case KEY_PAGEUP:
7255                                 scroll_offset -= 20;
7256                                 if (scroll_offset < 0)
7257                                         scroll_offset = 0;
7258                                 break;
7259
7260                         case KEY_PAGEDOWN:
7261                                 scroll_offset += 20;    // not font-independent, hard-coded since I counted the lines!
7262                                 break;
7263
7264                         default:
7265                                 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7266                                 key_flush();
7267                                 break;
7268                 } // end switch
7269
7270         gr_clear();
7271         gr_set_color_fast(&Color_bright);
7272         gr_set_font(FONT1);
7273         gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7274
7275         gr_set_color_fast(&Color_normal);
7276         gr_set_font(FONT1);
7277         gr_get_string_size(&font_width, &font_height, NOX("test"));
7278         y_max = gr_screen.max_h - font_height - 5;
7279         y_index = 45;
7280
7281         k = scroll_offset;
7282         while (k < ED_count) {
7283                 if (y_index > y_max)
7284                         break;
7285
7286                 z = Event_debug_index[k];
7287                 if (z & EVENT_DEBUG_EVENT) {
7288                         z &= 0x7fff;
7289                         sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7290                                 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7291                                 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7292                                 Mission_events[z].repeat_count, Mission_events[z].interval);
7293
7294                 } else {
7295                         i = (z >> 16) * 3;
7296                         buf[i] = 0;
7297                         while (i--)
7298                                 buf[i] = ' ';
7299
7300                         strcat(buf, Sexp_nodes[z & 0x7fff].text);
7301                         switch (Sexp_nodes[z & 0x7fff].value) {
7302                                 case SEXP_TRUE:
7303                                         strcat(buf, NOX(" (True)"));
7304                                         break;
7305
7306                                 case SEXP_FALSE:
7307                                         strcat(buf, NOX(" (False)"));
7308                                         break;
7309
7310                                 case SEXP_KNOWN_TRUE:
7311                                         strcat(buf, NOX(" (Always true)"));
7312                                         break;
7313
7314                                 case SEXP_KNOWN_FALSE:
7315                                         strcat(buf, NOX(" (Always false)"));
7316                                         break;
7317
7318                                 case SEXP_CANT_EVAL:
7319                                         strcat(buf, NOX(" (Can't eval)"));
7320                                         break;
7321
7322                                 case SEXP_NAN:
7323                                 case SEXP_NAN_FOREVER:
7324                                         strcat(buf, NOX(" (Not a number)"));
7325                                         break;
7326                         }
7327                 }
7328
7329                 gr_printf(10, y_index, buf);
7330                 y_index += font_height;
7331                 k++;
7332         }
7333
7334         gr_flip();
7335 }
7336
7337 #endif // NDEBUG
7338
7339 #ifndef NDEBUG
7340 FILE * Time_fp;
7341 FILE * Texture_fp;
7342
7343 extern int Tmap_npixels;
7344
7345 int Tmap_num_too_big = 0;
7346 int Num_models_needing_splitting = 0;
7347
7348 void Time_model( int modelnum )
7349 {
7350 //      mprintf(( "Timing ship '%s'\n", si->name ));
7351
7352         vector eye_pos, model_pos;
7353         matrix eye_orient, model_orient;
7354
7355         polymodel *pm = model_get( modelnum );
7356
7357         int l = strlen(pm->filename);
7358         while( (l>0) )  {
7359                 if ( (l == '/') || (l=='\\') || (l==':'))       {
7360                         l++;
7361                         break;
7362                 }
7363                 l--;
7364         }
7365         char *pof_file = &pm->filename[l];
7366
7367         int model_needs_splitting = 0;
7368
7369         //fprintf( Texture_fp, "Model: %s\n", pof_file );
7370         int i;
7371         for (i=0; i<pm->n_textures; i++ )       {
7372                 char filename[1024];
7373                 ubyte pal[768];
7374
7375                 int bmp_num = pm->original_textures[i];
7376                 if ( bmp_num > -1 )     {
7377                         bm_get_palette(pm->original_textures[i], pal, filename );               
7378                         int w,h;
7379                         bm_get_info( pm->original_textures[i],&w, &h );
7380
7381
7382                         if ( (w > 512) || (h > 512) )   {
7383                                 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7384                                 Tmap_num_too_big++;
7385                                 model_needs_splitting++;
7386                         }
7387                 } else {
7388                         //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7389                 }
7390         }
7391
7392         if ( model_needs_splitting )    {
7393                 Num_models_needing_splitting++;
7394         }
7395         eye_orient = model_orient = vmd_identity_matrix;
7396         eye_pos = model_pos = vmd_zero_vector;
7397
7398         eye_pos.z = -pm->rad*2.0f;
7399
7400         vector eye_to_model;
7401
7402         vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7403         vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7404
7405         fix t1 = timer_get_fixed_seconds();
7406
7407         angles ta;
7408         ta.p = ta.b = ta.h = 0.0f; 
7409         int framecount = 0;
7410
7411         Tmap_npixels = 0;
7412
7413         int bitmaps_used_this_frame, bitmaps_new_this_frame;
7414                 
7415         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7416
7417         modelstats_num_polys = modelstats_num_verts = 0;
7418
7419         while( ta.h < PI2 )     {
7420
7421                 matrix m1;
7422                 vm_angles_2_matrix(&m1, &ta );
7423                 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7424
7425                 gr_reset_clip();
7426 //              gr_clear();
7427
7428                 g3_start_frame(1);
7429
7430                 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );       
7431
7432                 model_clear_instance( modelnum );
7433                 model_set_detail_level(0);              // use highest detail level
7434                 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL);     //|MR_NO_POLYS );
7435
7436                 g3_end_frame();
7437 //              gr_flip();
7438
7439                 framecount++;
7440                 ta.h += 0.1f;
7441
7442                 int k = key_inkey();
7443                 if ( k == KEY_ESC ) {
7444                         exit(1);
7445                 }
7446         }
7447
7448         fix t2 = timer_get_fixed_seconds();
7449
7450         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7451         //bitmaps_used_this_frame /= framecount;
7452
7453         modelstats_num_polys /= framecount;
7454         modelstats_num_verts /= framecount;
7455
7456         Tmap_npixels /=framecount;
7457
7458
7459         mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7460         fprintf( Time_fp, "\"%s\"\t%.0f\t%d\t%d\t%d\t%d\n", pof_file, i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts, Tmap_npixels );
7461 //      fprintf( Time_fp, "%.0f\t%d\t%d\t%d\t%d\n", i2fl(framecount)/f2fl(t2-t1), bitmaps_used_this_frame, modelstats_num_polys, modelstats_num_verts, Tmap_npixels );
7462
7463                 
7464 //      key_getch();
7465 }
7466
7467 int Time_models = 0;
7468 DCF_BOOL( time_models, Time_models );
7469
7470 void Do_model_timings_test()
7471 {
7472         
7473
7474         if ( !Time_models ) return;
7475
7476         mprintf(( "Timing models!\n" ));
7477
7478         int i;
7479
7480         ubyte model_used[MAX_POLYGON_MODELS];
7481         int model_id[MAX_POLYGON_MODELS];
7482         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7483                 model_used[i] = 0;
7484         }
7485         
7486         // Load them all
7487         for (i=0; i<Num_ship_types; i++ )       {
7488                 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, NULL, NULL );
7489
7490                 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7491                 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7492         }
7493
7494         Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7495         if ( !Texture_fp ) return;
7496
7497         Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7498         if ( !Time_fp ) return;
7499
7500         fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7501 //      fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7502         
7503         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7504                 if ( model_used[i] )    {
7505                         Time_model( model_id[i] );
7506                 }
7507         }
7508         
7509         fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7510         fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7511         
7512         fclose(Time_fp);
7513         fclose(Texture_fp);
7514
7515         exit(1);
7516 }
7517 #endif
7518
7519 // Call this function when you want to inform the player that a feature is not
7520 // enabled in the DEMO version of FreSpace
7521 void game_feature_not_in_demo_popup()
7522 {
7523         popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7524 }
7525
7526 // format the specified time (fixed point) into a nice string
7527 void game_format_time(fix m_time,char *time_str)
7528 {
7529         float mtime;
7530         int hours,minutes,seconds;
7531         char tmp[10];
7532
7533         mtime = f2fl(m_time);           
7534
7535         // get the hours, minutes and seconds   
7536         hours = (int)(mtime / 3600.0f);
7537         if(hours > 0){
7538                 mtime -= (3600.0f * (float)hours);
7539         }
7540         seconds = (int)mtime%60;
7541         minutes = (int)mtime/60;                        
7542
7543         // print the hour if necessary
7544         if(hours > 0){          
7545                 sprintf(time_str,XSTR( "%d:", 201),hours);
7546                 // if there are less than 10 minutes, print a leading 0
7547                 if(minutes < 10){
7548                         strcpy(tmp,NOX("0"));
7549                         strcat(time_str,tmp);
7550                 }               
7551         }       
7552         
7553         // print the minutes
7554         if(hours){
7555                 sprintf(tmp,XSTR( "%d:", 201),minutes);
7556                 strcat(time_str,tmp);
7557         } else {
7558                 sprintf(time_str,XSTR( "%d:", 201),minutes);
7559         }
7560
7561         // print the seconds
7562         if(seconds < 10){
7563                 strcpy(tmp,NOX("0"));
7564                 strcat(time_str,tmp);
7565         } 
7566         sprintf(tmp,"%d",seconds);
7567         strcat(time_str,tmp);
7568 }
7569
7570 //      Stuff version string in *str.
7571 void get_version_string(char *str)
7572 {
7573 //XSTR:OFF
7574 if ( FS_VERSION_BUILD == 0 ) {
7575         sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7576 } else {
7577         sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7578 }
7579
7580 #if defined (FS2_DEMO)
7581         strcat(str, " D");
7582 #elif defined (OEM_BUILD)
7583         strcat(str, " (OEM)");
7584 #endif
7585 //XSTR:ON
7586         /*
7587         HMODULE hMod;
7588         DWORD bogus_handle;
7589         char myname[_MAX_PATH];
7590         int namelen, major, minor, build, waste;
7591         unsigned int buf_size;
7592         DWORD version_size;
7593         char *infop;
7594         VOID *bufp;
7595         BOOL result;
7596
7597         // Find my EXE file name
7598         hMod = GetModuleHandle(NULL);
7599         namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7600
7601         version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7602         infop = (char *)malloc(version_size);
7603         result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7604
7605         // get the product version
7606         result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7607         sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7608 #ifdef DEMO
7609         sprintf(str,"Dv%d.%02d",major, minor);
7610 #else
7611         sprintf(str,"v%d.%02d",major, minor);
7612 #endif
7613         */
7614 }
7615
7616 void get_version_string_short(char *str)
7617 {
7618         sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7619 }
7620
7621 // ----------------------------------------------------------------
7622 //
7623 // OEM UPSELL SCREENS BEGIN
7624 //
7625 // ----------------------------------------------------------------
7626 #if defined(OEM_BUILD)
7627
7628 #define NUM_OEM_UPSELL_SCREENS                          3
7629 #define OEM_UPSELL_SCREEN_DELAY                         10000
7630
7631 static int Oem_upsell_bitmaps_loaded = 0;
7632 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7633 static int Oem_upsell_screen_number = 0;
7634 static int Oem_upsell_show_next_bitmap_time;
7635
7636 //XSTR:OFF
7637 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] = 
7638 {
7639         {       "OEMUpSell02",
7640                 "OEMUpSell01",
7641                 "OEMUpSell03",
7642         },
7643         {       "2_OEMUpSell02",
7644                 "2_OEMUpSell01",
7645                 "2_OEMUpSell03",
7646         },
7647 };
7648 //XSTR:ON
7649
7650 static int Oem_normal_cursor = -1;
7651 static int Oem_web_cursor = -1;
7652 //#define OEM_UPSELL_URL                "http://www.interplay-store.com/"
7653 #define OEM_UPSELL_URL          "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7654
7655 void oem_upsell_next_screen()
7656 {
7657         Oem_upsell_screen_number++;
7658         if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7659                 // extra long delay, mouse shown on last upsell
7660                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7661                 Mouse_hidden = 0;
7662
7663         } else {
7664                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7665         }
7666 }
7667
7668 void oem_upsell_load_bitmaps()
7669 {
7670         int i;
7671
7672         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7673                 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7674         }
7675 }
7676
7677 void oem_upsell_unload_bitmaps()
7678 {
7679         int i;
7680
7681         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7682                 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7683                         bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7684                 }
7685         }
7686
7687         // unloaded
7688         Oem_upsell_bitmaps_loaded = 0;
7689 }
7690
7691 // clickable hotspot on 3rd OEM upsell screen
7692 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7693         {       // GR_640
7694                 28, 350, 287, 96                                        // x, y, w, h
7695         },
7696         {       // GR_1024
7697                 45, 561, 460, 152                                       // x, y, w, h
7698         }
7699 };
7700
7701 void oem_upsell_show_screens()
7702 {
7703         int current_time, k;
7704         int done = 0;
7705
7706         if ( !Oem_upsell_bitmaps_loaded ) {
7707                 oem_upsell_load_bitmaps();
7708                 Oem_upsell_bitmaps_loaded = 1;
7709         }
7710
7711         // may use upsell screens more than once
7712         Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7713         Oem_upsell_screen_number = 0;
7714         
7715         key_flush();
7716         Mouse_hidden = 1;
7717
7718         // set up cursors
7719         int nframes;                                            // used to pass, not really needed (should be 1)
7720         Oem_normal_cursor = gr_get_cursor_bitmap();
7721         Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7722         Assert(Oem_web_cursor >= 0);
7723         if (Oem_web_cursor < 0) {
7724                 Oem_web_cursor = Oem_normal_cursor;
7725         }
7726
7727         while(!done) {
7728
7729                 //oem_reset_trailer_timer();
7730
7731                 current_time = timer_get_milliseconds();
7732
7733                 os_poll();
7734                 k = key_inkey();
7735
7736                 // advance screen on keypress or timeout
7737                 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7738                         oem_upsell_next_screen();
7739                 }
7740
7741                 // check if we are done
7742                 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7743                         Oem_upsell_screen_number--;
7744                         done = 1;
7745                 } else {
7746                         if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7747                                 done = 1;
7748                         }
7749                 }
7750
7751                 // show me the upsell
7752                 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {               
7753                         gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7754                         gr_bitmap(0,0);
7755                 }
7756
7757                 // if this is the 3rd upsell, make it clickable, d00d
7758                 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7759                         int mx, my;
7760                         int button_state = mouse_get_pos(&mx, &my);
7761                         if ( (mx >= Oem_upsell3_button_coords[gr_screen.res][0]) && (mx <= Oem_upsell3_button_coords[gr_screen.res][0] + Oem_upsell3_button_coords[gr_screen.res][2])
7762                                 && (my >= Oem_upsell3_button_coords[gr_screen.res][1]) && (my <= Oem_upsell3_button_coords[gr_screen.res][1] + Oem_upsell3_button_coords[gr_screen.res][3]) )
7763                         {
7764                                 // switch cursors
7765                                 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7766
7767                                 // check for clicks
7768                                 if (button_state & MOUSE_LEFT_BUTTON) {
7769                                         // launch URL
7770                                         multi_pxo_url(OEM_UPSELL_URL);
7771                                         done = 1;
7772                                 } 
7773                         } else {
7774                                 // switch cursor back to normal one
7775                                 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7776                         }
7777                 }
7778
7779                 if ( done ) {
7780                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
7781                                 gr_fade_out(0);
7782                                 Sleep(300);
7783                         }
7784                 }
7785
7786                 gr_flip();
7787         }
7788
7789         // unload bitmap
7790         oem_upsell_unload_bitmaps();
7791
7792         // switch cursor back to normal one
7793         gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7794
7795 }
7796
7797 #endif // defined(OEM_BUILD)
7798 // ----------------------------------------------------------------
7799 //
7800 // OEM UPSELL SCREENS END
7801 //
7802 // ----------------------------------------------------------------
7803
7804
7805
7806 // ----------------------------------------------------------------
7807 //
7808 // DEMO UPSELL SCREENS BEGIN
7809 //
7810 // ----------------------------------------------------------------
7811
7812 #ifdef FS2_DEMO
7813
7814 //#define NUM_DEMO_UPSELL_SCREENS                               4
7815
7816 #define NUM_DEMO_UPSELL_SCREENS                         2
7817 #define DEMO_UPSELL_SCREEN_DELAY                                3000
7818
7819 static int Demo_upsell_bitmaps_loaded = 0;
7820 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7821 static int Demo_upsell_screen_number = 0;
7822 static int Demo_upsell_show_next_bitmap_time;
7823
7824 //XSTR:OFF
7825 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] = 
7826 {
7827         {       "UpSell02",
7828                 "UpSell01",
7829         },
7830         {       "2_UpSell02",
7831                 "2_UpSell01",
7832         },
7833         // "DemoUpsell3",
7834         // "DemoUpsell4",
7835 };
7836 //XSTR:ON
7837
7838 void demo_upsell_next_screen()
7839 {
7840         Demo_upsell_screen_number++;
7841         if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7842                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7843         } else {
7844                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7845         }
7846
7847         /*
7848         if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
7849                 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
7850 #ifndef HARDWARE_ONLY
7851                         palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7852 #endif
7853                 }
7854         }
7855         */
7856 }
7857
7858 void demo_upsell_load_bitmaps()
7859 {
7860         int i;
7861
7862         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7863                 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7864         }
7865 }
7866
7867 void demo_upsell_unload_bitmaps()
7868 {
7869         int i;
7870
7871         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7872                 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7873                         bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7874                 }
7875         }
7876
7877         // unloaded
7878         Demo_upsell_bitmaps_loaded = 0;
7879 }
7880
7881 void demo_upsell_show_screens()
7882 {
7883         int current_time, k;
7884         int done = 0;
7885
7886         if ( !Demo_upsell_bitmaps_loaded ) {
7887                 demo_upsell_load_bitmaps();
7888                 Demo_upsell_bitmaps_loaded = 1;
7889         }
7890
7891         // may use upsell screens more than once
7892         Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7893         Demo_upsell_screen_number = 0;
7894         
7895         key_flush();
7896         Mouse_hidden = 1;
7897
7898         while(!done) {
7899
7900                 demo_reset_trailer_timer();
7901
7902                 current_time = timer_get_milliseconds();
7903
7904 // #ifndef THREADED
7905                 os_poll();
7906 // #endif
7907                 k = key_inkey();
7908
7909                 // don't time out, wait for keypress
7910                 /*
7911                 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7912                         demo_upsell_next_screen();
7913                         k = 0;
7914                 }*/
7915
7916                 if ( k > 0 ) {
7917                         demo_upsell_next_screen();
7918                 }
7919
7920                 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7921                         Demo_upsell_screen_number--;
7922                         done = 1;
7923                 } else {
7924                         if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7925                                 done = 1;
7926                         }
7927                 }
7928
7929                 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {             
7930                         gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7931                         gr_bitmap(0,0);
7932                 }
7933
7934                 if ( done ) {
7935                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
7936                                 gr_fade_out(0);
7937                                 Sleep(300);
7938                         }
7939                 }
7940
7941                 gr_flip();
7942         }
7943
7944         // unload bitmap
7945         demo_upsell_unload_bitmaps();
7946 }
7947
7948 #endif // DEMO
7949
7950 // ----------------------------------------------------------------
7951 //
7952 // DEMO UPSELL SCREENS END
7953 //
7954 // ----------------------------------------------------------------
7955
7956
7957 // ----------------------------------------------------------------
7958 //
7959 // Subspace Ambient Sound START
7960 //
7961 // ----------------------------------------------------------------
7962
7963 static int Subspace_ambient_left_channel = -1;
7964 static int Subspace_ambient_right_channel = -1;
7965
7966 // 
7967 void game_start_subspace_ambient_sound()
7968 {
7969         if ( Subspace_ambient_left_channel < 0 ) {
7970                 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7971         }
7972
7973         if ( Subspace_ambient_right_channel < 0 ) {
7974                 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7975         }
7976 }
7977
7978 void game_stop_subspace_ambient_sound()
7979 {
7980         if ( Subspace_ambient_left_channel >= 0 ) {
7981                 snd_stop(Subspace_ambient_left_channel);
7982                 Subspace_ambient_left_channel = -1;
7983         }
7984
7985         if ( Subspace_ambient_right_channel >= 0 ) {
7986                 snd_stop(Subspace_ambient_right_channel);
7987                 Subspace_ambient_right_channel = -1;
7988         }
7989 }
7990
7991 // ----------------------------------------------------------------
7992 //
7993 // Subspace Ambient Sound END
7994 //
7995 // ----------------------------------------------------------------
7996
7997 // ----------------------------------------------------------------
7998 //
7999 // CDROM detection code START
8000 //
8001 // ----------------------------------------------------------------
8002
8003 #define CD_SIZE_72_MINUTE_MAX                   (697000000)
8004
8005 uint game_get_cd_used_space(char *path)
8006 {
8007 #ifndef PLAT_UNIX
8008         uint total = 0;
8009         char use_path[512] = "";
8010         char sub_path[512] = "";
8011         WIN32_FIND_DATA find;
8012         HANDLE find_handle;
8013
8014         // recurse through all files and directories
8015         strcpy(use_path, path);
8016         strcat(use_path, "*.*");
8017         find_handle = FindFirstFile(use_path, &find);
8018
8019         // bogus
8020         if(find_handle == INVALID_HANDLE_VALUE){
8021                 return 0;
8022         }       
8023
8024         // whee
8025         do {
8026                 // subdirectory. make sure to ignore . and ..
8027                 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8028                         // subsearch
8029                         strcpy(sub_path, path);
8030                         strcat(sub_path, find.cFileName);
8031                         strcat(sub_path, "\\");
8032                         total += game_get_cd_used_space(sub_path);      
8033                 } else {
8034                         total += (uint)find.nFileSizeLow;
8035                 }                               
8036         } while(FindNextFile(find_handle, &find));      
8037
8038         // close
8039         FindClose(find_handle);
8040
8041         // total
8042         return total;
8043 #else
8044         STUB_FUNCTION;
8045         
8046         return 0;
8047 #endif  
8048 }
8049
8050
8051 // if volume_name is non-null, the CD name must match that
8052 int find_freespace_cd(char *volume_name)
8053 {
8054 #ifndef PLAT_UNIX
8055         char oldpath[MAX_PATH];
8056         char volume[256];
8057         int i;
8058         int cdrom_drive=-1;
8059         int volume_match = 0;
8060         _finddata_t find;
8061         int find_handle;
8062
8063         GetCurrentDirectory(MAX_PATH, oldpath);
8064
8065         for (i = 0; i < 26; i++) 
8066         {
8067 //XSTR:OFF
8068                 char path[]="d:\\";
8069 //XSTR:ON
8070
8071                 path[0] = (char)('A'+i);
8072                 if (GetDriveType(path) == DRIVE_CDROM) {
8073                         cdrom_drive = -3;
8074                         if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8075                                 nprintf(("CD", "CD volume: %s\n", volume));
8076                         
8077                                 // check for any CD volume
8078                                 int volume1_present = 0;
8079                                 int volume2_present = 0;
8080                                 int volume3_present = 0;                
8081
8082                                 char full_check[512] = "";
8083
8084                                 // look for setup.exe
8085                                 strcpy(full_check, path);
8086                                 strcat(full_check, "setup.exe");                                
8087                                 find_handle = _findfirst(full_check, &find);
8088                                 if(find_handle != -1){
8089                                         volume1_present = 1;                            
8090                                         _findclose(find_handle);                                
8091                                 }
8092
8093                                 // look for intro.mve
8094                                 strcpy(full_check, path);
8095                                 strcat(full_check, "intro.mve");                                
8096                                 find_handle = _findfirst(full_check, &find);
8097                                 if(find_handle != -1){
8098                                         volume2_present = 1;
8099                                         _findclose(find_handle);                                                
8100                                 }                               
8101
8102                                 // look for endpart1.mve
8103                                 strcpy(full_check, path);
8104                                 strcat(full_check, "endpart1.mve");                             
8105                                 find_handle = _findfirst(full_check, &find);
8106                                 if(find_handle != -1){
8107                                         volume3_present = 1;
8108                                         _findclose(find_handle);                                
8109                                 }                               
8110                         
8111                                 // see if we have the specific CD we're looking for
8112                                 if ( volume_name ) {
8113                                         // volume 1
8114                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8115                                                 volume_match = 1;
8116                                         }
8117                                         // volume 2
8118                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8119                                                 volume_match = 1;
8120                                         }
8121                                         // volume 3
8122                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8123                                                 volume_match = 1;
8124                                         }
8125                                 } else {                                                                                
8126                                         if ( volume1_present || volume2_present || volume3_present ) {
8127                                                 volume_match = 1;
8128                                         }
8129                                 }
8130                                 
8131                                 // here's where we make sure that CD's 2 and 3 are not just ripped - check to make sure its capacity is > 697,000,000 bytes                             
8132                                 if ( volume_match ){
8133 #ifdef RELEASE_REAL                                     
8134                                         // we don't care about CD1 though. let it be whatever size it wants, since the game will demand CD's 2 and 3 at the proper time
8135                                         if(volume2_present || volume3_present) {
8136                                                 // first step - check to make sure its a cdrom
8137                                                 if(GetDriveType(path) != DRIVE_CDROM){                                                  
8138                                                         break;
8139                                                 }
8140
8141 #if !defined(OEM_BUILD)
8142                                                 // oem not on 80 min cds, so dont check tha size
8143                                                 // check its size
8144                                                 uint used_space = game_get_cd_used_space(path);                                                                                 
8145                                                 if(used_space < CD_SIZE_72_MINUTE_MAX){                                                 
8146                                                         break;
8147                                                 }
8148 #endif // !defined(OEM_BUILD)
8149                                         }                                       
8150
8151                                         cdrom_drive = i;
8152                                         break;
8153 #else
8154                                         cdrom_drive = i;
8155                                         break;
8156 #endif // RELEASE_REAL
8157                                 }
8158                         }
8159                 }
8160         }       
8161
8162         SetCurrentDirectory(oldpath);
8163         return cdrom_drive;
8164 #else
8165         STUB_FUNCTION;
8166         
8167         return 0;
8168 #endif  
8169 }
8170
8171 int set_cdrom_path(int drive_num)
8172 {
8173         int rval;
8174
8175         if (drive_num < 0) {                    //no CD
8176 //              #ifndef NDEBUG
8177 //              strcpy(CDROM_dir,"j:\\FreeSpaceCD\\");                          //set directory
8178 //              rval = 1;
8179 //              #else
8180                 strcpy(Game_CDROM_dir,"");                              //set directory
8181                 rval = 0;
8182 //              #endif
8183         } else {
8184                 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num );                 //set directory
8185                 rval = 1;
8186         }
8187
8188         return rval;
8189 }
8190
8191 int init_cdrom()
8192 {
8193         int i, rval;
8194
8195         //scan for CD, etc.
8196
8197         rval = 1;
8198
8199         #ifndef DEMO
8200         i = find_freespace_cd();
8201
8202         rval = set_cdrom_path(i);
8203
8204         /*
8205         if ( rval ) {
8206                 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8207         } else {
8208                 nprintf(("CD", "FreeSpace CD not found\n"));
8209         }
8210         */
8211         #endif
8212
8213         return rval;
8214 }
8215
8216 int Last_cd_label_found = 0;
8217 char Last_cd_label[256];
8218
8219 int game_cd_changed()
8220 {
8221 #ifndef PLAT_UNIX
8222         char label[256];
8223         int found;
8224         int changed = 0;
8225         
8226         if ( strlen(Game_CDROM_dir) == 0 ) {
8227                 init_cdrom();
8228         }
8229
8230         found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8231
8232         if ( found != Last_cd_label_found )     {
8233                 Last_cd_label_found = found;
8234                 if ( found )    {
8235                         mprintf(( "CD '%s' was inserted\n", label ));
8236                         changed = 1;
8237                 } else {
8238                         mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8239                         changed = 1;
8240                 }
8241         } else {
8242                 if ( Last_cd_label_found )      {
8243                         if ( !stricmp( Last_cd_label, label ))  {
8244                                 //mprintf(( "CD didn't change\n" ));
8245                         } else {
8246                                 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8247                                 changed = 1;
8248                         }
8249                 } else {
8250                         // none found before, none found now.
8251                         //mprintf(( "still no CD...\n" ));
8252                 }
8253         }
8254         
8255         Last_cd_label_found = found;
8256         if ( found )    {
8257                 strcpy( Last_cd_label, label );
8258         } else {
8259                 strcpy( Last_cd_label, "" );
8260         }
8261
8262         return changed;
8263 #else
8264         STUB_FUNCTION;
8265 #endif          
8266 }
8267
8268 // check if _any_ FreeSpace2 CDs are in the drive
8269 // return: 1    => CD now in drive
8270 //                        0     =>      Could not find CD, they refuse to put it in the drive
8271 int game_do_cd_check(char *volume_name)
8272 {       
8273 #if !defined(GAME_CD_CHECK)
8274         return 1;
8275 #else
8276         int cd_present = 0;
8277         int cd_drive_num;
8278
8279         int num_attempts = 0;
8280         int refresh_files = 0;
8281         while(1) {
8282                 int path_set_ok, popup_rval;
8283
8284                 cd_drive_num = find_freespace_cd(volume_name);
8285                 path_set_ok = set_cdrom_path(cd_drive_num);
8286                 if ( path_set_ok ) {
8287                         cd_present = 1;
8288                         if ( refresh_files ) {
8289                                 cfile_refresh();
8290                                 refresh_files = 0;
8291                         }
8292                         break;
8293                 }
8294
8295                 // standalone mode
8296                 if(Is_standalone){
8297                         cd_present = 0;
8298                         break;
8299                 } else {
8300                         // no CD found, so prompt user
8301                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8302                         refresh_files = 1;
8303                         if ( popup_rval != 1 ) {
8304                                 cd_present = 0;
8305                                 break;
8306                         }
8307
8308                         if ( num_attempts++ > 5 ) {
8309                                 cd_present = 0;
8310                                 break;
8311                         }
8312                 }
8313         }
8314
8315         return cd_present;
8316 #endif
8317 }
8318
8319 // check if _any_ FreeSpace2 CDs are in the drive
8320 // return: 1    => CD now in drive
8321 //                        0     =>      Could not find CD, they refuse to put it in the drive
8322 int game_do_cd_check_specific(char *volume_name, int cdnum)
8323 {       
8324         int cd_present = 0;
8325         int cd_drive_num;
8326
8327         int num_attempts = 0;
8328         int refresh_files = 0;
8329         while(1) {
8330                 int path_set_ok, popup_rval;
8331
8332                 cd_drive_num = find_freespace_cd(volume_name);
8333                 path_set_ok = set_cdrom_path(cd_drive_num);
8334                 if ( path_set_ok ) {
8335                         cd_present = 1;
8336                         if ( refresh_files ) {
8337                                 cfile_refresh();
8338                                 refresh_files = 0;
8339                         }
8340                         break;
8341                 }
8342
8343                 if(Is_standalone){
8344                         cd_present = 0;
8345                         break;
8346                 } else {
8347                         // no CD found, so prompt user
8348 #if defined(DVD_MESSAGE_HACK)
8349                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8350 #else
8351                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8352 #endif
8353                         refresh_files = 1;
8354                         if ( popup_rval != 1 ) {
8355                                 cd_present = 0;
8356                                 break;
8357                         }
8358
8359                         if ( num_attempts++ > 5 ) {
8360                                 cd_present = 0;
8361                                 break;
8362                         }
8363                 }
8364         }
8365
8366         return cd_present;
8367 }
8368
8369 // only need to do this in RELEASE_REAL
8370 int game_do_cd_mission_check(char *filename)
8371 {       
8372 #ifdef RELEASE_REAL
8373         int cd_num;
8374         int cd_present = 0;
8375         int cd_drive_num;
8376         fs_builtin_mission *m = game_find_builtin_mission(filename);
8377
8378         // check for changed CD
8379         if(game_cd_changed()){
8380                 cfile_refresh();
8381         }
8382
8383         // multiplayer
8384         if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8385                 return 1;
8386         }
8387
8388         // not builtin, so do a general check (any FS2 CD will do)
8389         if(m == NULL){
8390                 return game_do_cd_check();
8391         }
8392
8393         // does not have any CD requirement, do a general check
8394         if(strlen(m->cd_volume) <= 0){
8395                 return game_do_cd_check();
8396         }
8397
8398         // get the volume
8399         if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8400                 cd_num = 1;
8401         } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8402                 cd_num = 2;
8403         } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8404                 cd_num = 3; 
8405         } else {
8406                 return game_do_cd_check();
8407         }
8408
8409         // did we find the cd?
8410         if(find_freespace_cd(m->cd_volume) >= 0){
8411                 return 1;
8412         }
8413
8414         // make sure the volume exists
8415         int num_attempts = 0;
8416         int refresh_files = 0;
8417         while(1){
8418                 int path_set_ok, popup_rval;
8419
8420                 cd_drive_num = find_freespace_cd(m->cd_volume);
8421                 path_set_ok = set_cdrom_path(cd_drive_num);
8422                 if ( path_set_ok ) {
8423                         cd_present = 1;
8424                         if ( refresh_files ) {
8425                                 cfile_refresh();
8426                                 refresh_files = 0;
8427                         }
8428                         break;
8429                 }
8430
8431                 // no CD found, so prompt user
8432 #if defined(DVD_MESSAGE_HACK)
8433                 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8434 #else
8435                 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8436 #endif
8437
8438                 refresh_files = 1;
8439                 if ( popup_rval != 1 ) {
8440                         cd_present = 0;
8441                         break;
8442                 }
8443
8444                 if ( num_attempts++ > 5 ) {
8445                         cd_present = 0;
8446                         break;
8447                 }
8448         }       
8449
8450         return cd_present;
8451 #else
8452         return 1;
8453 #endif
8454 }
8455
8456 // ----------------------------------------------------------------
8457 //
8458 // CDROM detection code END
8459 //
8460 // ----------------------------------------------------------------
8461
8462 // ----------------------------------------------------------------
8463 // SHIPS TBL VERIFICATION STUFF
8464 //
8465
8466 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8467 #define NUM_SHIPS_TBL_CHECKSUMS         1
8468 /*
8469 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8470         -463907578,                                             // US - beta 1
8471         1696074201,                                             // FS2 demo
8472 };
8473 */
8474 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8475 //      -1022810006,                                    // 1.0 FULL
8476         -1254285366                                             // 1.2 FULL (German)
8477 };
8478
8479 void verify_ships_tbl()
8480 {       
8481         /*
8482 #ifdef NDEBUG
8483         Game_ships_tbl_valid = 1;
8484 #else
8485         */
8486         uint file_checksum;             
8487         int idx;
8488
8489         // detect if the packfile exists
8490         CFILE *detect = cfopen("ships.tbl", "rb");
8491         Game_ships_tbl_valid = 0;        
8492         
8493         // not mission-disk
8494         if(!detect){
8495                 Game_ships_tbl_valid = 0;
8496                 return;
8497         }       
8498
8499         // get the long checksum of the file
8500         file_checksum = 0;
8501         cfseek(detect, 0, SEEK_SET);    
8502         cf_chksum_long(detect, &file_checksum);
8503         cfclose(detect);
8504         detect = NULL;  
8505
8506         // now compare the checksum/filesize against known #'s
8507         for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8508                 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8509                         Game_ships_tbl_valid = 1;
8510                         return;
8511                 }
8512         }
8513 // #endif
8514 }
8515
8516 DCF(shipspew, "display the checksum for the current ships.tbl")
8517 {
8518         uint file_checksum;
8519         CFILE *detect = cfopen("ships.tbl", "rb");
8520         // get the long checksum of the file
8521         file_checksum = 0;
8522         cfseek(detect, 0, SEEK_SET);    
8523         cf_chksum_long(detect, &file_checksum);
8524         cfclose(detect);
8525
8526         dc_printf("%d", file_checksum);
8527 }
8528
8529 // ----------------------------------------------------------------
8530 // WEAPONS TBL VERIFICATION STUFF
8531 //
8532
8533 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8534 #define NUM_WEAPONS_TBL_CHECKSUMS               1
8535 /*
8536 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8537         141718090,                              // US - beta 1
8538         -266420030,                             // demo 1
8539 };
8540 */
8541 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8542 //      399297860,                              // 1.0 FULL     
8543         -553984927                              // 1.2 FULL (german)
8544 };
8545
8546 void verify_weapons_tbl()
8547 {       
8548         /*
8549 #ifdef NDEBUG
8550         Game_weapons_tbl_valid = 1;
8551 #else
8552         */
8553         uint file_checksum;             
8554         int idx;
8555
8556         // detect if the packfile exists
8557         CFILE *detect = cfopen("weapons.tbl", "rb");
8558         Game_weapons_tbl_valid = 0;      
8559         
8560         // not mission-disk
8561         if(!detect){
8562                 Game_weapons_tbl_valid = 0;
8563                 return;
8564         }       
8565
8566         // get the long checksum of the file
8567         file_checksum = 0;
8568         cfseek(detect, 0, SEEK_SET);    
8569         cf_chksum_long(detect, &file_checksum);
8570         cfclose(detect);
8571         detect = NULL;  
8572
8573         // now compare the checksum/filesize against known #'s
8574         for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8575                 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8576                         Game_weapons_tbl_valid = 1;
8577                         return;
8578                 }
8579         }
8580 // #endif
8581 }
8582
8583 DCF(wepspew, "display the checksum for the current weapons.tbl")
8584 {
8585         uint file_checksum;
8586         CFILE *detect = cfopen("weapons.tbl", "rb");
8587         // get the long checksum of the file
8588         file_checksum = 0;
8589         cfseek(detect, 0, SEEK_SET);    
8590         cf_chksum_long(detect, &file_checksum);
8591         cfclose(detect);
8592
8593         dc_printf("%d", file_checksum);
8594 }
8595
8596 // if the game is running using hacked data
8597 int game_hacked_data()
8598 {
8599         // hacked!
8600         if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8601                 return 1;
8602         }
8603
8604         // not hacked
8605         return 0;
8606 }
8607
8608 void display_title_screen()
8609 {
8610 #if defined(FS2_DEMO) || defined(OEM_BUILD)
8611         ///int title_bitmap;
8612
8613         // load bitmap
8614         int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8615         if (title_bitmap == -1) {
8616                 return;
8617         }
8618
8619         // d3d  
8620         if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8621                 extern void d3d_start_frame();
8622                 d3d_start_frame();
8623         }
8624
8625         // set
8626         gr_set_bitmap(title_bitmap);
8627
8628         // draw
8629         gr_bitmap(0, 0);
8630
8631         // d3d  
8632         if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
8633                 extern void d3d_stop_frame();
8634                 d3d_stop_frame();
8635         }
8636
8637         // flip
8638         gr_flip();
8639
8640         bm_unload(title_bitmap);
8641 #endif  // FS2_DEMO || OEM_BUILD
8642 }
8643
8644 // return true if the game is running with "low memory", which is less than 48MB
8645 bool game_using_low_mem()
8646 {
8647         if (Use_low_mem == 0) {
8648                 return false;
8649         } else {
8650                 return true;
8651         }
8652 }
8653