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