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