]> icculus.org git repositories - taylor/freespace2.git/blob - src/freespace2/freespace.cpp
cross-platform RAM check
[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         parse_cmdline(szCmdLine);       
7113
7114 #ifdef STANDALONE_ONLY_BUILD
7115         Is_standalone = 1;
7116         nprintf(("Network", "Standalone running"));
7117 #else
7118         if (Is_standalone){
7119                 nprintf(("Network", "Standalone running"));
7120         }
7121 #endif
7122
7123         init_cdrom();
7124         game_init();
7125         game_stop_time();
7126
7127         // maybe spew pof stuff
7128         if(Cmdline_spew_pof_info){
7129                 game_spew_pof_info();
7130                 game_shutdown();
7131                 return 1;
7132         }
7133
7134         // non-demo, non-standalone, play the intro movie
7135 #ifndef DEMO
7136         if(!Is_standalone){
7137 #ifdef RELEASE_REAL
7138                 char *plist[5];
7139
7140                 // to avoid crashes on debug build
7141                 for (i=0; i<5; i++) {
7142                         plist[i] = NULL;
7143                 }
7144
7145                 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) ){
7146                         // prompt for cd 2
7147 #if defined(OEM_BUILD)
7148                         game_do_cd_check_specific(FS_CDROM_VOLUME_1, 1);
7149 #else
7150                         game_do_cd_check_specific(FS_CDROM_VOLUME_2, 2);
7151 #endif // defined(OEM_BUILD)
7152                 }
7153
7154                 for (int i=0; i<5; i++) {
7155                         if (plist[i] != NULL) {
7156                                 free(plist[i]);
7157                                 plist[i] = NULL;
7158                         }
7159                 }
7160 #endif // RELEASE_REAL
7161         }
7162
7163         if ( !Is_standalone ) {
7164
7165                 // release -- movies always play
7166 #if defined(NDEBUG)
7167
7168                 // 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
7169                 movie_play( NOX("intro.mve"), 0 );
7170
7171                 // debug version, movie will only play with -showmovies
7172 #elif !defined(NDEBUG)
7173                 
7174                 movie_play( NOX("intro.mve"), 0);
7175 /*
7176 #ifndef NDEBUG
7177                 if ( Cmdline_show_movies )
7178                         movie_play( NOX("intro.mve"), 0 );
7179 #endif
7180 */
7181 #endif // NDEBUG
7182         }
7183
7184 #endif // DEMO
7185
7186         if (Is_standalone){
7187                 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
7188         } else {
7189                 gameseq_post_event(GS_EVENT_GAME_INIT);         // start the game rolling -- check for default pilot, or go to the pilot select screen
7190         }
7191
7192         while (1) {
7193                 // only important for non THREADED mode
7194                 os_poll();
7195
7196                 state = gameseq_process_events();
7197                 if ( state == GS_STATE_QUIT_GAME ){
7198                         break;
7199                 }
7200         } 
7201
7202 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7203         if(!Is_standalone){
7204                 demo_upsell_show_screens();
7205         }
7206 #elif defined(OEM_BUILD)
7207         // show upsell screens on exit
7208         oem_upsell_show_screens();
7209 #endif
7210
7211         game_shutdown();
7212         return 1;
7213 }
7214
7215 int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
7216 {
7217         int result = -1;
7218 #ifndef PLAT_UNIX
7219         __try
7220         {
7221                 result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7222         }
7223         __except(RecordExceptionInfo(GetExceptionInformation(), "Freespace 2 Main Thread"))
7224         {
7225                 // Do nothing here - RecordExceptionInfo() has already done
7226                 // everything that is needed. Actually this code won't even
7227                 // get called unless you return EXCEPTION_EXECUTE_HANDLER from
7228                 // the __except clause.
7229         }
7230         return result;
7231 #else
7232         nprintf(("WinMain", "exceptions shall fall through"));
7233         
7234         result = WinMainSub(hInst, hPrev, szCmdLine, nCmdShow);
7235         
7236         return result;
7237 #endif  
7238 }
7239
7240 // launcher the fslauncher program on exit
7241 void game_launch_launcher_on_exit()
7242 {
7243 #ifndef PLAT_UNIX
7244         STARTUPINFO si;
7245         PROCESS_INFORMATION pi;
7246         char cmd_line[2048];
7247         char original_path[1024] = "";
7248         
7249         memset( &si, 0, sizeof(STARTUPINFO) );
7250         si.cb = sizeof(si);
7251
7252         // directory
7253         _getcwd(original_path, 1023);
7254
7255         // set up command line
7256         strcpy(cmd_line, original_path);
7257         strcat(cmd_line, "\\");
7258         strcat(cmd_line, LAUNCHER_FNAME);
7259         strcat(cmd_line, " -straight_to_update");               
7260
7261         BOOL ret = CreateProcess(       NULL,                                                                   // pointer to name of executable module 
7262                                                                                 cmd_line,                                                       // pointer to command line string
7263                                                                                 NULL,                                                                   // pointer to process security attributes 
7264                                                                                 NULL,                                                                   // pointer to thread security attributes 
7265                                                                                 FALSE,                                                          // handle inheritance flag 
7266                                                                                 CREATE_DEFAULT_ERROR_MODE,              // creation flags 
7267                                                                                 NULL,                                                                   // pointer to new environment block 
7268                                                                                 NULL,                                                                   // pointer to current directory name 
7269                                                                                 &si,                                                                    // pointer to STARTUPINFO 
7270                                                                                 &pi                                                                     // pointer to PROCESS_INFORMATION  
7271                                                                                 );                      
7272         // to eliminate build warnings
7273         ret;
7274 #else
7275         STUB_FUNCTION;
7276 #endif          
7277 }
7278
7279
7280 // game_shutdown()
7281 //
7282 // This function is called when FreeSpace terminates normally.  
7283 //
7284 void game_shutdown(void)
7285 {
7286 #ifndef PLAT_UNIX
7287         timeEndPeriod(1);
7288 #endif
7289
7290         // don't ever flip a page on the standalone!
7291         if(!(Game_mode & GM_STANDALONE_SERVER)){
7292                 gr_reset_clip();
7293                 gr_clear();
7294                 gr_flip();
7295         }
7296
7297    // if the player has left the "player select" screen and quit the game without actually choosing
7298         // a player, Player will be NULL, in which case we shouldn't write the player file out!
7299         if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
7300                 write_pilot_file();
7301         }
7302
7303         // load up common multiplayer icons
7304         multi_unload_common_icons();
7305         
7306         shockwave_close();                      // release any memory used by shockwave system  
7307         fireball_close();                               // free fireball system
7308         ship_close();                                   // free any memory that was allocated for the ships
7309         weapon_close();                                 // free any memory that was allocated for the weapons
7310         hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
7311         unload_animating_pointer();// frees the frames used for the animating mouse pointer
7312         bm_unload_all();                                // free bitmaps
7313         mission_campaign_close();       // close out the campaign stuff
7314         mission_campaign_shutdown();    // get anything that mission_campaign_close can't do
7315         multi_voice_close();                    // close down multiplayer voice (including freeing buffers, etc)
7316         multi_log_close();
7317 #ifdef MULTI_USE_LAG
7318         multi_lag_close();
7319 #endif
7320
7321         // the menu close functions will unload the bitmaps if they were displayed during the game
7322 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
7323         main_hall_close();
7324 #endif
7325         context_help_close();           // close out help system
7326         training_menu_close();
7327         lcl_close();                            // be sure localization is closed out
7328         gr_close();
7329
7330         // free left-over memory from parsed tables
7331         cutscene_tbl_close();
7332         medal_tbl_close();
7333         scoring_tbl_close();
7334         player_tips_close();
7335
7336         extern void joy_close();
7337         joy_close();
7338
7339         audiostream_close();
7340         snd_close();
7341         event_music_close();
7342         psnet_close();
7343         os_cleanup();
7344
7345         // HACKITY HACK HACK
7346         // if this flag is set, we should be firing up the launcher when exiting freespace
7347         extern int Multi_update_fireup_launcher_on_exit;
7348         if(Multi_update_fireup_launcher_on_exit){
7349                 game_launch_launcher_on_exit();
7350         }
7351 }
7352
7353 // game_stop_looped_sounds()
7354 //
7355 // This function will call the appropriate stop looped sound functions for those
7356 // modules which use looping sounds.  It is not enough just to stop a looping sound
7357 // at the DirectSound level, the game is keeping track of looping sounds, and this
7358 // function is used to inform the game that looping sounds are being halted.
7359 //
7360 void game_stop_looped_sounds()
7361 {
7362         hud_stop_looped_locking_sounds();
7363         hud_stop_looped_engine_sounds();
7364         afterburner_stop_sounds();
7365         player_stop_looped_sounds();
7366         obj_snd_stop_all();             // stop all object-linked persistant sounds
7367         game_stop_subspace_ambient_sound();
7368         snd_stop(Radar_static_looping);
7369         Radar_static_looping = -1;
7370         snd_stop(Target_static_looping);
7371         shipfx_stop_engine_wash_sound();
7372         Target_static_looping = -1;
7373 }
7374
7375 //////////////////////////////////////////////////////////////////////////
7376 //
7377 // Code for supporting an animating mouse pointer
7378 //
7379 //
7380 //////////////////////////////////////////////////////////////////////////
7381
7382 typedef struct animating_obj
7383 {
7384         int     first_frame;
7385         int     num_frames;
7386         int     current_frame;
7387         float time;
7388         float elapsed_time;
7389 } animating_obj;
7390
7391 static animating_obj Animating_mouse;
7392
7393 // ----------------------------------------------------------------------------
7394 // init_animating_pointer()
7395 //
7396 // Called by load_animating_pointer() to ensure the Animating_mouse struct
7397 // gets properly initialized
7398 //
7399 void init_animating_pointer()
7400 {
7401         Animating_mouse.first_frame     = -1;
7402         Animating_mouse.num_frames              = 0;
7403         Animating_mouse.current_frame   = -1;
7404         Animating_mouse.time                            = 0.0f;
7405         Animating_mouse.elapsed_time    = 0.0f;
7406 }
7407
7408 // ----------------------------------------------------------------------------
7409 // load_animating_pointer()
7410 //
7411 // Called at game init to load in the frames for the animating mouse pointer
7412 //
7413 // input:       filename        =>      filename of animation file that holds the animation
7414 // 
7415 void load_animating_pointer(const char *filename, int dx, int dy)
7416 {
7417         int                             fps;
7418         animating_obj *am;
7419
7420         init_animating_pointer();
7421
7422         am = &Animating_mouse;
7423         am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
7424         if ( am->first_frame == -1 ) 
7425                 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
7426         am->current_frame = 0;
7427         am->time = am->num_frames / i2fl(fps);
7428 }
7429
7430 // ----------------------------------------------------------------------------
7431 // unload_animating_pointer()
7432 //
7433 // Called at game shutdown to free the memory used to store the animation frames
7434 //
7435 void unload_animating_pointer()
7436 {
7437         int                             i;
7438         animating_obj   *am;
7439
7440         am = &Animating_mouse;
7441         for ( i = 0; i < am->num_frames; i++ ) {
7442                 Assert( (am->first_frame+i) >= 0 );
7443                 bm_release(am->first_frame + i);
7444         }
7445
7446         am->first_frame = -1;
7447         am->num_frames          = 0;
7448         am->current_frame = -1;
7449 }
7450
7451 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
7452 void game_render_mouse(float frametime)
7453 {
7454         int                             mx, my;
7455         animating_obj   *am;
7456
7457         // if animating cursor exists, play the next frame
7458         am = &Animating_mouse;
7459         if ( am->first_frame != -1 ) {
7460                 mouse_get_pos(&mx, &my);
7461                 am->elapsed_time += frametime;
7462                 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
7463                 if ( am->current_frame >= am->num_frames ) {
7464                         am->current_frame = 0;
7465                         am->elapsed_time = 0.0f;
7466                 }
7467                 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
7468         }
7469 }
7470
7471 // ----------------------------------------------------------------------------
7472 // game_maybe_draw_mouse()
7473 //
7474 // determines whether to draw the mouse pointer at all, and what frame of
7475 // animation to use if the mouse is animating
7476 //
7477 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
7478 //
7479 // input:       frametime => elapsed frame time in seconds since last call
7480 //
7481 void game_maybe_draw_mouse(float frametime)
7482 {
7483         int game_state;
7484
7485         game_state = gameseq_get_state();
7486
7487         switch ( game_state ) {
7488                 case GS_STATE_GAME_PAUSED:
7489                 // case GS_STATE_MULTI_PAUSED:
7490                 case GS_STATE_GAME_PLAY:
7491                 case GS_STATE_DEATH_DIED:
7492                 case GS_STATE_DEATH_BLEW_UP:
7493                         if ( popup_active() || popupdead_is_active() ) {
7494                                 Mouse_hidden = 0;
7495                         } else {
7496                                 Mouse_hidden = 1;       
7497                         }
7498                         break;
7499
7500                 default:
7501                         Mouse_hidden = 0;
7502                         break;
7503         }       // end switch
7504
7505         if ( !Mouse_hidden ) 
7506                 game_render_mouse(frametime);
7507
7508 }
7509
7510 void game_do_training_checks()
7511 {
7512         int i, s;
7513         float d;
7514         waypoint_list *wplp;
7515
7516         if (Training_context & TRAINING_CONTEXT_SPEED) {
7517                 s = (int) Player_obj->phys_info.fspeed;
7518                 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7519                         if (!Training_context_speed_set) {
7520                                 Training_context_speed_set = 1;
7521                                 Training_context_speed_timestamp = timestamp();
7522                         }
7523
7524                 } else
7525                         Training_context_speed_set = 0;
7526         }
7527
7528         if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7529                 wplp = &Waypoint_lists[Training_context_path];
7530                 if (wplp->count > Training_context_goal_waypoint) {
7531                         i = Training_context_goal_waypoint;
7532                         do {
7533                                 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7534                                 if (d <= Training_context_distance) {
7535                                         Training_context_at_waypoint = i;
7536                                         if (Training_context_goal_waypoint == i) {
7537                                                 Training_context_goal_waypoint++;
7538                                                 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7539                                         }
7540
7541                                         break;
7542                                 }
7543
7544                                 i++;
7545                                 if (i == wplp->count)
7546                                         i = 0;
7547
7548                         } while (i != Training_context_goal_waypoint);
7549                 }
7550         }
7551
7552         if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7553                 Players_target = Player_ai->target_objnum;
7554                 Players_targeted_subsys = Player_ai->targeted_subsys;
7555                 Players_target_timestamp = timestamp();
7556         }
7557 }
7558
7559 /////////// Following is for event debug view screen
7560
7561 #ifndef NDEBUG
7562
7563 #define EVENT_DEBUG_MAX 5000
7564 #define EVENT_DEBUG_EVENT 0x8000
7565
7566 int Event_debug_index[EVENT_DEBUG_MAX];
7567 int ED_count;
7568
7569 void game_add_event_debug_index(int n, int indent)
7570 {
7571         if (ED_count < EVENT_DEBUG_MAX)
7572                 Event_debug_index[ED_count++] = n | (indent << 16);
7573 }
7574
7575 void game_add_event_debug_sexp(int n, int indent)
7576 {
7577         if (n < 0)
7578                 return;
7579
7580         if (Sexp_nodes[n].first >= 0) {
7581                 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7582                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7583                 return;
7584         }
7585
7586         game_add_event_debug_index(n, indent);
7587         if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7588                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7589         else
7590                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7591 }
7592
7593 void game_event_debug_init()
7594 {
7595         int e;
7596
7597         ED_count = 0;
7598         for (e=0; e<Num_mission_events; e++) {
7599                 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7600                 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7601         }
7602 }
7603
7604 void game_show_event_debug(float frametime) 
7605 {
7606         char buf[256];
7607         int i, k, z;
7608         int font_height, font_width;    
7609         int y_index, y_max;
7610         static int scroll_offset = 0;
7611         
7612         k = game_check_key();
7613         if (k)
7614                 switch (k) {
7615                         case SDLK_UP:
7616                         case SDLK_KP_8:
7617                                 scroll_offset--;
7618                                 if (scroll_offset < 0)
7619                                         scroll_offset = 0;
7620                                 break;
7621
7622                         case SDLK_DOWN:
7623                         case SDLK_KP_2:
7624                                 scroll_offset++;
7625                                 break;
7626
7627                         case SDLK_PAGEUP:
7628                                 scroll_offset -= 20;
7629                                 if (scroll_offset < 0)
7630                                         scroll_offset = 0;
7631                                 break;
7632
7633                         case SDLK_PAGEDOWN:
7634                                 scroll_offset += 20;    // not font-independent, hard-coded since I counted the lines!
7635                                 break;
7636
7637                         default:
7638                                 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7639                                 key_flush();
7640                                 break;
7641                 } // end switch
7642
7643         gr_clear();
7644         gr_set_color_fast(&Color_bright);
7645         gr_set_font(FONT1);
7646         gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7647
7648         gr_set_color_fast(&Color_normal);
7649         gr_set_font(FONT1);
7650         gr_get_string_size(&font_width, &font_height, NOX("test"));
7651         y_max = gr_screen.max_h - font_height - 5;
7652         y_index = 45;
7653
7654         k = scroll_offset;
7655         while (k < ED_count) {
7656                 if (y_index > y_max)
7657                         break;
7658
7659                 z = Event_debug_index[k];
7660                 if (z & EVENT_DEBUG_EVENT) {
7661                         z &= 0x7fff;
7662                         sprintf(buf, NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7663                                 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7664                                 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7665                                 Mission_events[z].repeat_count, Mission_events[z].interval);
7666
7667                 } else {
7668                         i = (z >> 16) * 3;
7669                         buf[i] = 0;
7670                         while (i--)
7671                                 buf[i] = ' ';
7672
7673                         strcat(buf, Sexp_nodes[z & 0x7fff].text);
7674                         switch (Sexp_nodes[z & 0x7fff].value) {
7675                                 case SEXP_TRUE:
7676                                         strcat(buf, NOX(" (True)"));
7677                                         break;
7678
7679                                 case SEXP_FALSE:
7680                                         strcat(buf, NOX(" (False)"));
7681                                         break;
7682
7683                                 case SEXP_KNOWN_TRUE:
7684                                         strcat(buf, NOX(" (Always true)"));
7685                                         break;
7686
7687                                 case SEXP_KNOWN_FALSE:
7688                                         strcat(buf, NOX(" (Always false)"));
7689                                         break;
7690
7691                                 case SEXP_CANT_EVAL:
7692                                         strcat(buf, NOX(" (Can't eval)"));
7693                                         break;
7694
7695                                 case SEXP_NAN:
7696                                 case SEXP_NAN_FOREVER:
7697                                         strcat(buf, NOX(" (Not a number)"));
7698                                         break;
7699                         }
7700                 }
7701
7702                 gr_printf(10, y_index, buf);
7703                 y_index += font_height;
7704                 k++;
7705         }
7706
7707         gr_flip();
7708 }
7709
7710 #endif // NDEBUG
7711
7712 #ifndef NDEBUG
7713 FILE * Time_fp;
7714 FILE * Texture_fp;
7715
7716 #ifndef PLAT_UNIX
7717 extern int Tmap_npixels;
7718 #endif
7719
7720 int Tmap_num_too_big = 0;
7721 int Num_models_needing_splitting = 0;
7722
7723 void Time_model( int modelnum )
7724 {
7725 //      mprintf(( "Timing ship '%s'\n", si->name ));
7726
7727         vector eye_pos, model_pos;
7728         matrix eye_orient, model_orient;
7729
7730         polymodel *pm = model_get( modelnum );
7731
7732         int l = strlen(pm->filename);
7733         while( (l>0) )  {
7734                 if ( (l == '/') || (l=='\\') || (l==':'))       {
7735                         l++;
7736                         break;
7737                 }
7738                 l--;
7739         }
7740         char *pof_file = &pm->filename[l];
7741
7742         int model_needs_splitting = 0;
7743
7744         //fprintf( Texture_fp, "Model: %s\n", pof_file );
7745         int i;
7746         for (i=0; i<pm->n_textures; i++ )       {
7747                 char filename[1024];
7748                 ubyte pal[768];
7749
7750                 int bmp_num = pm->original_textures[i];
7751                 if ( bmp_num > -1 )     {
7752                         bm_get_palette(pm->original_textures[i], pal, filename );               
7753                         int w,h;
7754                         bm_get_info( pm->original_textures[i],&w, &h );
7755
7756
7757                         if ( (w > 512) || (h > 512) )   {
7758                                 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7759                                 Tmap_num_too_big++;
7760                                 model_needs_splitting++;
7761                         }
7762                 } else {
7763                         //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7764                 }
7765         }
7766
7767         if ( model_needs_splitting )    {
7768                 Num_models_needing_splitting++;
7769         }
7770         eye_orient = model_orient = vmd_identity_matrix;
7771         eye_pos = model_pos = vmd_zero_vector;
7772
7773         eye_pos.xyz.z = -pm->rad*2.0f;
7774
7775         vector eye_to_model;
7776
7777         vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7778         vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7779
7780         fix t1 = timer_get_fixed_seconds();
7781
7782         angles ta;
7783         ta.p = ta.b = ta.h = 0.0f; 
7784         int framecount = 0;
7785
7786 #ifndef PLAT_UNIX
7787         Tmap_npixels = 0;
7788 #endif
7789
7790         int bitmaps_used_this_frame, bitmaps_new_this_frame;
7791                 
7792         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7793
7794         modelstats_num_polys = modelstats_num_verts = 0;
7795
7796         while( ta.h < PI2 )     {
7797
7798                 matrix m1;
7799                 vm_angles_2_matrix(&m1, &ta );
7800                 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7801
7802                 gr_reset_clip();
7803 //              gr_clear();
7804
7805                 g3_start_frame(1);
7806
7807                 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );       
7808
7809                 model_clear_instance( modelnum );
7810                 model_set_detail_level(0);              // use highest detail level
7811                 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL);     //|MR_NO_POLYS );
7812
7813                 g3_end_frame();
7814 //              gr_flip();
7815
7816                 framecount++;
7817                 ta.h += 0.1f;
7818
7819                 int k = key_inkey();
7820                 if ( k == SDLK_ESCAPE ) {
7821                         exit(1);
7822                 }
7823         }
7824
7825         fix t2 = timer_get_fixed_seconds();
7826
7827         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7828         //bitmaps_used_this_frame /= framecount;
7829
7830         modelstats_num_polys /= framecount;
7831         modelstats_num_verts /= framecount;
7832
7833 #ifndef PLAT_UNIX
7834         Tmap_npixels /=framecount;
7835 #endif
7836
7837         mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7838 #ifndef PLAT_UNIX
7839         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 );
7840 #else
7841                 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 );
7842 #endif
7843 //      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 );
7844
7845                 
7846 //      key_getch();
7847 }
7848
7849 int Time_models = 0;
7850 DCF_BOOL( time_models, Time_models );
7851
7852 void Do_model_timings_test()
7853 {
7854         
7855
7856         if ( !Time_models ) return;
7857
7858         mprintf(( "Timing models!\n" ));
7859
7860         int i;
7861
7862         ubyte model_used[MAX_POLYGON_MODELS];
7863         int model_id[MAX_POLYGON_MODELS];
7864         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7865                 model_used[i] = 0;
7866         }
7867         
7868         // Load them all
7869         for (i=0; i<Num_ship_types; i++ )       {
7870                 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7871
7872                 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7873                 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7874         }
7875
7876         Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7877         if ( !Texture_fp ) return;
7878
7879         Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7880         if ( !Time_fp ) return;
7881
7882         fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7883 //      fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7884         
7885         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7886                 if ( model_used[i] )    {
7887                         Time_model( model_id[i] );
7888                 }
7889         }
7890         
7891         fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7892         fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7893         
7894         fclose(Time_fp);
7895         fclose(Texture_fp);
7896
7897         exit(1);
7898 }
7899 #endif
7900
7901 // Call this function when you want to inform the player that a feature is not
7902 // enabled in the DEMO version of FreSpace
7903 void game_feature_not_in_demo_popup()
7904 {
7905         popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7906 }
7907
7908 // format the specified time (fixed point) into a nice string
7909 void game_format_time(fix m_time,char *time_str)
7910 {
7911         float mtime;
7912         int hours,minutes,seconds;
7913         char tmp[10];
7914
7915         mtime = f2fl(m_time);           
7916
7917         // get the hours, minutes and seconds   
7918         hours = (int)(mtime / 3600.0f);
7919         if(hours > 0){
7920                 mtime -= (3600.0f * (float)hours);
7921         }
7922         seconds = (int)mtime%60;
7923         minutes = (int)mtime/60;                        
7924
7925         // print the hour if necessary
7926         if(hours > 0){          
7927                 sprintf(time_str,XSTR( "%d:", 201),hours);
7928                 // if there are less than 10 minutes, print a leading 0
7929                 if(minutes < 10){
7930                         strcpy(tmp,NOX("0"));
7931                         strcat(time_str,tmp);
7932                 }               
7933         }       
7934         
7935         // print the minutes
7936         if(hours){
7937                 sprintf(tmp,XSTR( "%d:", 201),minutes);
7938                 strcat(time_str,tmp);
7939         } else {
7940                 sprintf(time_str,XSTR( "%d:", 201),minutes);
7941         }
7942
7943         // print the seconds
7944         if(seconds < 10){
7945                 strcpy(tmp,NOX("0"));
7946                 strcat(time_str,tmp);
7947         } 
7948         sprintf(tmp,"%d",seconds);
7949         strcat(time_str,tmp);
7950 }
7951
7952 //      Stuff version string in *str.
7953 void get_version_string(char *str)
7954 {
7955 //XSTR:OFF
7956 if ( FS_VERSION_BUILD == 0 ) {
7957         sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
7958 } else {
7959         sprintf(str,"v%d.%02d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7960 }
7961
7962 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7963         strcat(str, " D");
7964 #elif defined (OEM_BUILD)
7965         strcat(str, " (OEM)");
7966 #endif
7967 //XSTR:ON
7968         /*
7969         HMODULE hMod;
7970         DWORD bogus_handle;
7971         char myname[_MAX_PATH];
7972         int namelen, major, minor, build, waste;
7973         unsigned int buf_size;
7974         DWORD version_size;
7975         char *infop;
7976         VOID *bufp;
7977         BOOL result;
7978
7979         // Find my EXE file name
7980         hMod = GetModuleHandle(NULL);
7981         namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7982
7983         version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7984         infop = (char *)malloc(version_size);
7985         result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7986
7987         // get the product version
7988         result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7989         sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7990 #ifdef DEMO
7991         sprintf(str,"Dv%d.%02d",major, minor);
7992 #else
7993         sprintf(str,"v%d.%02d",major, minor);
7994 #endif
7995         */
7996 }
7997
7998 void get_version_string_short(char *str)
7999 {
8000         sprintf(str,"v%d.%02d",FS_VERSION_MAJOR, FS_VERSION_MINOR);
8001 }
8002
8003 // ----------------------------------------------------------------
8004 //
8005 // OEM UPSELL SCREENS BEGIN
8006 //
8007 // ----------------------------------------------------------------
8008 #if defined(OEM_BUILD)
8009
8010 #define NUM_OEM_UPSELL_SCREENS                          3
8011 #define OEM_UPSELL_SCREEN_DELAY                         10000
8012
8013 static int Oem_upsell_bitmaps_loaded = 0;
8014 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
8015 static int Oem_upsell_screen_number = 0;
8016 static int Oem_upsell_show_next_bitmap_time;
8017
8018 //XSTR:OFF
8019 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] = 
8020 {
8021         {       "OEMUpSell02",
8022                 "OEMUpSell01",
8023                 "OEMUpSell03",
8024         },
8025         {       "2_OEMUpSell02",
8026                 "2_OEMUpSell01",
8027                 "2_OEMUpSell03",
8028         },
8029 };
8030 //XSTR:ON
8031
8032 static int Oem_normal_cursor = -1;
8033 static int Oem_web_cursor = -1;
8034 //#define OEM_UPSELL_URL                "http://www.interplay-store.com/"
8035 #define OEM_UPSELL_URL          "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
8036
8037 void oem_upsell_next_screen()
8038 {
8039         Oem_upsell_screen_number++;
8040         if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
8041                 // extra long delay, mouse shown on last upsell
8042                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
8043                 Mouse_hidden = 0;
8044
8045         } else {
8046                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8047         }
8048 }
8049
8050 void oem_upsell_load_bitmaps()
8051 {
8052         int i;
8053
8054         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8055                 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
8056         }
8057 }
8058
8059 void oem_upsell_unload_bitmaps()
8060 {
8061         int i;
8062
8063         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
8064                 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
8065                         bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
8066                 }
8067         }
8068
8069         // unloaded
8070         Oem_upsell_bitmaps_loaded = 0;
8071 }
8072
8073 // clickable hotspot on 3rd OEM upsell screen
8074 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
8075         {       // GR_640
8076                 28, 350, 287, 96                                        // x, y, w, h
8077         },
8078         {       // GR_1024
8079                 45, 561, 460, 152                                       // x, y, w, h
8080         }
8081 };
8082
8083 void oem_upsell_show_screens()
8084 {
8085         int current_time, k;
8086         int done = 0;
8087
8088         if ( !Oem_upsell_bitmaps_loaded ) {
8089                 oem_upsell_load_bitmaps();
8090                 Oem_upsell_bitmaps_loaded = 1;
8091         }
8092
8093         // may use upsell screens more than once
8094         Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
8095         Oem_upsell_screen_number = 0;
8096         
8097         key_flush();
8098         Mouse_hidden = 1;
8099
8100         // set up cursors
8101         int nframes;                                            // used to pass, not really needed (should be 1)
8102         Oem_normal_cursor = gr_get_cursor_bitmap();
8103         Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
8104         Assert(Oem_web_cursor >= 0);
8105         if (Oem_web_cursor < 0) {
8106                 Oem_web_cursor = Oem_normal_cursor;
8107         }
8108
8109         while(!done) {
8110
8111                 //oem_reset_trailer_timer();
8112
8113                 current_time = timer_get_milliseconds();
8114
8115                 os_poll();
8116                 k = key_inkey();
8117
8118                 // advance screen on keypress or timeout
8119                 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
8120                         oem_upsell_next_screen();
8121                 }
8122
8123                 // check if we are done
8124                 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
8125                         Oem_upsell_screen_number--;
8126                         done = 1;
8127                 } else {
8128                         if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
8129                                 done = 1;
8130                         }
8131                 }
8132
8133                 // show me the upsell
8134                 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {               
8135                         gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
8136                         gr_bitmap(0,0);
8137                 }
8138
8139                 // if this is the 3rd upsell, make it clickable, d00d
8140                 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
8141                         int mx, my;
8142                         int button_state = mouse_get_pos(&mx, &my);
8143                         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])
8144                                 && (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]) )
8145                         {
8146                                 // switch cursors
8147                                 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
8148
8149                                 // check for clicks
8150                                 if (button_state & MOUSE_LEFT_BUTTON) {
8151                                         // launch URL
8152                                         multi_pxo_url(OEM_UPSELL_URL);
8153                                         done = 1;
8154                                 } 
8155                         } else {
8156                                 // switch cursor back to normal one
8157                                 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8158                         }
8159                 }
8160
8161                 if ( done ) {
8162                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
8163                                 gr_fade_out(0);
8164                                 Sleep(300);
8165                         }
8166                 }
8167
8168                 gr_flip();
8169         }
8170
8171         // unload bitmap
8172         oem_upsell_unload_bitmaps();
8173
8174         // switch cursor back to normal one
8175         gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
8176
8177 }
8178
8179 #endif // defined(OEM_BUILD)
8180 // ----------------------------------------------------------------
8181 //
8182 // OEM UPSELL SCREENS END
8183 //
8184 // ----------------------------------------------------------------
8185
8186
8187
8188 // ----------------------------------------------------------------
8189 //
8190 // DEMO UPSELL SCREENS BEGIN
8191 //
8192 // ----------------------------------------------------------------
8193
8194 #if defined(FS2_DEMO) || defined(FS1_DEMO)
8195
8196 #ifdef FS2_DEMO
8197 #define NUM_DEMO_UPSELL_SCREENS                         2
8198 #elif FS1_DEMO
8199 #define NUM_DEMO_UPSELL_SCREENS                         4
8200 #endif
8201 #define DEMO_UPSELL_SCREEN_DELAY                                3000
8202
8203 static int Demo_upsell_bitmaps_loaded = 0;
8204 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
8205 static int Demo_upsell_screen_number = 0;
8206 static int Demo_upsell_show_next_bitmap_time;
8207
8208 //XSTR:OFF
8209 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] = 
8210 {
8211 #ifdef FS1_DEMO
8212         {       "DemoUpsell1",
8213                 "DemoUpsell2",
8214                 "DemoUpsell3",
8215                 "DemoUpsell4"
8216         },
8217         {       "DemoUpsell1",
8218                 "DemoUpsell2",
8219                 "DemoUpsell3",
8220                 "DemoUpsell4"
8221         },
8222 #else
8223         {       "UpSell02",
8224                 "UpSell01",
8225         },
8226         {       "2_UpSell02",
8227                 "2_UpSell01",
8228         },
8229 #endif
8230         // "DemoUpsell3",
8231         // "DemoUpsell4",
8232 };
8233 //XSTR:ON
8234
8235 void demo_upsell_next_screen()
8236 {
8237         Demo_upsell_screen_number++;
8238         if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
8239                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
8240         } else {
8241                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8242         }
8243
8244         /*
8245         if ( Demo_upsell_screen_number < NUM_DEMO_UPSELL_SCREENS ) {
8246                 if ( Demo_upsell_bitmap_filenames[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {
8247 #ifndef HARDWARE_ONLY
8248                         palette_use_bm_palette(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8249 #endif
8250                 }
8251         }
8252         */
8253 }
8254
8255 void demo_upsell_load_bitmaps()
8256 {
8257         int i;
8258
8259         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8260                 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
8261         }
8262 }
8263
8264 void demo_upsell_unload_bitmaps()
8265 {
8266         int i;
8267
8268         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
8269                 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
8270                         bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
8271                 }
8272         }
8273
8274         // unloaded
8275         Demo_upsell_bitmaps_loaded = 0;
8276 }
8277
8278 void demo_upsell_show_screens()
8279 {
8280         int current_time, k;
8281         int done = 0;
8282
8283         if ( !Demo_upsell_bitmaps_loaded ) {
8284                 demo_upsell_load_bitmaps();
8285                 Demo_upsell_bitmaps_loaded = 1;
8286         }
8287
8288         // may use upsell screens more than once
8289         Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
8290         Demo_upsell_screen_number = 0;
8291         
8292         key_flush();
8293         Mouse_hidden = 1;
8294
8295         while(!done) {
8296
8297                 demo_reset_trailer_timer();
8298
8299                 current_time = timer_get_milliseconds();
8300
8301 // #ifndef THREADED
8302                 os_poll();
8303 // #endif
8304                 k = key_inkey();
8305
8306                 // don't time out, wait for keypress
8307                 /*
8308                 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
8309                         demo_upsell_next_screen();
8310                         k = 0;
8311                 }*/
8312
8313                 if ( k > 0 ) {
8314                         demo_upsell_next_screen();
8315                 }
8316
8317                 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
8318                         Demo_upsell_screen_number--;
8319                         done = 1;
8320                 } else {
8321                         if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
8322                                 done = 1;
8323                         }
8324                 }
8325
8326                 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {             
8327                         gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
8328                         gr_bitmap(0,0);
8329                 }
8330
8331                 if ( done ) {
8332                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
8333                                 gr_fade_out(0);
8334                                 Sleep(300);
8335                         }
8336                 }
8337
8338                 gr_flip();
8339         }
8340
8341         // unload bitmap
8342         demo_upsell_unload_bitmaps();
8343 }
8344
8345 #endif // DEMO
8346
8347 // ----------------------------------------------------------------
8348 //
8349 // DEMO UPSELL SCREENS END
8350 //
8351 // ----------------------------------------------------------------
8352
8353
8354 // ----------------------------------------------------------------
8355 //
8356 // Subspace Ambient Sound START
8357 //
8358 // ----------------------------------------------------------------
8359
8360 static int Subspace_ambient_left_channel = -1;
8361 static int Subspace_ambient_right_channel = -1;
8362
8363 // 
8364 void game_start_subspace_ambient_sound()
8365 {
8366         if ( Subspace_ambient_left_channel < 0 ) {
8367                 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
8368         }
8369
8370         if ( Subspace_ambient_right_channel < 0 ) {
8371                 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
8372         }
8373 }
8374
8375 void game_stop_subspace_ambient_sound()
8376 {
8377         if ( Subspace_ambient_left_channel >= 0 ) {
8378                 snd_stop(Subspace_ambient_left_channel);
8379                 Subspace_ambient_left_channel = -1;
8380         }
8381
8382         if ( Subspace_ambient_right_channel >= 0 ) {
8383                 snd_stop(Subspace_ambient_right_channel);
8384                 Subspace_ambient_right_channel = -1;
8385         }
8386 }
8387
8388 // ----------------------------------------------------------------
8389 //
8390 // Subspace Ambient Sound END
8391 //
8392 // ----------------------------------------------------------------
8393
8394 // ----------------------------------------------------------------
8395 //
8396 // CDROM detection code START
8397 //
8398 // ----------------------------------------------------------------
8399
8400 #define CD_SIZE_72_MINUTE_MAX                   (697000000)
8401
8402 uint game_get_cd_used_space(char *path)
8403 {
8404 #ifndef PLAT_UNIX
8405         uint total = 0;
8406         char use_path[512] = "";
8407         char sub_path[512] = "";
8408         WIN32_FIND_DATA find;
8409         HANDLE find_handle;
8410
8411         // recurse through all files and directories
8412         strcpy(use_path, path);
8413         strcat(use_path, "*.*");
8414         find_handle = FindFirstFile(use_path, &find);
8415
8416         // bogus
8417         if(find_handle == INVALID_HANDLE_VALUE){
8418                 return 0;
8419         }       
8420
8421         // whee
8422         do {
8423                 // subdirectory. make sure to ignore . and ..
8424                 if((find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && stricmp(find.cFileName, ".") && stricmp(find.cFileName, "..")){
8425                         // subsearch
8426                         strcpy(sub_path, path);
8427                         strcat(sub_path, find.cFileName);
8428                         strcat(sub_path, "\\");
8429                         total += game_get_cd_used_space(sub_path);      
8430                 } else {
8431                         total += (uint)find.nFileSizeLow;
8432                 }                               
8433         } while(FindNextFile(find_handle, &find));      
8434
8435         // close
8436         FindClose(find_handle);
8437
8438         // total
8439         return total;
8440 #else
8441         STUB_FUNCTION;
8442         
8443         return 0;
8444 #endif  
8445 }
8446
8447
8448 // if volume_name is non-null, the CD name must match that
8449 int find_freespace_cd(const char *volume_name)
8450 {
8451 #ifndef PLAT_UNIX
8452         char oldpath[MAX_PATH];
8453         char volume[256];
8454         int i;
8455         int cdrom_drive=-1;
8456         int volume_match = 0;
8457         _finddata_t find;
8458         int find_handle;
8459
8460         GetCurrentDirectory(MAX_PATH, oldpath);
8461
8462         for (i = 0; i < 26; i++) 
8463         {
8464 //XSTR:OFF
8465                 char path[]="d:\\";
8466 //XSTR:ON
8467
8468                 path[0] = (char)('A'+i);
8469                 if (GetDriveType(path) == DRIVE_CDROM) {
8470                         cdrom_drive = -3;
8471                         if ( GetVolumeInformation(path, volume, 256, NULL, NULL, NULL, NULL, 0) == TRUE ) {
8472                                 nprintf(("CD", "CD volume: %s\n", volume));
8473                         
8474                                 // check for any CD volume
8475                                 int volume1_present = 0;
8476                                 int volume2_present = 0;
8477                                 int volume3_present = 0;                
8478
8479                                 char full_check[512] = "";
8480
8481                                 // look for setup.exe
8482                                 strcpy(full_check, path);
8483                                 strcat(full_check, "setup.exe");                                
8484                                 find_handle = _findfirst(full_check, &find);
8485                                 if(find_handle != -1){
8486                                         volume1_present = 1;                            
8487                                         _findclose(find_handle);                                
8488                                 }
8489
8490                                 // look for intro.mve
8491                                 strcpy(full_check, path);
8492                                 strcat(full_check, "intro.mve");                                
8493                                 find_handle = _findfirst(full_check, &find);
8494                                 if(find_handle != -1){
8495                                         volume2_present = 1;
8496                                         _findclose(find_handle);                                                
8497                                 }                               
8498
8499                                 // look for endpart1.mve
8500                                 strcpy(full_check, path);
8501                                 strcat(full_check, "endpart1.mve");                             
8502                                 find_handle = _findfirst(full_check, &find);
8503                                 if(find_handle != -1){
8504                                         volume3_present = 1;
8505                                         _findclose(find_handle);                                
8506                                 }                               
8507                         
8508                                 // see if we have the specific CD we're looking for
8509                                 if ( volume_name ) {
8510                                         // volume 1
8511                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_1) && volume1_present) {
8512                                                 volume_match = 1;
8513                                         }
8514                                         // volume 2
8515                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_2) && volume2_present) {
8516                                                 volume_match = 1;
8517                                         }
8518                                         // volume 3
8519                                         if ( !stricmp(volume_name, FS_CDROM_VOLUME_3) && volume3_present) {
8520                                                 volume_match = 1;
8521                                         }
8522                                 } else {                                                                                
8523                                         if ( volume1_present || volume2_present || volume3_present ) {
8524                                                 volume_match = 1;
8525                                         }
8526                                 }
8527                                 
8528                                 // 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                             
8529                                 if ( volume_match ){
8530 #ifdef RELEASE_REAL                                     
8531                                         // 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
8532                                         if(volume2_present || volume3_present) {
8533                                                 // first step - check to make sure its a cdrom
8534                                                 if(GetDriveType(path) != DRIVE_CDROM){                                                  
8535                                                         break;
8536                                                 }
8537
8538 #if !defined(OEM_BUILD)
8539                                                 // oem not on 80 min cds, so dont check tha size
8540                                                 // check its size
8541                                                 uint used_space = game_get_cd_used_space(path);                                                                                 
8542                                                 if(used_space < CD_SIZE_72_MINUTE_MAX){                                                 
8543                                                         break;
8544                                                 }
8545 #endif // !defined(OEM_BUILD)
8546                                         }                                       
8547
8548                                         cdrom_drive = i;
8549                                         break;
8550 #else
8551                                         cdrom_drive = i;
8552                                         break;
8553 #endif // RELEASE_REAL
8554                                 }
8555                         }
8556                 }
8557         }       
8558
8559         SetCurrentDirectory(oldpath);
8560         return cdrom_drive;
8561 #else
8562         STUB_FUNCTION;
8563         
8564         return 0;
8565 #endif  
8566 }
8567
8568 int set_cdrom_path(int drive_num)
8569 {
8570         int rval;
8571
8572         if (drive_num < 0) {                    //no CD
8573 //              #ifndef NDEBUG
8574 //              strcpy(CDROM_dir,"j:\\FreeSpaceCD\\");                          //set directory
8575 //              rval = 1;
8576 //              #else
8577                 strcpy(Game_CDROM_dir,"");                              //set directory
8578                 rval = 0;
8579 //              #endif
8580         } else {
8581                 sprintf(Game_CDROM_dir,NOX("%c:\\"), 'a' + drive_num );                 //set directory
8582                 rval = 1;
8583         }
8584
8585         return rval;
8586 }
8587
8588 int init_cdrom()
8589 {
8590         int i, rval;
8591
8592         //scan for CD, etc.
8593
8594         rval = 1;
8595
8596 #ifndef DEMO
8597         i = find_freespace_cd();
8598
8599         rval = set_cdrom_path(i);
8600
8601         /*
8602         if ( rval ) {
8603                 nprintf(("CD", "Using %s for FreeSpace CD\n", CDROM_dir));
8604         } else {
8605                 nprintf(("CD", "FreeSpace CD not found\n"));
8606         }
8607         */
8608 #endif
8609
8610         return rval;
8611 }
8612
8613 int Last_cd_label_found = 0;
8614 char Last_cd_label[256];
8615
8616 int game_cd_changed()
8617 {
8618 #ifndef PLAT_UNIX
8619         char label[256];
8620         int found;
8621         int changed = 0;
8622         
8623         if ( strlen(Game_CDROM_dir) == 0 ) {
8624                 init_cdrom();
8625         }
8626
8627         found = GetVolumeInformation(Game_CDROM_dir, label, 256, NULL, NULL, NULL, NULL, 0);
8628
8629         if ( found != Last_cd_label_found )     {
8630                 Last_cd_label_found = found;
8631                 if ( found )    {
8632                         mprintf(( "CD '%s' was inserted\n", label ));
8633                         changed = 1;
8634                 } else {
8635                         mprintf(( "CD '%s' was removed\n", Last_cd_label ));
8636                         changed = 1;
8637                 }
8638         } else {
8639                 if ( Last_cd_label_found )      {
8640                         if ( !stricmp( Last_cd_label, label ))  {
8641                                 //mprintf(( "CD didn't change\n" ));
8642                         } else {
8643                                 mprintf(( "CD was changed from '%s' to '%s'\n", Last_cd_label, label ));
8644                                 changed = 1;
8645                         }
8646                 } else {
8647                         // none found before, none found now.
8648                         //mprintf(( "still no CD...\n" ));
8649                 }
8650         }
8651         
8652         Last_cd_label_found = found;
8653         if ( found )    {
8654                 strcpy( Last_cd_label, label );
8655         } else {
8656                 strcpy( Last_cd_label, "" );
8657         }
8658
8659         return changed;
8660 #else
8661         STUB_FUNCTION;
8662         
8663         return 0;
8664 #endif          
8665 }
8666
8667 // check if _any_ FreeSpace2 CDs are in the drive
8668 // return: 1    => CD now in drive
8669 //                        0     =>      Could not find CD, they refuse to put it in the drive
8670 int game_do_cd_check(const char *volume_name)
8671 {       
8672 #if !defined(GAME_CD_CHECK)
8673         return 1;
8674 #else
8675         int cd_present = 0;
8676         int cd_drive_num;
8677
8678         int num_attempts = 0;
8679         int refresh_files = 0;
8680         while(1) {
8681                 int path_set_ok, popup_rval;
8682
8683                 cd_drive_num = find_freespace_cd(volume_name);
8684                 path_set_ok = set_cdrom_path(cd_drive_num);
8685                 if ( path_set_ok ) {
8686                         cd_present = 1;
8687                         if ( refresh_files ) {
8688                                 cfile_refresh();
8689                                 refresh_files = 0;
8690                         }
8691                         break;
8692                 }
8693
8694                 // standalone mode
8695                 if(Is_standalone){
8696                         cd_present = 0;
8697                         break;
8698                 } else {
8699                         // no CD found, so prompt user
8700                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR( "FreeSpace 2 CD not found\n\nInsert a FreeSpace 2 CD to continue", 202));
8701                         refresh_files = 1;
8702                         if ( popup_rval != 1 ) {
8703                                 cd_present = 0;
8704                                 break;
8705                         }
8706
8707                         if ( num_attempts++ > 5 ) {
8708                                 cd_present = 0;
8709                                 break;
8710                         }
8711                 }
8712         }
8713
8714         return cd_present;
8715 #endif
8716 }
8717
8718 // check if _any_ FreeSpace2 CDs are in the drive
8719 // return: 1    => CD now in drive
8720 //                        0     =>      Could not find CD, they refuse to put it in the drive
8721 int game_do_cd_check_specific(const char *volume_name, int cdnum)
8722 {       
8723         int cd_present = 0;
8724         int cd_drive_num;
8725
8726         int num_attempts = 0;
8727         int refresh_files = 0;
8728         while(1) {
8729                 int path_set_ok, popup_rval;
8730
8731                 cd_drive_num = find_freespace_cd(volume_name);
8732                 path_set_ok = set_cdrom_path(cd_drive_num);
8733                 if ( path_set_ok ) {
8734                         cd_present = 1;
8735                         if ( refresh_files ) {
8736                                 cfile_refresh();
8737                                 refresh_files = 0;
8738                         }
8739                         break;
8740                 }
8741
8742                 if(Is_standalone){
8743                         cd_present = 0;
8744                         break;
8745                 } else {
8746                         // no CD found, so prompt user
8747 #if defined(DVD_MESSAGE_HACK)
8748                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8749 #else
8750                         popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cdnum);
8751 #endif
8752                         refresh_files = 1;
8753                         if ( popup_rval != 1 ) {
8754                                 cd_present = 0;
8755                                 break;
8756                         }
8757
8758                         if ( num_attempts++ > 5 ) {
8759                                 cd_present = 0;
8760                                 break;
8761                         }
8762                 }
8763         }
8764
8765         return cd_present;
8766 }
8767
8768 // only need to do this in RELEASE_REAL
8769 int game_do_cd_mission_check(const char *filename)
8770 {       
8771 #ifdef RELEASE_REAL
8772         int cd_num;
8773         int cd_present = 0;
8774         int cd_drive_num;
8775         fs_builtin_mission *m = game_find_builtin_mission(filename);
8776
8777         // check for changed CD
8778         if(game_cd_changed()){
8779                 cfile_refresh();
8780         }
8781
8782         // multiplayer
8783         if((Game_mode & GM_MULTIPLAYER) || Is_standalone){
8784                 return 1;
8785         }
8786
8787         // not builtin, so do a general check (any FS2 CD will do)
8788         if(m == NULL){
8789                 return game_do_cd_check();
8790         }
8791
8792         // does not have any CD requirement, do a general check
8793         if(strlen(m->cd_volume) <= 0){
8794                 return game_do_cd_check();
8795         }
8796
8797         // get the volume
8798         if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_1)){
8799                 cd_num = 1;
8800         } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_2)){
8801                 cd_num = 2;
8802 #ifndef MAKE_FS1
8803         } else if(!stricmp(m->cd_volume, FS_CDROM_VOLUME_3)){
8804                 cd_num = 3; 
8805 #endif
8806         } else {
8807                 return game_do_cd_check();
8808         }
8809
8810         // did we find the cd?
8811         if(find_freespace_cd(m->cd_volume) >= 0){
8812                 return 1;
8813         }
8814
8815         // make sure the volume exists
8816         int num_attempts = 0;
8817         int refresh_files = 0;
8818         while(1){
8819                 int path_set_ok, popup_rval;
8820
8821                 cd_drive_num = find_freespace_cd(m->cd_volume);
8822                 path_set_ok = set_cdrom_path(cd_drive_num);
8823                 if ( path_set_ok ) {
8824                         cd_present = 1;
8825                         if ( refresh_files ) {
8826                                 cfile_refresh();
8827                                 refresh_files = 0;
8828                         }
8829                         break;
8830                 }
8831
8832                 // no CD found, so prompt user
8833 #if defined(DVD_MESSAGE_HACK)
8834                 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert DVD", 1468));
8835 #else
8836                 popup_rval = popup(PF_BODY_BIG, 1, POPUP_OK, XSTR("Please insert CD %d", 1468), cd_num);
8837 #endif
8838
8839                 refresh_files = 1;
8840                 if ( popup_rval != 1 ) {
8841                         cd_present = 0;
8842                         break;
8843                 }
8844
8845                 if ( num_attempts++ > 5 ) {
8846                         cd_present = 0;
8847                         break;
8848                 }
8849         }       
8850
8851         return cd_present;
8852 #else
8853         return 1;
8854 #endif
8855 }
8856
8857 // ----------------------------------------------------------------
8858 //
8859 // CDROM detection code END
8860 //
8861 // ----------------------------------------------------------------
8862
8863 // ----------------------------------------------------------------
8864 //
8865 // Language Autodetection stuff
8866 //
8867
8868 // this layout order must match Lcl_languages in localize.cpp in order for the
8869 // correct language to be detected
8870 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
8871 #ifdef MAKE_FS1
8872         1366105450,                             // English
8873 #else
8874         589986744,                              // English
8875 #endif
8876         -1132430286,                    // German
8877         0,                                              // French
8878         -1131728960,                                    // Polish
8879 };
8880
8881 // default setting is "-1" to use config file with English as fall back
8882 // DO NOT change the default setting here or something uncouth might happen
8883 // in the localization code
8884 int detect_lang()
8885 {
8886         uint file_checksum;             
8887         int idx;
8888
8889         // try and open the file to verify
8890         CFILE *detect = cfopen("font01.vf", "rb");
8891         
8892         // will use default setting if something went wrong
8893         if (!detect) {
8894                 return -1;
8895         }       
8896
8897         // get the long checksum of the file
8898         file_checksum = 0;
8899         cfseek(detect, 0, SEEK_SET);    
8900         cf_chksum_long(detect, &file_checksum);
8901         cfclose(detect);
8902         detect = NULL;  
8903
8904         // now compare the checksum/filesize against known #'s
8905         for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
8906                 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
8907                         return idx;
8908                 }
8909         }
8910
8911         // notify if a match was not found, include detected checksum
8912         printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
8913         printf("Using default language...\n\n");
8914         
8915         return -1;
8916 }
8917
8918 //
8919 // End Auto Lang stuff
8920 //
8921 // ----------------------------------------------------------------
8922
8923 // ----------------------------------------------------------------
8924 // SHIPS TBL VERIFICATION STUFF
8925 //
8926
8927 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8928 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8929         #define NUM_SHIPS_TBL_CHECKSUMS         3
8930 #else
8931         #define NUM_SHIPS_TBL_CHECKSUMS         1
8932 #endif
8933
8934 #ifdef FS2_DEMO
8935 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8936         1696074201,                                             // FS2 demo
8937 };
8938 #elif FS1_DEMO
8939 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8940         1603375034,                                             // FS1 DEMO
8941 };
8942 #elif MAKE_FS1
8943 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8944         -129679197,                                             // FS1 Full 1.06 (US)
8945         7762567,                                                // FS1 SilentThreat
8946         1555372475                                              // FS1 Full 1.06 (German)
8947 };
8948 #else
8949 /*
8950 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8951         -463907578,                                             // US - beta 1
8952         1696074201,                                             // FS2 demo
8953 };
8954 */
8955 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
8956 //      -1022810006,                                    // 1.0 FULL
8957         -1254285366                                             // 1.2 FULL (German)
8958 };
8959 #endif
8960
8961 void verify_ships_tbl()
8962 {       
8963         /*
8964 #ifdef NDEBUG
8965         Game_ships_tbl_valid = 1;
8966 #else
8967         */
8968         uint file_checksum;             
8969         int idx;
8970
8971         // detect if the packfile exists
8972         CFILE *detect = cfopen("ships.tbl", "rb");
8973         Game_ships_tbl_valid = 0;        
8974         
8975         // not mission-disk
8976         if(!detect){
8977                 Game_ships_tbl_valid = 0;
8978                 return;
8979         }       
8980
8981         // get the long checksum of the file
8982         file_checksum = 0;
8983         cfseek(detect, 0, SEEK_SET);    
8984         cf_chksum_long(detect, &file_checksum);
8985         cfclose(detect);
8986         detect = NULL;  
8987
8988         // now compare the checksum/filesize against known #'s
8989         for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
8990                 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
8991                         Game_ships_tbl_valid = 1;
8992                         return;
8993                 }
8994         }
8995 // #endif
8996 }
8997
8998 DCF(shipspew, "display the checksum for the current ships.tbl")
8999 {
9000         uint file_checksum;
9001         CFILE *detect = cfopen("ships.tbl", "rb");
9002         // get the long checksum of the file
9003         file_checksum = 0;
9004         cfseek(detect, 0, SEEK_SET);    
9005         cf_chksum_long(detect, &file_checksum);
9006         cfclose(detect);
9007
9008         dc_printf("%d", file_checksum);
9009 }
9010
9011 // ----------------------------------------------------------------
9012 // WEAPONS TBL VERIFICATION STUFF
9013 //
9014
9015 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
9016 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
9017         #define NUM_WEAPONS_TBL_CHECKSUMS               3
9018 #else
9019         #define NUM_WEAPONS_TBL_CHECKSUMS               1
9020 #endif
9021
9022 #ifdef FS2_DEMO
9023 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9024         -266420030,                             // demo 1
9025 };
9026 #elif FS1_DEMO
9027 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9028         -1246928725,                    // FS1 DEMO
9029 };
9030 #elif MAKE_FS1
9031 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9032         -834598107,                             // FS1 1.06 Full (US)
9033         -1652231417,                    // FS1 SilentThreat
9034         720209793                               // FS1 1.06 Full (German)
9035 };
9036 #else
9037 /*
9038 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9039         141718090,                              // US - beta 1
9040         -266420030,                             // demo 1
9041 };
9042 */
9043 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
9044 //      399297860,                              // 1.0 FULL     
9045         -553984927                              // 1.2 FULL (german)
9046 };
9047 #endif
9048
9049 void verify_weapons_tbl()
9050 {       
9051         /*
9052 #ifdef NDEBUG
9053         Game_weapons_tbl_valid = 1;
9054 #else
9055         */
9056         uint file_checksum;
9057         int idx;
9058
9059         // detect if the packfile exists
9060         CFILE *detect = cfopen("weapons.tbl", "rb");
9061         Game_weapons_tbl_valid = 0;      
9062         
9063         // not mission-disk
9064         if(!detect){
9065                 Game_weapons_tbl_valid = 0;
9066                 return;
9067         }       
9068
9069         // get the long checksum of the file
9070         file_checksum = 0;
9071         cfseek(detect, 0, SEEK_SET);    
9072         cf_chksum_long(detect, &file_checksum);
9073         cfclose(detect);
9074         detect = NULL;  
9075
9076         // now compare the checksum/filesize against known #'s
9077         for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
9078                 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
9079                         Game_weapons_tbl_valid = 1;
9080                         return;
9081                 }
9082         }
9083 // #endif
9084 }
9085
9086 DCF(wepspew, "display the checksum for the current weapons.tbl")
9087 {
9088         uint file_checksum;
9089         CFILE *detect = cfopen("weapons.tbl", "rb");
9090         // get the long checksum of the file
9091         file_checksum = 0;
9092         cfseek(detect, 0, SEEK_SET);    
9093         cf_chksum_long(detect, &file_checksum);
9094         cfclose(detect);
9095
9096         dc_printf("%d", file_checksum);
9097 }
9098
9099 // if the game is running using hacked data
9100 int game_hacked_data()
9101 {
9102         // hacked!
9103         if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
9104                 return 1;
9105         }
9106
9107         // not hacked
9108         return 0;
9109 }
9110
9111 void display_title_screen()
9112 {
9113 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
9114         ///int title_bitmap;
9115
9116         // load bitmap
9117         int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
9118         if (title_bitmap == -1) {
9119                 return;
9120         }
9121
9122 #ifndef PLAT_UNIX
9123         // d3d          
9124         if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9125                 extern void d3d_start_frame();
9126                 d3d_start_frame();
9127         }
9128 #endif
9129
9130         // set
9131         gr_set_bitmap(title_bitmap);
9132
9133         // draw
9134         gr_bitmap(0, 0);
9135
9136 #ifndef PLAT_UNIX
9137         // d3d  
9138         if((gr_screen.mode == GR_DIRECT3D) && (Gr_bitmap_poly)){
9139                 extern void d3d_stop_frame();
9140                 d3d_stop_frame();
9141         }
9142 #endif
9143
9144         // flip
9145         gr_flip();
9146
9147         bm_unload(title_bitmap);
9148 #endif  // FS2_DEMO || OEM_BUILD || FS1_DEMO
9149 }
9150
9151 // return true if the game is running with "low memory", which is less than 48MB
9152 bool game_using_low_mem()
9153 {
9154         if (Use_low_mem == 0) {
9155                 return false;
9156         } else {
9157                 return true;
9158         }
9159 }