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