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