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