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