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