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