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