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