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