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