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