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