]> icculus.org git repositories - taylor/freespace2.git/blob - src/freespace2/freespace.cpp
add stubbed graphics for standalone server
[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_gui.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         if (Is_standalone) {
2327                 std_init_standalone();
2328         } else {                
2329                 os_init( Osreg_class_name, Osreg_app_name );
2330                 os_set_title(Osreg_title);
2331         }
2332
2333         // initialize localization module. Make sure this is down AFTER initialzing OS.
2334 //      int t1 = timer_get_milliseconds();
2335         lcl_init( detect_lang() );
2336         lcl_xstr_init();
2337 //      mprintf(("LCL_INIT() TOOK %d MS\n", timer_get_milliseconds()-t1));
2338
2339         // verify that he has a valid ships.tbl (will Game_ships_tbl_valid if so)
2340         verify_ships_tbl();
2341
2342         // verify that he has a valid weapons.tbl
2343         verify_weapons_tbl();
2344
2345         // Output version numbers to registry for auto patching purposes
2346         os_config_write_uint(NOX("Version"), NOX("Major"), FS_VERSION_MAJOR);
2347         os_config_write_uint(NOX("Version"), NOX("Minor"), FS_VERSION_MINOR);
2348         os_config_write_uint(NOX("Version"), NOX("Build"), FS_VERSION_BUILD);
2349
2350         Use_joy_mouse = 0;              //os_config_read_uint( NULL, NOX("JoystickMovesCursor"), 1 );
2351         //Use_palette_flash = os_config_read_uint( NULL, NOX("PaletteFlash"), 0 );
2352         Use_low_mem = os_config_read_uint( NULL, NOX("LowMem"), 0 );
2353
2354         // show the FPS counter if the config file says so
2355         Show_framerate = os_config_read_uint( "Video", "ShowFPS", Show_framerate );
2356
2357 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
2358         Asteroids_enabled = 1;          
2359 #endif
2360
2361 /////////////////////////////
2362 // SOUND INIT START
2363 /////////////////////////////
2364
2365         if (!Is_standalone) {
2366                 snd_init();
2367         }
2368
2369 /////////////////////////////
2370 // SOUND INIT END
2371 /////////////////////////////
2372
2373
2374         gr_init();
2375
2376
2377 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
2378         // add title screen
2379         if(!Is_standalone){
2380                 display_title_screen();
2381         }
2382 #endif
2383
2384         // If less than 48MB of RAM, use low memory model.
2385         if ( (Freespace_total_ram < 48) || Use_low_mem )        {
2386                 mprintf(( "Using normal memory settings...\n" ));
2387                 bm_set_low_mem(1);              // Use every other frame of bitmaps
2388         } else {
2389                 mprintf(( "Using high memory settings...\n" ));
2390                 bm_set_low_mem(0);              // Use all frames of bitmaps
2391         }
2392
2393         // load non-darkening pixel defs
2394         palman_load_pixels();
2395
2396         // hud shield icon stuff
2397         hud_shield_game_init();
2398
2399         control_config_common_init();                           // sets up localization stuff in the control config
2400         parse_rank_tbl();
2401         parse_medal_tbl();
2402         cutscene_init();
2403         key_init();
2404         mouse_init();
2405         gamesnd_parse_soundstbl();
2406         radar_init();
2407         gameseq_init();
2408         multi_init();   
2409
2410         // standalone's don't use hte joystick and it seems to sometimes cause them to not get shutdown properly
2411         if(!Is_standalone){
2412                 joy_init();
2413         }
2414
2415         player_controls_init();
2416         model_init();   
2417
2418         //if(!Is_standalone){
2419                 event_music_init();
2420         //}     
2421
2422         obj_init();     
2423         mflash_game_init();     
2424         weapon_init();  
2425         ai_init();              
2426         ship_init();                                            // read in ships.tbl    
2427         player_init();  
2428         mission_campaign_init();                // load in the default campaign 
2429         anim_init();
2430 //      navmap_init();                                          // init the navigation map system
2431         context_help_init();                    
2432         techroom_intel_init();                  // parse species.tbl, load intel info   
2433         // initialize psnet
2434         psnet_init( Multi_options_g.protocol, Multi_options_g.port );                                           // initialize the networking code               
2435         init_animating_pointer();       
2436         asteroid_init();
2437         mission_brief_common_init();    // Mark all the briefing structures as empty.           
2438         gr_font_init();                                 // loads up all fonts           
2439
2440         neb2_init();                                            // fullneb stuff
2441         nebl_init();
2442         stars_init();
2443         ssm_init();     
2444         player_tips_init();                             // helpful tips
2445         beam_init();
2446         
2447         // load the list of pilot pic filenames (for barracks and pilot select popup quick reference)
2448         pilot_load_pic_list();  
2449         pilot_load_squad_pic_list();
2450
2451         load_animating_pointer(NOX("cursor"), 0, 0);    
2452
2453         // initialize alpha colors
2454         alpha_colors_init();    
2455
2456         Viewer_mode = 0;
2457 //      Game_music_paused = 0;
2458         Game_paused = 0;
2459
2460
2461         nprintf(("General", "Ships.tbl is : %s\n", Game_ships_tbl_valid ? "VALID" : "INVALID!!!!"));
2462         nprintf(("General", "Weapons.tbl is : %s\n", Game_weapons_tbl_valid ? "VALID" : "INVALID!!!!"));
2463
2464         mprintf(("cfile_init() took %d\n", e1 - s1));
2465         // mprintf(("1000 cfopens() took %d\n", e2 - s2));      
2466 }
2467
2468 char transfer_text[128];
2469
2470 float   Start_time = 0.0f;
2471
2472 float Framerate = 0.0f;
2473
2474 float Timing_total = 0.0f;
2475 float Timing_render2 = 0.0f;
2476 float Timing_render3 = 0.0f;
2477 float Timing_flip = 0.0f;
2478 float Timing_clear = 0.0f;
2479
2480 MONITOR(NumPolysDrawn);
2481 MONITOR(NumPolys);
2482 MONITOR(NumVerts);
2483 MONITOR(BmpUsed);
2484 MONITOR(BmpNew);
2485
2486 void game_get_framerate()
2487 {       
2488         char text[128] = "";
2489
2490         if ( frame_int == -1 )  {
2491                 int i;
2492                 for (i=0; i<FRAME_FILTER; i++ ) {
2493                         frametimes[i] = 0.0f;
2494                 }
2495                 frametotal = 0.0f;
2496                 frame_int = 0;
2497         }
2498         frametotal -= frametimes[frame_int];
2499         frametotal += flFrametime;
2500         frametimes[frame_int] = flFrametime;
2501         frame_int = (frame_int + 1 ) % FRAME_FILTER;
2502
2503         if ( frametotal != 0.0 )        {
2504                 if ( Framecount >= FRAME_FILTER )
2505                         Framerate = FRAME_FILTER / frametotal;
2506                 else
2507                         Framerate = Framecount / frametotal;
2508                 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: %.1f"), Framerate );
2509         } else {
2510                 SDL_snprintf( text, SDL_arraysize(text), NOX("FPS: ?") );
2511         }
2512         Framecount++;
2513
2514         if (Show_framerate)     {
2515                 gr_set_color_fast(&HUD_color_debug);
2516                 gr_string( 570, 2, text );
2517         }
2518 }
2519
2520 void game_show_framerate()
2521 {       
2522         float   cur_time;
2523
2524         cur_time = f2fl(timer_get_approx_seconds());
2525         if (cur_time - Start_time > 30.0f) {
2526                 mprintf(("%i frames executed in %7.3f seconds, %7.3f frames per second.\n", Framecount, cur_time - Start_time, Framecount/(cur_time - Start_time)));
2527                 Start_time += 1000.0f;
2528         }
2529
2530         //mprintf(( "%s\n", text ));
2531
2532 #ifndef NDEBUG
2533         if ( Debug_dump_frames )
2534                 return;
2535 #endif  
2536
2537         // possibly show control checking info
2538         control_check_indicate();
2539
2540 //      int bitmaps_used_this_frame, bitmaps_new_this_frame;
2541 //      bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
2542 //      MONITOR_INC(BmpUsed, bitmaps_used_this_frame);
2543 // MONITOR_INC(BmpNew, bitmaps_new_this_frame);
2544
2545 #ifndef NDEBUG
2546         if ( Show_cpu == 1 ) {
2547                 
2548                 int sx,sy,dy;
2549                 sx = 530;
2550                 sy = 15;
2551                 dy = gr_get_font_height() + 1;
2552
2553                 gr_set_color_fast(&HUD_color_debug);
2554
2555                 {
2556                         extern int Gr_textures_in;
2557                         gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2558                         sy += dy;
2559                 }
2560 //              gr_printf( sx, sy, "BPP: %d", gr_screen.bits_per_pixel );
2561 //              sy += dy;
2562                 gr_printf( sx, sy, NOX("DMA: %s"), transfer_text );
2563                 sy += dy;
2564                 gr_printf( sx, sy, NOX("POLYP: %d"), modelstats_num_polys );
2565                 sy += dy;
2566                 gr_printf( sx, sy, NOX("POLYD: %d"), modelstats_num_polys_drawn );
2567                 sy += dy;
2568                 gr_printf( sx, sy, NOX("VERTS: %d"), modelstats_num_verts );
2569                 sy += dy;
2570
2571                 {
2572
2573                         extern int Num_pairs;           // Number of object pairs that were checked.
2574                         gr_printf( sx, sy, NOX("PAIRS: %d"), Num_pairs );
2575                         sy += dy;
2576
2577                         extern int Num_pairs_checked;   // What percent of object pairs were checked.
2578                         gr_printf( sx, sy, NOX("FVI: %d"), Num_pairs_checked );
2579                         sy += dy;
2580                         Num_pairs_checked = 0;
2581
2582                 }
2583
2584                 gr_printf( sx, sy, NOX("Snds: %d"), snd_num_playing() );
2585                 sy += dy;
2586
2587                 if ( Timing_total > 0.01f )     {
2588                         gr_printf(  sx, sy, NOX("CLEAR: %.0f%%"), Timing_clear*100.0f/Timing_total );
2589                         sy += dy;
2590                         gr_printf( sx, sy, NOX("REND2D: %.0f%%"), Timing_render2*100.0f/Timing_total );
2591                         sy += dy;
2592                         gr_printf( sx, sy, NOX("REND3D: %.0f%%"), Timing_render3*100.0f/Timing_total );
2593                         sy += dy;
2594                         gr_printf( sx, sy, NOX("FLIP: %.0f%%"), Timing_flip*100.0f/Timing_total );
2595                         sy += dy;
2596                         gr_printf( sx, sy, NOX("GAME: %.0f%%"), (Timing_total-(Timing_render2+Timing_render3+Timing_flip+Timing_clear))*100.0f/Timing_total );
2597                 }
2598         }
2599                 
2600         if ( Show_mem  ) {
2601                 
2602                 int sx,sy,dy;
2603                 sx = 530;
2604                 sy = 15;
2605                 dy = gr_get_font_height() + 1;
2606
2607                 gr_set_color_fast(&HUD_color_debug);
2608
2609                 {
2610                         extern int TotalRam;
2611                         gr_printf( sx, sy, NOX("DYN: %d KB\n"), TotalRam/1024 );
2612                         sy += dy;
2613                 }       
2614
2615                 {
2616                         extern int Model_ram;
2617                         gr_printf( sx, sy, NOX("POF: %d KB\n"), Model_ram/1024 );
2618                         sy += dy;
2619                 }       
2620
2621                 gr_printf( sx, sy, NOX("BMP: %d KB\n"), bm_texture_ram/1024 );
2622                 sy += dy;
2623                 gr_printf( sx, sy, NOX("S-SRAM: %d KB\n"), Snd_sram/1024 );             // mem used to store game sound
2624                 sy += dy;
2625
2626                 {
2627                         extern int Gr_textures_in;
2628                         gr_printf( sx, sy, NOX("VRAM: %d KB\n"), Gr_textures_in/1024 );
2629                 }
2630         }
2631
2632
2633         if ( Show_player_pos ) {
2634                 int sx, sy;
2635                 sx = 320;
2636                 sy = 100;
2637                 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));
2638         }
2639
2640         MONITOR_INC(NumPolys, modelstats_num_polys);
2641         MONITOR_INC(NumPolysDrawn, modelstats_num_polys_drawn );
2642         MONITOR_INC(NumVerts, modelstats_num_verts );
2643
2644         modelstats_num_polys = 0;
2645         modelstats_num_polys_drawn = 0;
2646         modelstats_num_verts = 0;
2647         modelstats_num_sortnorms = 0;
2648 #endif
2649 }
2650
2651 void game_show_standalone_framerate()
2652 {
2653         float frame_rate=30.0f;
2654         if ( frame_int == -1 )  {
2655                 int i;
2656                 for (i=0; i<FRAME_FILTER; i++ ) {
2657                         frametimes[i] = 0.0f;
2658                 }
2659                 frametotal = 0.0f;
2660                 frame_int = 0;
2661         }
2662         frametotal -= frametimes[frame_int];
2663         frametotal += flFrametime;
2664         frametimes[frame_int] = flFrametime;
2665         frame_int = (frame_int + 1 ) % FRAME_FILTER;
2666
2667         if ( frametotal != 0.0 )        {
2668                 if ( Framecount >= FRAME_FILTER ){
2669                         frame_rate = FRAME_FILTER / frametotal;
2670                 } else {
2671                         frame_rate = Framecount / frametotal;
2672                 }
2673         }
2674         std_set_standalone_fps(frame_rate);
2675         Framecount++;
2676 }
2677
2678 // function to show the time remaining in a mission.  Used only when the end-mission sexpression is used
2679 void game_show_time_left()
2680 {
2681         int diff;
2682
2683         // mission_end_time is a global from missionparse.cpp that contains the mission time at which the
2684         // mission should end (in fixed seconds).  There is code in missionparse.cpp which actually handles
2685         // checking how much time is left
2686
2687         if ( Mission_end_time == -1 ){
2688                 return;
2689         }
2690
2691         diff = f2i(Mission_end_time - Missiontime);
2692         // be sure to bash to 0.  diff could be negative on frame that we quit mission
2693         if ( diff < 0 ){
2694                 diff = 0;
2695         }
2696
2697         hud_set_default_color();
2698         gr_printf( 5, 40, XSTR( "Mission time remaining: %d seconds", 179), diff );
2699 }
2700
2701 //========================================================================================
2702 //=================== NEW DEBUG CONSOLE COMMANDS TO REPLACE OLD DEBUG PAUSE MENU =========
2703 //========================================================================================
2704
2705 #ifndef NDEBUG
2706
2707 DCF(ai_pause,"Pauses ai")
2708 {
2709         if ( Dc_command )       {       
2710                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
2711                 if ( Dc_arg_type & ARG_TRUE )   ai_paused = 1;  
2712                 else if ( Dc_arg_type & ARG_FALSE ) ai_paused = 0;      
2713                 else if ( Dc_arg_type & ARG_NONE ) ai_paused = !ai_paused;      
2714
2715                 if (ai_paused)  {       
2716                         obj_init_all_ships_physics();
2717                 }
2718         }       
2719         if ( Dc_help )  dc_printf( "Usage: ai_paused [bool]\nSets ai_paused to true or false.  If nothing passed, then toggles it.\n" );        
2720         if ( Dc_status )        dc_printf( "ai_paused is %s\n", (ai_paused?"TRUE":"FALSE") );   
2721 }
2722
2723 DCF(single_step,"Single steps the game")
2724 {
2725         if ( Dc_command )       {       
2726                 dc_get_arg(ARG_TRUE|ARG_FALSE|ARG_NONE);                
2727                 if ( Dc_arg_type & ARG_TRUE )   game_single_step = 1;   
2728                 else if ( Dc_arg_type & ARG_FALSE ) game_single_step = 0;       
2729                 else if ( Dc_arg_type & ARG_NONE ) game_single_step = !game_single_step;        
2730
2731                 last_single_step = 0;   // Make so single step waits a frame before stepping
2732
2733         }       
2734         if ( Dc_help )  dc_printf( "Usage: single_step [bool]\nSets single_step to true or false.  If nothing passed, then toggles it.\n" );    
2735         if ( Dc_status )        dc_printf( "single_step is %s\n", (game_single_step?"TRUE":"FALSE") );  
2736 }
2737
2738 DCF_BOOL(physics_pause, physics_paused)
2739 DCF_BOOL(ai_rendering, Ai_render_debug_flag)
2740 DCF_BOOL(ai_firing, Ai_firing_enabled )
2741
2742 // Create some simple aliases to these commands...
2743 debug_command dc_s("s","shortcut for single_step",dcf_single_step);
2744 debug_command dc_p("p","shortcut for physics_pause", dcf_physics_pause );
2745 debug_command dc_r("r","shortcut for ai_rendering", dcf_ai_rendering );
2746 debug_command dc_f("f","shortcut for ai_firing", dcf_ai_firing);
2747 debug_command dc_a("a","shortcut for ai_pause", dcf_ai_pause);
2748 #endif
2749
2750 //========================================================================================
2751 //========================================================================================
2752
2753
2754 void game_training_pause_do()
2755 {
2756         int key;
2757
2758         key = game_check_key();
2759         if (key > 0){
2760                 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
2761         }
2762
2763         gr_flip();
2764 }
2765
2766
2767 void game_increase_skill_level()
2768 {
2769         Game_skill_level++;
2770         if (Game_skill_level >= NUM_SKILL_LEVELS){
2771                 Game_skill_level = 0;
2772         }
2773 }
2774
2775 int     Player_died_time;
2776
2777 int View_percent = 100;
2778
2779
2780 DCF(view, "Sets the percent of the 3d view to render.")
2781 {
2782         if ( Dc_command ) {
2783                 dc_get_arg(ARG_INT);
2784                 if ( (Dc_arg_int >= 5 ) || (Dc_arg_int <= 100) ) {
2785                         View_percent = Dc_arg_int;
2786                 } else {
2787                         dc_printf( "Illegal value for view. (Must be from 5-100) \n\n");
2788                         Dc_help = 1;
2789                 }
2790         }
2791
2792         if ( Dc_help ) {
2793                 dc_printf("Usage: view [n]\nwhere n is percent of view to show (5-100).\n");
2794         }
2795         
2796         if ( Dc_status ) {
2797                 dc_printf("View is set to %d%%\n", View_percent );
2798         }
2799 }
2800
2801
2802 // Set the clip region for the 3d rendering window
2803 void game_set_view_clip()
2804 {
2805         if ((Game_mode & GM_DEAD) || (supernova_active() >= 2)) {
2806                 // Set the clip region for the letterbox "dead view"
2807                 int yborder = gr_screen.max_h/4;
2808
2809                 //      Numeric constants encouraged by J "pig farmer" S, who shall remain semi-anonymous.
2810                 // J.S. I've changed my ways!! See the new "no constants" code!!!
2811                 gr_set_clip(0, yborder, gr_screen.max_w, gr_screen.max_h - yborder*2 ); 
2812         } else {
2813                 // Set the clip region for normal view
2814                 if ( View_percent >= 100 )      {
2815                         gr_reset_clip();
2816                 } else {
2817                         int xborder, yborder;
2818
2819                         if ( View_percent < 5 ) {
2820                                 View_percent = 5;
2821                         }
2822
2823                         float fp = i2fl(View_percent)/100.0f;
2824                         int fi = fl2i(fl_sqrt(fp)*100.0f);
2825                         if ( fi > 100 ) fi=100;
2826                         
2827                         xborder = ( gr_screen.max_w*(100-fi) )/200;
2828                         yborder = ( gr_screen.max_h*(100-fi) )/200;
2829
2830                         gr_set_clip(xborder, yborder, gr_screen.max_w-xborder*2,gr_screen.max_h-yborder*2 );
2831                 }
2832         }
2833 }
2834
2835
2836 void show_debug_stuff()
2837 {
2838         int     i;
2839         int     laser_count = 0, missile_count = 0;
2840
2841         for (i=0; i<MAX_OBJECTS; i++) {
2842                 if (Objects[i].type == OBJ_WEAPON){
2843                         if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_LASER){
2844                                 laser_count++;
2845                         } else if (Weapon_info[Weapons[Objects[i].instance].weapon_info_index].subtype == WP_MISSILE){
2846                                 missile_count++;
2847                         }
2848                 }
2849         }
2850
2851         nprintf(("Mike", "Frame: %i Lasers: %4i, Missiles: %4i\n", Framecount, laser_count, missile_count));
2852 }
2853
2854 extern int Tool_enabled;
2855 int tst = 0;
2856 time_t tst_time = 0;
2857 int tst_big = 0;
2858 vector tst_pos;
2859 int tst_bitmap = -1;
2860 float tst_x, tst_y;
2861 float tst_offset, tst_offset_total;
2862 int tst_mode;
2863 int tst_stamp;
2864 void game_tst_frame_pre()
2865 {
2866         // start tst
2867         if(tst == 3){
2868                 tst = 0;
2869
2870                 // screen position
2871                 vertex v;
2872                 g3_rotate_vertex(&v, &tst_pos);
2873                 g3_project_vertex(&v);  
2874         
2875                 // offscreen
2876                 if(!((v.sx >= 0) && (v.sx <= gr_screen.max_w) && (v.sy >= 0) && (v.sy <= gr_screen.max_h))){
2877                         return;
2878                 }       
2879
2880                 // big ship? always tst
2881                 if(tst_big){
2882                         // within 3000 meters
2883                         if( vm_vec_dist_quick(&tst_pos, &Eye_position) <= 3000.0f){
2884                                 tst = 2;                                
2885                         }
2886                 } else {                        
2887                         // within 300 meters
2888                         if( (vm_vec_dist_quick(&tst_pos, &Eye_position) <= 300.0f) && ((tst_time == 0) || ((time(NULL) - tst_time) >= 10)) ){
2889                                 tst = 2;                                
2890                         } 
2891                 }                       
2892         }
2893
2894 }
2895 void game_tst_frame()
2896 {
2897         int left = 0;
2898
2899         if(!Tool_enabled){
2900                 return;
2901         }
2902         
2903         // setup tst
2904         if(tst == 2){           
2905                 tst_time = time(NULL);
2906
2907                 // load the tst bitmap          
2908                 switch((int)frand_range(0.0f, 3.0)){
2909                 case 0:                 
2910                         tst_bitmap = bm_load("ig_jim");
2911                         left = 1;
2912                         mprintf(("TST 0\n"));
2913                         break;
2914
2915                 case 1:
2916                         tst_bitmap = bm_load("ig_kan");
2917                         left = 0;
2918                         mprintf(("TST 1\n"));
2919                         break;
2920
2921                 case 2:
2922                         tst_bitmap = bm_load("ig_jim");
2923                         left = 1;
2924                         mprintf(("TST 2\n"));
2925                         break;
2926                         
2927                 default:                        
2928                         tst_bitmap = bm_load("ig_kan");
2929                         left = 0;
2930                         mprintf(("TST 3\n"));
2931                         break;
2932                 }
2933
2934                 if(tst_bitmap < 0){
2935                         tst = 0;
2936                         return;
2937                 }               
2938
2939                 // get the tst bitmap dimensions
2940                 int w, h;
2941                 bm_get_info(tst_bitmap, &w, &h);
2942
2943                 // tst y
2944                 tst_y = frand_range(0.0f, (float)gr_screen.max_h - h);
2945
2946                 snd_play(&Snds[SND_VASUDAN_BUP]);
2947
2948                 // tst x and direction
2949                 tst_mode = 0;
2950                 if(left){
2951                         tst_x = (float)-w;
2952                         tst_offset_total = (float)w;
2953                         tst_offset = (float)w;
2954                 } else {
2955                         tst_x = (float)gr_screen.max_w;
2956                         tst_offset_total = (float)-w;
2957                         tst_offset = (float)w;
2958                 }
2959
2960                 tst = 1;
2961         }
2962
2963         // run tst
2964         if(tst == 1){
2965                 float diff = (tst_offset_total / 0.5f) * flFrametime;
2966
2967                 // move the bitmap
2968                 if(tst_mode == 0){
2969                         tst_x += diff;
2970                         
2971                         tst_offset -= fl_abs(diff);
2972                 } else if(tst_mode == 2){
2973                         tst_x -= diff;
2974                         
2975                         tst_offset -= fl_abs(diff);
2976                 }
2977
2978                 // draw the bitmap
2979                 gr_set_bitmap(tst_bitmap, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
2980                 gr_bitmap((int)tst_x, (int)tst_y);
2981
2982                 if(tst_mode == 1){
2983                         if(timestamp_elapsed_safe(tst_stamp, 1100)){
2984                                 tst_mode = 2;
2985                         }
2986                 } else {
2987                         // if we passed the switch point
2988                         if(tst_offset <= 0.0f){
2989                                 // switch modes
2990                                 switch(tst_mode){
2991                                 case 0:
2992                                         tst_mode = 1;
2993                                         tst_stamp = timestamp(1000);
2994                                         tst_offset = fl_abs(tst_offset_total);
2995                                         break;                          
2996
2997                                 case 2:                         
2998                                         tst = 0;
2999                                         return;
3000                                 }
3001                         }                               
3002                 }
3003         }
3004 }
3005 void game_tst_mark(object *objp, ship *shipp)
3006 {
3007         ship_info *sip; 
3008
3009         if(!Tool_enabled){
3010                 return;
3011         }
3012
3013         // bogus
3014         if((objp == NULL) || (shipp == NULL) || (shipp->ship_info_index < 0) || (shipp->ship_info_index >= Num_ship_types)){
3015                 return;
3016         }
3017         sip = &Ship_info[shipp->ship_info_index];
3018
3019         // already tst
3020         if(tst){
3021                 return;
3022         }
3023
3024         tst_pos = objp->pos;
3025         if(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)){
3026                 tst_big = 1;
3027         }
3028         tst = 3;
3029 }
3030
3031 extern void render_shields();
3032
3033 void player_repair_frame(float frametime)
3034 {
3035         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
3036                 int idx;
3037                 for(idx=0;idx<MAX_PLAYERS;idx++){
3038                         net_player *np;
3039
3040                         np = &Net_players[idx];
3041
3042                         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)){
3043
3044                                 // don't rearm/repair if the player is dead or dying/departing
3045                                 if ( !NETPLAYER_IS_DEAD(np) && !(Ships[Objects[np->player->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) ) {
3046                                         ai_do_repair_frame(&Objects[Net_players[idx].player->objnum],&Ai_info[Ships[Objects[Net_players[idx].player->objnum].instance].ai_index],frametime);
3047                                 }
3048                         }
3049                 }
3050         }       
3051         if ( (Player_obj != NULL) && (Player_obj->type == OBJ_SHIP) && !(Game_mode & GM_STANDALONE_SERVER) && (Player_ship != NULL) && !(Player_ship->flags & SF_DYING) ) {
3052                 ai_do_repair_frame(Player_obj, &Ai_info[Ships[Player_obj->instance].ai_index], frametime);
3053         }
3054 }
3055
3056
3057 #ifndef NDEBUG
3058 #define NUM_FRAMES_TEST         300
3059 #define NUM_MIXED_SOUNDS        16
3060 void do_timing_test(float flFrametime)
3061 {
3062         static int framecount = 0;
3063         static int test_running = 0;
3064         static float test_time = 0.0f;
3065
3066         static int snds[NUM_MIXED_SOUNDS];
3067         int i;
3068
3069         if ( test_running ) {
3070                 framecount++;
3071                 test_time += flFrametime;
3072                 if ( framecount >= NUM_FRAMES_TEST ) {
3073                         test_running = 0;
3074                         nprintf(("General", "%d frames took %.3f seconds\n", NUM_FRAMES_TEST, test_time));
3075                         for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3076                                 snd_stop(snds[i]);
3077                 }
3078         }
3079
3080         if ( Test_begin == 1 ) {
3081                 framecount = 0;
3082                 test_running = 1;
3083                 test_time = 0.0f;
3084                 Test_begin = 0;
3085
3086                 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3087                         snds[i] = -1;
3088
3089                 // start looping digital sounds
3090                 for ( i = 0; i < NUM_MIXED_SOUNDS; i++ )
3091                         snds[i] = snd_play_looping( &Snds[i], 0.0f);
3092         }
3093         
3094
3095 }
3096 #endif
3097
3098 DCF(dcf_fov, "Change the field of view")
3099 {
3100         if ( Dc_command )       {
3101                 dc_get_arg(ARG_FLOAT|ARG_NONE);
3102                 if ( Dc_arg_type & ARG_NONE )   {
3103                         Viewer_zoom = VIEWER_ZOOM_DEFAULT;
3104                         dc_printf( "Zoom factor reset\n" );
3105                 }
3106                 if ( Dc_arg_type & ARG_FLOAT )  {
3107                         if (Dc_arg_float < 0.25f) {
3108                                 Viewer_zoom = 0.25f;
3109                                 dc_printf("Zoom factor pinned at 0.25.\n");
3110                         } else if (Dc_arg_float > 1.25f) {
3111                                 Viewer_zoom = 1.25f;
3112                                 dc_printf("Zoom factor pinned at 1.25.\n");
3113                         } else {
3114                                 Viewer_zoom = Dc_arg_float;
3115                         }
3116                 }
3117         }
3118
3119         if ( Dc_help )  
3120                 dc_printf( "Usage: fov [factor]\nFactor is the zoom factor btwn .25 and 1.25\nNo parameter resets it to default.\n" );
3121
3122         if ( Dc_status )                                
3123                 dc_printf("Zoom factor set to %6.3f (original = 0.5, John = 0.75)", Viewer_zoom);
3124 }
3125
3126
3127 DCF(framerate_cap, "Sets the framerate cap")
3128 {
3129         if ( Dc_command ) {
3130                 dc_get_arg(ARG_INT);
3131                 if ( (Dc_arg_int >= 1 ) || (Dc_arg_int <= 120) ) {
3132                         Framerate_cap = Dc_arg_int;
3133                 } else {
3134                         dc_printf( "Illegal value for framerate cap. (Must be from 1-120) \n\n");
3135                         Dc_help = 1;
3136                 }
3137         }
3138
3139         if ( Dc_help ) {
3140                 dc_printf("Usage: framerate_cap [n]\nwhere n is the frames per second to cap framerate at.\n");
3141                 dc_printf("If n is 0 or omitted, then the framerate cap is removed\n");
3142                 dc_printf("[n] must be from 1 to 120.\n");
3143         }
3144         
3145         if ( Dc_status ) {
3146                 if ( Framerate_cap )
3147                         dc_printf("Framerate cap is set to %d fps\n", Framerate_cap );
3148                 else
3149                         dc_printf("There is no framerate cap currently active.\n");
3150         }
3151 }
3152
3153 #define MIN_DIST_TO_DEAD_CAMERA         50.0f
3154 int Show_viewing_from_self = 0;
3155
3156 void say_view_target()
3157 {
3158         object  *view_target;
3159
3160         if ((Viewer_mode & VM_OTHER_SHIP) && (Player_ai->target_objnum != -1))
3161                 view_target = &Objects[Player_ai->target_objnum];
3162         else
3163                 view_target = Player_obj;
3164
3165         if (Game_mode & GM_DEAD) {
3166                 if (Player_ai->target_objnum != -1)
3167                         view_target = &Objects[Player_ai->target_objnum];
3168         }
3169
3170         if (!(Game_mode & GM_DEAD_DIED) && ((Game_mode & (GM_DEAD_BLEW_UP)) || ((Last_view_target != NULL) && (Last_view_target != view_target)))) {
3171                 if (view_target != Player_obj){
3172
3173                         char *view_target_name = NULL;
3174                         switch(Objects[Player_ai->target_objnum].type) {
3175                         case OBJ_SHIP:
3176                                 view_target_name = Ships[Objects[Player_ai->target_objnum].instance].ship_name;
3177                                 break;
3178                         case OBJ_WEAPON:
3179                                 view_target_name = Weapon_info[Weapons[Objects[Player_ai->target_objnum].instance].weapon_info_index].name;
3180                                 Viewer_mode &= ~VM_OTHER_SHIP;
3181                                 break;
3182                         case OBJ_JUMP_NODE: {
3183                                 char    jump_node_name[128];
3184                                 SDL_strlcpy(jump_node_name, XSTR( "jump node", 184), SDL_arraysize(jump_node_name));
3185                                 view_target_name = jump_node_name;
3186                                 Viewer_mode &= ~VM_OTHER_SHIP;
3187                                 break;
3188                                 }
3189
3190                         default:
3191                                 Int3();
3192                                 break;
3193                         }
3194
3195                         if ( view_target_name ) {
3196                                 HUD_fixed_printf(0.0f, XSTR( "Viewing %s%s\n", 185), (Viewer_mode & VM_OTHER_SHIP) ? XSTR( "from ", 186) : "", view_target_name);
3197                                 Show_viewing_from_self = 1;
3198                         }
3199                 } else {
3200                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER) && (Player_obj->type == OBJ_OBSERVER)){
3201                                 HUD_fixed_printf(2.0f,XSTR( "Viewing from observer\n", 187));
3202                                 Show_viewing_from_self = 1;
3203                         } else {
3204                                 if (Show_viewing_from_self)
3205                                         HUD_fixed_printf(2.0f, XSTR( "Viewing from self\n", 188));
3206                         }
3207                 }
3208         }
3209
3210         Last_view_target = view_target;
3211 }
3212
3213
3214 float Game_hit_x = 0.0f;
3215 float Game_hit_y = 0.0f;
3216
3217 // Reset at the beginning of each frame
3218 void game_whack_reset()
3219 {
3220         Game_hit_x = 0.0f;
3221         Game_hit_y = 0.0f;
3222 }
3223
3224 // Apply a 2d whack to the player
3225 void game_whack_apply( float x, float y )
3226 {
3227         // Do some force feedback
3228         joy_ff_play_dir_effect(x * 80.0f, y * 80.0f);
3229
3230         // Move the eye 
3231         Game_hit_x += x;
3232         Game_hit_y += y;
3233
3234 //      mprintf(( "WHACK = %.1f, %.1f\n", Game_hit_x, Game_hit_y ));
3235 }
3236
3237 // call to apply a "shudder"
3238 void game_shudder_apply(int time, float intensity)
3239 {
3240         Game_shudder_time = timestamp(time);
3241         Game_shudder_total = time;
3242         Game_shudder_intensity = intensity;
3243 }
3244
3245 #define FF_SCALE        10000
3246 void apply_hud_shake(matrix *eye_orient)
3247 {
3248         if (Viewer_obj == Player_obj) {
3249                 physics_info    *pi = &Player_obj->phys_info;
3250
3251                 angles  tangles;
3252
3253                 tangles.p = 0.0f;
3254                 tangles.h = 0.0f;
3255                 tangles.b = 0.0f;
3256
3257                 //      Make eye shake due to afterburner
3258                 if ( !timestamp_elapsed(pi->afterburner_decay) ) {                      
3259                         int             dtime;
3260
3261                         dtime = timestamp_until(pi->afterburner_decay);
3262                         
3263                         int r1 = myrand();
3264                         int r2 = myrand();
3265                         tangles.p += 0.07f * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3266                         tangles.h += 0.07f * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX * (0.5f - fl_abs(0.5f - (float) dtime/ABURN_DECAY_TIME));
3267                 }
3268
3269                 // Make eye shake due to engine wash
3270                 extern int Wash_on;
3271                 if (Player_obj->type == OBJ_SHIP && (Ships[Player_obj->instance].wash_intensity > 0) && Wash_on ) {
3272                         int r1 = myrand();
3273                         int r2 = myrand();
3274                         tangles.p += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r1-MY_RAND_MAX/2)/MY_RAND_MAX;
3275                         tangles.h += 0.07f * Ships[Player_obj->instance].wash_intensity * (float) (r2-MY_RAND_MAX/2)/MY_RAND_MAX;
3276
3277                         // get the   intensity
3278                         float intensity = FF_SCALE * Ships[Player_obj->instance].wash_intensity;
3279
3280                         // vector rand_vec
3281                         vector rand_vec;
3282                         vm_vec_rand_vec_quick(&rand_vec);
3283
3284                         // play the effect
3285                         joy_ff_play_dir_effect(intensity*rand_vec.xyz.x, intensity*rand_vec.xyz.y);
3286                 }
3287
3288         
3289                 // make hud shake due to shuddering
3290                 if(Game_shudder_time != -1){
3291                         // if the timestamp has elapsed
3292                         if(timestamp_elapsed(Game_shudder_time)){
3293                                 Game_shudder_time = -1;
3294                         } 
3295                         // otherwise apply some shudder
3296                         else {
3297                                 int dtime;
3298
3299                                 dtime = timestamp_until(Game_shudder_time);
3300                         
3301                                 int r1 = myrand();
3302                                 int r2 = myrand();
3303                                 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));
3304                                 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));
3305                         }
3306                 }
3307
3308                 matrix  tm, tm2;
3309                 vm_angles_2_matrix(&tm, &tangles);
3310                 SDL_assert(vm_vec_mag(&tm.v.fvec) > 0.0f);
3311                 SDL_assert(vm_vec_mag(&tm.v.rvec) > 0.0f);
3312                 SDL_assert(vm_vec_mag(&tm.v.uvec) > 0.0f);
3313                 vm_matrix_x_matrix(&tm2, eye_orient, &tm);
3314                 *eye_orient = tm2;
3315         }
3316 }
3317
3318 extern void compute_slew_matrix(matrix *orient, angles *a);     // TODO: move code to proper place and extern in header file
3319
3320 //      Player's velocity just before he blew up.  Used to keep camera target moving.
3321 vector  Dead_player_last_vel = { { { 1.0f, 1.0f, 1.0f } } };
3322
3323 //      Set eye_pos and eye_orient based on view mode.
3324 void game_render_frame_setup(vector *eye_pos, matrix *eye_orient)
3325 {
3326         vector  eye_dir;
3327
3328         static int last_Viewer_mode = 0;
3329         static int last_Game_mode = 0;
3330         static int last_Viewer_objnum = -1;
3331
3332         // This code is supposed to detect camera "cuts"... like going between
3333         // different views.
3334
3335         // determine if we need to regenerate the nebula
3336         if(     (!(last_Viewer_mode & VM_EXTERNAL) && (Viewer_mode & VM_EXTERNAL)) ||                                                   // internal to external 
3337                         ((last_Viewer_mode & VM_EXTERNAL) && !(Viewer_mode & VM_EXTERNAL)) ||                                                   // external to internal
3338                         (!(last_Viewer_mode & VM_DEAD_VIEW) && (Viewer_mode & VM_DEAD_VIEW)) ||                                                 // non dead-view to dead-view
3339                         ((last_Viewer_mode & VM_DEAD_VIEW) && !(Viewer_mode & VM_DEAD_VIEW)) ||                                                 // dead-view to non dead-view
3340                         (!(last_Viewer_mode & VM_WARP_CHASE) && (Viewer_mode & VM_WARP_CHASE)) ||                                               // non warp-chase to warp-chase
3341                         ((last_Viewer_mode & VM_WARP_CHASE) && !(Viewer_mode & VM_WARP_CHASE)) ||                                               // warp-chase to non warp-chase
3342                         (!(last_Viewer_mode & VM_OTHER_SHIP) && (Viewer_mode & VM_OTHER_SHIP)) ||                                               // non other-ship to other-ship
3343                         ((last_Viewer_mode & VM_OTHER_SHIP) && !(Viewer_mode & VM_OTHER_SHIP)) ||                                               // other-ship to non-other ship
3344                         ((Viewer_mode & VM_OTHER_SHIP) && (last_Viewer_objnum != Player_ai->target_objnum))             // other ship mode, but targets changes
3345                         ) {
3346
3347                 // regenerate the nebula
3348                 neb2_eye_changed();
3349         }               
3350
3351         if ( (last_Viewer_mode != Viewer_mode) || (last_Game_mode != Game_mode) )       {
3352                 //mprintf(( "************** Camera cut! ************\n" ));
3353                 last_Viewer_mode = Viewer_mode;
3354                 last_Game_mode = Game_mode;
3355
3356                 // Camera moved.  Tell stars & debris to not do blurring.
3357                 stars_camera_cut();             
3358         }
3359
3360         say_view_target();
3361
3362         if ( Viewer_mode & VM_PADLOCK_ANY ) {
3363                 player_display_packlock_view();
3364         }
3365         
3366         game_set_view_clip();
3367
3368         if (Game_mode & GM_DEAD) {
3369                 vector  vec_to_deader, view_pos;
3370                 float           dist;
3371
3372                 Viewer_mode |= VM_DEAD_VIEW;
3373
3374                 if (Player_ai->target_objnum != -1) {
3375                         int view_from_player = 1;
3376
3377                         if (Viewer_mode & VM_OTHER_SHIP) {
3378                                 //      View from target.
3379                                 Viewer_obj = &Objects[Player_ai->target_objnum];
3380
3381                                 last_Viewer_objnum = Player_ai->target_objnum;
3382
3383                                 if ( Viewer_obj->type == OBJ_SHIP ) {
3384                                         ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3385                                         view_from_player = 0;
3386                                 }
3387                         } else {
3388                                 last_Viewer_objnum = -1;
3389                         }
3390
3391                         if ( view_from_player ) {
3392                                 //      View target from player ship.
3393                                 Viewer_obj = NULL;
3394                                 *eye_pos = Player_obj->pos;
3395                                 vm_vec_normalized_dir(&eye_dir, &Objects[Player_ai->target_objnum].pos, eye_pos);
3396                                 vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3397                         }
3398                 } else {
3399                         dist = vm_vec_normalized_dir(&vec_to_deader, &Player_obj->pos, &Dead_camera_pos);
3400                         
3401                         if (dist < MIN_DIST_TO_DEAD_CAMERA)
3402                                 dist += flFrametime * 16.0f;
3403
3404                         vm_vec_scale(&vec_to_deader, -dist);
3405                         vm_vec_add(&Dead_camera_pos, &Player_obj->pos, &vec_to_deader);
3406                         
3407                         view_pos = Player_obj->pos;
3408
3409                         if (!(Game_mode & GM_DEAD_BLEW_UP)) {
3410                                 Viewer_mode &= ~(VM_EXTERNAL | VM_CHASE);
3411                                 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, 25.0f * flFrametime);
3412                                 Dead_player_last_vel = Player_obj->phys_info.vel;
3413                                 //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));
3414                         } else if (Player_ai->target_objnum != -1) {
3415                                 view_pos = Objects[Player_ai->target_objnum].pos;
3416                         } else {
3417                                 //      Make camera follow explosion, but gradually slow down.
3418                                 vm_vec_scale_add2(&Player_obj->pos, &Dead_player_last_vel, flFrametime);
3419                                 view_pos = Player_obj->pos;
3420                                 vm_vec_scale(&Dead_player_last_vel, 0.99f);
3421                                 vm_vec_scale_add2(&Dead_camera_pos, &Original_vec_to_deader, min(25.0f, vm_vec_mag_quick(&Dead_player_last_vel)) * flFrametime);
3422                         }
3423
3424                         *eye_pos = Dead_camera_pos;
3425
3426                         vm_vec_normalized_dir(&eye_dir, &Player_obj->pos, eye_pos);
3427
3428                         vm_vector_2_matrix(eye_orient, &eye_dir, NULL, NULL);
3429                         Viewer_obj = NULL;
3430                 }
3431         } 
3432
3433         // if supernova shockwave
3434         if(supernova_camera_cut()){
3435                 // no viewer obj
3436                 Viewer_obj = NULL;
3437
3438                 // call it dead view
3439                 Viewer_mode |= VM_DEAD_VIEW;
3440
3441                 // set eye pos and orient
3442                 supernova_set_view(eye_pos, eye_orient);
3443         } else {        
3444                 //      If already blown up, these other modes can override.
3445                 if (!(Game_mode & (GM_DEAD | GM_DEAD_BLEW_UP))) {
3446                         Viewer_mode &= ~VM_DEAD_VIEW;
3447
3448                         Viewer_obj = Player_obj;
3449  
3450                         if (Viewer_mode & VM_OTHER_SHIP) {
3451                                 if (Player_ai->target_objnum != -1){
3452                                         Viewer_obj = &Objects[Player_ai->target_objnum];
3453                                         last_Viewer_objnum = Player_ai->target_objnum;
3454                                 } else {
3455                                         Viewer_mode &= ~VM_OTHER_SHIP;
3456                                         last_Viewer_objnum = -1;
3457                                 }
3458                         } else {
3459                                 last_Viewer_objnum = -1;
3460                         }
3461
3462                         if (Viewer_mode & VM_EXTERNAL) {
3463                                 matrix  tm, tm2;
3464
3465                                 vm_angles_2_matrix(&tm2, &Viewer_external_info.angles);
3466                                 vm_matrix_x_matrix(&tm, &Viewer_obj->orient, &tm2);
3467
3468                                 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &tm.v.fvec, 2.0f * Viewer_obj->radius + Viewer_external_info.distance);
3469
3470                                 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3471                                 vm_vec_normalize(&eye_dir);
3472                                 vm_vector_2_matrix(eye_orient, &eye_dir, &Viewer_obj->orient.v.uvec, NULL);
3473                                 Viewer_obj = NULL;
3474
3475                                 //      Modify the orientation based on head orientation.
3476                                 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3477
3478                         } else if ( Viewer_mode & VM_CHASE ) {
3479                                 vector  move_dir;
3480
3481                                 if ( Viewer_obj->phys_info.speed < 0.1 )
3482                                         move_dir = Viewer_obj->orient.v.fvec;
3483                                 else {
3484                                         move_dir = Viewer_obj->phys_info.vel;
3485                                         vm_vec_normalize(&move_dir);
3486                                 }
3487
3488                                 vm_vec_scale_add(eye_pos, &Viewer_obj->pos, &move_dir, -3.0f * Viewer_obj->radius - Viewer_chase_info.distance);
3489                                 vm_vec_scale_add2(eye_pos, &Viewer_obj->orient.v.uvec, 0.75f * Viewer_obj->radius);
3490                                 vm_vec_sub(&eye_dir, &Viewer_obj->pos, eye_pos);
3491                                 vm_vec_normalize(&eye_dir);
3492
3493                                 // JAS: I added the following code because if you slew up using
3494                                 // Descent-style physics, eye_dir and Viewer_obj->orient.v.uvec are
3495                                 // equal, which causes a zero-length vector in the vm_vector_2_matrix
3496                                 // call because the up and the forward vector are the same.   I fixed
3497                                 // it by adding in a fraction of the right vector all the time to the
3498                                 // up vector.
3499                                 vector tmp_up = Viewer_obj->orient.v.uvec;
3500                                 vm_vec_scale_add2( &tmp_up, &Viewer_obj->orient.v.rvec, 0.00001f );
3501
3502                                 vm_vector_2_matrix(eye_orient, &eye_dir, &tmp_up, NULL);
3503                                 Viewer_obj = NULL;
3504
3505                                 //      Modify the orientation based on head orientation.
3506                                 compute_slew_matrix(eye_orient, &Viewer_slew_angles);
3507                         } else if ( Viewer_mode & VM_WARP_CHASE ) {
3508                                         *eye_pos = Camera_pos;
3509
3510                                         ship * shipp = &Ships[Player_obj->instance];
3511
3512                                         vm_vec_sub(&eye_dir, &shipp->warp_effect_pos, eye_pos);
3513                                         vm_vec_normalize(&eye_dir);
3514                                         vm_vector_2_matrix(eye_orient, &eye_dir, &Player_obj->orient.v.uvec, NULL);
3515                                         Viewer_obj = NULL;
3516                         } else {
3517                                 // get an eye position based upon the correct type of object
3518                                 switch(Viewer_obj->type){
3519                                 case OBJ_SHIP:
3520                                         // make a call to get the eye point for the player object
3521                                         ship_get_eye( eye_pos, eye_orient, Viewer_obj );
3522                                         break;
3523                                 case OBJ_OBSERVER:
3524                                         // make a call to get the eye point for the player object
3525                                         observer_get_eye( eye_pos, eye_orient, Viewer_obj );                            
3526                                         break;
3527                                 default :
3528                                         Int3();
3529                                 }
3530
3531                                 #ifdef JOHNS_DEBUG_CODE
3532                                 john_debug_stuff(&eye_pos, &eye_orient);
3533                                 #endif
3534                         }
3535                 }
3536         }
3537
3538         apply_hud_shake(eye_orient);
3539
3540         // setup neb2 rendering
3541         neb2_render_setup(eye_pos, eye_orient);
3542 }
3543
3544 #ifndef NDEBUG
3545 extern void ai_debug_render_stuff();
3546 #endif
3547
3548 int Game_subspace_effect = 0;
3549 DCF_BOOL( subspace, Game_subspace_effect );
3550
3551 // Does everything needed to render a frame
3552 void game_render_frame( vector * eye_pos, matrix * eye_orient )
3553 {
3554         int dont_offset;
3555
3556         g3_start_frame(game_zbuffer);
3557         g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
3558
3559         // maybe offset the HUD (jitter stuff)
3560         dont_offset = ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER));
3561         HUD_set_offsets(Viewer_obj, !dont_offset);
3562         
3563         // for multiplayer clients, call code in Shield.cpp to set up the Shield_hit array.  Have to
3564         // do this becaues of the disjointed nature of this system (in terms of setup and execution).
3565         // must be done before ships are rendered
3566         if ( MULTIPLAYER_CLIENT ) {
3567                 shield_point_multi_setup();
3568         }
3569
3570         if ( Game_subspace_effect )     {
3571                 stars_draw(0,0,0,1);
3572         } else {
3573                 stars_draw(1,1,1,0);
3574         }
3575
3576         obj_render_all(obj_render);
3577         beam_render_all();                                              // render all beam weapons
3578         particle_render_all();                                  // render particles after everything else.
3579         trail_render_all();                                             // render missilie trails after everything else.        
3580         mflash_render_all();                                            // render all muzzle flashes    
3581
3582         //      Why do we not show the shield effect in these modes?  Seems ok.
3583         //if (!(Viewer_mode & (VM_EXTERNAL | VM_SLEWED | VM_CHASE | VM_DEAD_VIEW))) {
3584         render_shields();
3585         //}
3586
3587         // render nebula lightning
3588         nebl_render_all();
3589
3590         // render local player nebula
3591         neb2_render_player();   
3592
3593 #ifndef NDEBUG
3594         ai_debug_render_stuff();
3595 #endif
3596
3597 #ifndef RELEASE_REAL
3598         // game_framerate_check();
3599 #endif
3600
3601 #ifndef NDEBUG
3602         extern void snd_spew_debug_info();
3603         snd_spew_debug_info();
3604 #endif
3605
3606         //================ END OF 3D RENDERING STUFF ====================
3607
3608         hud_show_radar();
3609
3610         if( (Game_detail_flags & DETAIL_FLAG_HUD) && (!(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )) ) {
3611                 hud_maybe_clear_head_area();
3612                 anim_render_all(0, flFrametime);
3613         }
3614
3615         extern int Multi_display_netinfo;
3616         if(Multi_display_netinfo){
3617                 extern void multi_display_netinfo();
3618                 multi_display_netinfo();
3619         }       
3620
3621         game_tst_frame_pre();
3622
3623 #ifndef NDEBUG
3624         do_timing_test(flFrametime);
3625 #endif
3626
3627 #ifndef NDEBUG
3628         extern int OO_update_index;     
3629         multi_rate_display(OO_update_index, 375, 0);
3630 #endif
3631
3632 #ifndef NDEBUG
3633         // test
3634         extern void oo_display();
3635         oo_display();                   
3636 #endif
3637         
3638         g3_end_frame();
3639 }
3640
3641 //#define JOHNS_DEBUG_CODE      1
3642
3643 #ifdef JOHNS_DEBUG_CODE
3644 void john_debug_stuff(vector *eye_pos, matrix *eye_orient)
3645 {
3646         //if ( key_pressed(SDLK_LSHIFT) )
3647         {
3648                 ship_subsys *tsys = Players[Player_num].targeted_subobject;
3649                 if ( tsys )     {
3650                         model_subsystem *turret = tsys->system_info;
3651
3652                         if (turret->type == SUBSYSTEM_TURRET )  {
3653                                 vector v.fvec, v.uvec;
3654                                 object * tobj = &Objects[Players[Player_num].targeted_subobject_parent];
3655
3656                                 ship_model_start(tobj);
3657
3658                                 model_find_world_point(eye_pos, &turret->turret_firing_point[0], turret->model_num, turret->turret_gun_sobj, &tobj->orient, &tobj->pos );
3659                                 model_find_world_dir(&v.fvec, &turret->turret_matrix.v.fvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3660                                 model_find_world_dir(&v.uvec, &turret->turret_matrix.v.uvec, turret->model_num, turret->turret_gun_sobj, &tobj->orient, NULL );
3661                                 
3662                                 vm_vector_2_matrix( eye_orient, &v.fvec, &v.uvec, NULL );
3663
3664                                 ship_model_stop(tobj);
3665
3666                                 Viewer_obj = NULL;
3667                         }
3668                 }
3669
3670         }
3671 }
3672 #endif
3673
3674 // following function for dumping frames for purposes of building trailers.
3675 #ifndef NDEBUG
3676
3677 // function to toggle state of dumping every frame into PCX when playing the game
3678 DCF(dump_frames, "Starts/stop frame dumping at 15 hz")
3679 {
3680         if ( Dc_command )       {
3681
3682                 if ( Debug_dump_frames == 0 )   {
3683                         // Turn it on
3684                         Debug_dump_frames = 15;
3685                         Debug_dump_trigger = 0;
3686                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3687                         dc_printf( "Frame dumping at 15 hz is now ON\n" );
3688                 } else {
3689                         // Turn it off
3690                         Debug_dump_frames = 0;
3691                         Debug_dump_trigger = 0;
3692                         gr_dump_frame_stop();
3693                         dc_printf( "Frame dumping is now OFF\n" );
3694                 }
3695                 
3696         }
3697 }
3698
3699 DCF(dump_frames_trigger, "Starts/stop frame dumping at 15 hz")
3700 {
3701         if ( Dc_command )       {
3702
3703                 if ( Debug_dump_frames == 0 )   {
3704                         // Turn it on
3705                         Debug_dump_frames = 15;
3706                         Debug_dump_trigger = 1;
3707                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3708                         dc_printf( "Frame dumping at 15 hz is now ON\n" );
3709                 } else {
3710                         // Turn it off
3711                         Debug_dump_frames = 0;
3712                         Debug_dump_trigger = 0;
3713                         gr_dump_frame_stop();
3714                         dc_printf( "Frame dumping is now OFF\n" );
3715                 }
3716                 
3717         }
3718 }
3719
3720 DCF(dump_frames30, "Starts/stop frame dumping at 30 hz")
3721 {
3722         if ( Dc_command )       {
3723
3724                 if ( Debug_dump_frames == 0 )   {
3725                         // Turn it on
3726                         Debug_dump_frames = 30;
3727                         Debug_dump_trigger = 0;
3728                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3729                         dc_printf( "Frame dumping at 30 hz is now ON\n" );
3730                 } else {
3731                         // Turn it off
3732                         Debug_dump_frames = 0;
3733                         Debug_dump_trigger = 0;
3734                         gr_dump_frame_stop();
3735                         dc_printf( "Frame dumping is now OFF\n" );
3736                 }
3737                 
3738         }
3739 }
3740
3741 DCF(dump_frames30_trigger, "Starts/stop frame dumping at 30 hz")
3742 {
3743         if ( Dc_command )       {
3744
3745                 if ( Debug_dump_frames == 0 )   {
3746                         // Turn it on
3747                         Debug_dump_frames = 30;
3748                         Debug_dump_trigger = 1;
3749                         gr_dump_frame_start( Debug_dump_frame_num, DUMP_BUFFER_NUM_FRAMES );
3750                         dc_printf( "Triggered frame dumping at 30 hz is now ON\n" );
3751                 } else {
3752                         // Turn it off
3753                         Debug_dump_frames = 0;
3754                         Debug_dump_trigger = 0;
3755                         gr_dump_frame_stop();
3756                         dc_printf( "Triggered frame dumping is now OFF\n" );
3757                 }
3758                 
3759         }
3760 }
3761
3762 void game_maybe_dump_frame()
3763 {
3764         if ( !Debug_dump_frames ){
3765                 return;
3766         }
3767
3768         if( Debug_dump_trigger && !key_pressed(SDLK_q) ){
3769                 return;
3770         }
3771
3772         game_stop_time();
3773
3774         gr_dump_frame();
3775         Debug_dump_frame_num++;
3776
3777         game_start_time();
3778 }
3779 #endif
3780
3781 extern int Player_dead_state;
3782
3783 //      Flip the page and time how long it took.
3784 void game_flip_page_and_time_it()
3785 {       
3786 #ifndef NDEBUG
3787         fix t1, t2,d;
3788         int t;
3789         t1 = timer_get_fixed_seconds();
3790         gr_flip();
3791         t2 = timer_get_fixed_seconds();
3792         d = t2 - t1;
3793         if (d != 0) {
3794                 t = (gr_screen.max_w*gr_screen.max_h*gr_screen.bytes_per_pixel)/1024;
3795                 SDL_snprintf( transfer_text, SDL_arraysize(transfer_text), NOX("%d MB/s"), fixmuldiv(t,65,d) );
3796         }
3797 #else
3798         gr_flip ();
3799 #endif
3800 }
3801
3802 void game_simulation_frame()
3803 {
3804         // blow ships up in multiplayer dogfight
3805         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){
3806                 // blow up all non-player ships
3807                 ship_obj *moveup = GET_FIRST(&Ship_obj_list);
3808                 ship *shipp;
3809                 ship_info *sip;
3810                 while((moveup != END_OF_LIST(&Ship_obj_list)) && (moveup != NULL)){
3811                         // bogus
3812                         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)){
3813                                 moveup = GET_NEXT(moveup);
3814                                 continue;
3815                         }
3816                         shipp = &Ships[Objects[moveup->objnum].instance];
3817                         sip = &Ship_info[shipp->ship_info_index];
3818
3819                         // only blow up small ships                     
3820                         if((sip->flags & SIF_SMALL_SHIP) && (multi_find_player_by_object(&Objects[moveup->objnum]) < 0) ){                                                      
3821                                 // function to simply explode a ship where it is currently at
3822                                 ship_self_destruct( &Objects[moveup->objnum] );                                 
3823                         }
3824
3825                         moveup = GET_NEXT(moveup);
3826                 }
3827
3828                 dogfight_blown = 1;
3829         }
3830
3831         // process AWACS stuff - do this first thing
3832         awacs_process();
3833
3834         // single player, set Player hits_this_frame to 0
3835         if ( !(Game_mode & GM_MULTIPLAYER) && Player ) {
3836                 Player->damage_this_burst -= (flFrametime * MAX_BURST_DAMAGE  / (0.001f * BURST_DURATION));
3837                 Player->damage_this_burst = max(Player->damage_this_burst, 0.0f);
3838         }
3839
3840         // supernova
3841         supernova_process();
3842         if(supernova_active() >= 5){
3843                 return;
3844         }
3845
3846         // fire targeting lasers now so that 
3847         // 1 - created this frame
3848         // 2 - collide this frame
3849         // 3 - render this frame
3850         // 4 - ignored and deleted next frame
3851         // the basic idea being that because it con be confusing to deal with them on a multi-frame basis, they are only valid for
3852         // frame
3853         ship_process_targeting_lasers();        
3854
3855         // do this here so that it works for multiplayer
3856         if ( Viewer_obj ) {
3857                 // get viewer direction
3858                 int viewer_direction = PHYSICS_VIEWER_REAR;
3859
3860                 if(Viewer_mode == 0){
3861                         viewer_direction = PHYSICS_VIEWER_FRONT;
3862                 }
3863                 if(Viewer_mode & VM_PADLOCK_UP){
3864                         viewer_direction = PHYSICS_VIEWER_UP;
3865                 }
3866                 else if(Viewer_mode & VM_PADLOCK_REAR){
3867                         viewer_direction = PHYSICS_VIEWER_REAR;
3868                 } 
3869                 else if(Viewer_mode & VM_PADLOCK_LEFT){
3870                         viewer_direction = PHYSICS_VIEWER_LEFT;
3871                 } 
3872                 else if(Viewer_mode & VM_PADLOCK_RIGHT){
3873                         viewer_direction = PHYSICS_VIEWER_RIGHT;
3874                 }
3875
3876                 physics_set_viewer( &Viewer_obj->phys_info, viewer_direction );
3877         } else {
3878                 physics_set_viewer( NULL, PHYSICS_VIEWER_FRONT );
3879         }
3880
3881 #define VM_PADLOCK_UP                                   (1 << 7)
3882 #define VM_PADLOCK_REAR                         (1 << 8)
3883 #define VM_PADLOCK_LEFT                         (1 << 9)
3884 #define VM_PADLOCK_RIGHT                                (1 << 10)
3885                 
3886         // evaluate mission departures and arrivals before we process all objects.
3887         if ( !(Game_mode & GM_MULTIPLAYER) || ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending()) ) {
3888
3889                 // we don't want to evaluate mission stuff when any ingame joiner in multiplayer is receiving
3890                 // ships/wing packets.
3891                 if ( !((Game_mode & GM_MULTIPLAYER) && (Netgame.flags & NG_FLAG_INGAME_JOINING_CRITICAL)) && !(Game_mode & GM_DEMO_PLAYBACK)){
3892                         mission_parse_eval_stuff();
3893                 }
3894
3895                 // if we're an observer, move ourselves seperately from the standard physics
3896                 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
3897                         obj_observer_move(flFrametime);
3898                 }
3899                 
3900                 // move all the objects now
3901                 obj_move_all(flFrametime);
3902
3903                 // check for cargo reveal (this has an internal timestamp, so only runs every N ms)
3904                 // AL: 3-15-98: It was decided to not let AI ships inspect cargo
3905                 //      ship_check_cargo_all();
3906                 if(!(Game_mode & GM_DEMO_PLAYBACK)){
3907                         mission_eval_goals();
3908                 }
3909         }
3910
3911         // always check training objectives, even in multiplayer missions. we need to do this so that the directives gauge works properly on clients
3912         if(!(Game_mode & GM_DEMO_PLAYBACK)){
3913                 training_check_objectives();
3914         }
3915         
3916         // do all interpolation now
3917         if ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !multi_endgame_ending() && !(Netgame.flags & NG_FLAG_SERVER_LOST)) {
3918                 // client side processing of warping in effect stages
3919                 multi_do_client_warp(flFrametime);     
3920         
3921                 // client side movement of an observer
3922                 if((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)){
3923                         obj_observer_move(flFrametime);   
3924                 }
3925
3926                 // move all objects - does interpolation now as well
3927                 obj_move_all(flFrametime);
3928         }
3929
3930         // only process the message queue when the player is "in" the game
3931         if ( !Pre_player_entry ){
3932                 message_queue_process();                                // process any messages send to the player
3933         }
3934
3935         if(!(Game_mode & GM_DEMO_PLAYBACK)){
3936                 message_maybe_distort();                                // maybe distort incoming message if comms damaged
3937                 player_repair_frame(flFrametime);       //      AI objects get repaired in ai_process, called from move code...deal with player.
3938                 player_process_pending_praise();                // maybe send off a delayed praise message to the player
3939                 player_maybe_play_all_alone_msg();      // mabye tell the player he is all alone        
3940         }
3941
3942         if(!(Game_mode & GM_STANDALONE_SERVER)){                
3943                 // process some stuff every frame (before frame is rendered)
3944                 emp_process_local();
3945
3946                 hud_update_frame();                                             // update hud systems
3947
3948                 if (!physics_paused)    {
3949                         // Move particle system
3950                         particle_move_all(flFrametime); 
3951
3952                         // Move missile trails
3953                         trail_move_all(flFrametime);            
3954
3955                         // process muzzle flashes
3956                         mflash_process_all();
3957
3958                         // Flash the gun flashes
3959                         shipfx_flash_do_frame(flFrametime);                     
3960
3961                         shockwave_move_all(flFrametime);        // update all the shockwaves
3962                 }
3963
3964                 // subspace missile strikes
3965                 ssm_process();
3966
3967                 obj_snd_do_frame();                                             // update the object-linked persistant sounds
3968                 game_maybe_update_sound_environment();
3969                 snd_update_listener(&View_position, &Player_obj->phys_info.vel, &Player_obj->orient);
3970
3971 // AL: debug code used for testing ambient subspace sound (ie when enabling subspace through debug console)
3972 #ifndef NDEBUG
3973                 if ( Game_subspace_effect ) {
3974                         game_start_subspace_ambient_sound();
3975                 }
3976 #endif
3977         }               
3978 }
3979
3980 // Maybe render and process the dead-popup
3981 void game_maybe_do_dead_popup(float frametime)
3982 {
3983         if ( popupdead_is_active() ) {
3984                 int leave_popup=1;
3985                 int choice = popupdead_do_frame(frametime);
3986
3987                 if ( Game_mode & GM_NORMAL ) {
3988                         switch(choice) {
3989                         case 0:
3990                                 gameseq_post_event(GS_EVENT_ENTER_GAME);
3991                                 break;
3992
3993                         case 1:
3994                                 gameseq_post_event(GS_EVENT_END_GAME);
3995                                 break;
3996
3997                         case 2:
3998                                 gameseq_post_event(GS_EVENT_START_GAME);
3999                                 break;
4000
4001                         // this should only happen during a red alert mission
4002                         case 3:                         
4003                                 // bogus?
4004                                 SDL_assert(The_mission.red_alert);
4005                                 if(!The_mission.red_alert){
4006                                         gameseq_post_event(GS_EVENT_START_GAME);
4007                                         break;
4008                                 }
4009                                 
4010                                 // choose the previous mission
4011                                 mission_campaign_previous_mission();
4012
4013                                 gameseq_post_event(GS_EVENT_START_GAME);
4014                                 break;
4015
4016                         default:
4017                                 leave_popup=0;
4018                                 break;
4019                         }
4020                 } else {
4021                         switch( choice ) {
4022
4023                         case POPUPDEAD_DO_MAIN_HALL:
4024                                 multi_quit_game(PROMPT_NONE,-1);
4025                                 break;
4026
4027                         case POPUPDEAD_DO_RESPAWN:                              
4028                                 multi_respawn_normal();
4029                                 event_music_player_respawn();
4030                                 break;
4031
4032                         case POPUPDEAD_DO_OBSERVER:
4033                                 multi_respawn_observer();
4034                                 event_music_player_respawn_as_observer();
4035                                 break;
4036
4037                         default:
4038                                 leave_popup = 0;
4039                                 break;
4040                         }
4041                 }
4042
4043                 if ( leave_popup ) {
4044                         popupdead_close();
4045                 }
4046         }
4047 }
4048
4049 // returns true if player is actually in a game_play stats
4050 int game_actually_playing()
4051 {
4052         int state;
4053
4054         state = gameseq_get_state();
4055         if ( (state != GS_STATE_GAME_PLAY) && (state != GS_STATE_DEATH_DIED) && (state != GS_STATE_DEATH_BLEW_UP) )
4056                 return 0;
4057         else
4058                 return 1;
4059 }
4060
4061 // Draw the 2D HUD gauges
4062 void game_render_hud_2d()
4063 {
4064         if ( !(Game_detail_flags & DETAIL_FLAG_HUD) ) {
4065                 return;
4066         }
4067         
4068         HUD_render_2d(flFrametime);
4069         gr_reset_clip();
4070 }
4071
4072 // Draw the 3D-dependant HUD gauges
4073 void game_render_hud_3d(vector *eye_pos, matrix *eye_orient)
4074 {
4075         g3_start_frame(0);              // 0 = turn zbuffering off
4076         g3_set_view_matrix( eye_pos, eye_orient, Viewer_zoom );
4077
4078         if ( (Game_detail_flags & DETAIL_FLAG_HUD) && (supernova_active() < 3)/* && !(Game_mode & GM_MULTIPLAYER) || ( (Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER) )*/ ) {
4079                 HUD_render_3d(flFrametime);
4080         }
4081
4082         // Do the sunspot
4083         game_sunspot_process(flFrametime);
4084
4085         // Diminish the palette effect
4086         game_flash_diminish(flFrametime);
4087
4088         g3_end_frame();
4089 }
4090
4091
4092 void game_frame()
4093 {
4094         int actually_playing;
4095         fix total_time1, total_time2;
4096         fix render2_time1=0, render2_time2=0;
4097         fix render3_time1=0, render3_time2=0;
4098         fix flip_time1=0, flip_time2=0;
4099         fix clear_time1=0, clear_time2=0;
4100         
4101         vector eye_pos;
4102         matrix eye_orient;
4103
4104 #ifndef NDEBUG
4105         if (Framerate_delay) {
4106                 int     start_time = timer_get_milliseconds();
4107                 while (timer_get_milliseconds() < start_time + Framerate_delay)
4108                         ;
4109         }
4110 #endif
4111
4112 #ifdef DEMO_SYSTEM
4113         demo_do_frame_start();
4114         if(Demo_error){
4115                 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4116                 demo_close();
4117         }
4118 #endif
4119         
4120         // start timing frame
4121         timing_frame_start();
4122
4123         total_time1 = timer_get_fixed_seconds();
4124
4125         // var to hold which state we are in
4126         actually_playing = game_actually_playing();
4127         
4128         if ((!(Game_mode & GM_MULTIPLAYER)) || ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER))) {
4129                 if (!(Game_mode & GM_STANDALONE_SERVER)){
4130                         SDL_assert( OBJ_INDEX(Player_obj) >= 0 );
4131                 }
4132         }
4133
4134         if (Missiontime > Entry_delay_time){
4135                 Pre_player_entry = 0;
4136         } else {
4137                 ; //nprintf(("AI", "Framecount = %i, time = %7.3f\n", Framecount, f2fl(Missiontime)));
4138         }
4139
4140         //      Note: These are done even before the player enters, else buffers can overflow.
4141         if (! (Game_mode & GM_STANDALONE_SERVER)){
4142                 radar_frame_init();
4143         }
4144
4145         shield_frame_init();
4146
4147         if ( Player->control_mode != PCM_NORMAL )
4148                 camera_move();
4149
4150         if ( !Pre_player_entry && actually_playing ) {                          
4151                 if (! (Game_mode & GM_STANDALONE_SERVER) ) {
4152
4153                         if( (!popup_running_state()) && (!popupdead_is_active()) ){
4154                                 game_process_keys();
4155
4156                                 // don't read flying controls if we're playing a demo back
4157                                 if(!(Game_mode & GM_DEMO_PLAYBACK)){
4158                                         read_player_controls( Player_obj, flFrametime);
4159                                 }
4160                         }
4161                         
4162                         // if we're not the master, we may have to send the server-critical ship status button_info bits
4163                         if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Net_player->flags & NETINFO_FLAG_OBSERVER)){
4164                                 multi_maybe_send_ship_status();
4165                         }
4166                 }
4167         }
4168
4169         // Reset the whack stuff
4170         game_whack_reset();
4171
4172         // These two lines must be outside of Pre_player_entry code,
4173         // otherwise too many lights are added.
4174         light_reset();
4175
4176         if ((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4177                 return;
4178         }
4179         
4180         game_simulation_frame();        
4181
4182         // if not actually in a game play state, then return.  This condition could only be true in 
4183         // a multiplayer game.
4184         if ( !actually_playing ) {
4185                 SDL_assert( Game_mode & GM_MULTIPLAYER );
4186                 return;
4187         }
4188
4189         if (!Pre_player_entry) {
4190                 if (! (Game_mode & GM_STANDALONE_SERVER)) {
4191                         clear_time1 = timer_get_fixed_seconds();
4192                         // clear the screen to black
4193                         gr_reset_clip();
4194                         if ( (Game_detail_flags & DETAIL_FLAG_CLEAR) ) {
4195                                 gr_clear();
4196                         }
4197
4198                         clear_time2 = timer_get_fixed_seconds();
4199                         render3_time1 = timer_get_fixed_seconds();
4200                         game_render_frame_setup(&eye_pos, &eye_orient);
4201                         game_render_frame( &eye_pos, &eye_orient );
4202
4203                         // save the eye position and orientation
4204                         if ( Game_mode & GM_MULTIPLAYER ) {
4205                                 Net_player->s_info.eye_pos = eye_pos;
4206                                 Net_player->s_info.eye_orient = eye_orient;
4207                         }
4208
4209                         hud_show_target_model();
4210
4211                         // check to see if we should display the death died popup
4212                         if(Game_mode & GM_DEAD_BLEW_UP){                                
4213                                 if(Game_mode & GM_MULTIPLAYER){
4214                                         // catch the situation where we're supposed to be warping out on this transition
4215                                         if(Net_player->flags & NETINFO_FLAG_WARPING_OUT){
4216                                                 gameseq_post_event(GS_EVENT_DEBRIEF);
4217                                         } else if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4218                                                 Player_died_popup_wait = -1;
4219                                                 popupdead_start();
4220                                         }
4221                                 } else {
4222                                         if((Player_died_popup_wait != -1) && (timestamp_elapsed(Player_died_popup_wait))){
4223                                                 Player_died_popup_wait = -1;
4224                                                 popupdead_start();
4225                                         }
4226                                 }
4227                         }
4228
4229                         // hack - sometimes this seems to slip by in multiplayer. this should guarantee that we catch it
4230                         if((Game_mode & GM_MULTIPLAYER) && (Player_multi_died_check != -1) && (Game_mode & GM_DEAD_BLEW_UP) ){
4231                                 if(fl_abs(time(NULL) - Player_multi_died_check) > 4){
4232                                         if(!popupdead_is_active()){
4233                                                 popupdead_start();
4234                                         }
4235
4236                                         Player_multi_died_check = -1;
4237                                 }
4238                         }
4239         
4240                         render3_time2 = timer_get_fixed_seconds();
4241                         render2_time1 = timer_get_fixed_seconds();
4242
4243                         gr_reset_clip();
4244                         game_get_framerate();
4245                         game_show_framerate();          
4246
4247                         game_show_time_left();
4248
4249                         // Draw the 2D HUD gauges
4250                         if(supernova_active() < 3){
4251                                 game_render_hud_2d();
4252                         }
4253
4254                         game_set_view_clip();
4255
4256                         // Draw 3D HUD gauges                   
4257                         game_render_hud_3d(&eye_pos, &eye_orient);                                                                      
4258
4259                         game_tst_frame();
4260
4261                         render2_time2 = timer_get_fixed_seconds();
4262
4263                         // maybe render and process the dead popup
4264                         game_maybe_do_dead_popup(flFrametime);
4265
4266                         // start timing frame
4267                         timing_frame_stop();
4268                         // timing_display(30, 10);                      
4269
4270                         // If a regular popup is active, don't flip (popup code flips)
4271                         if( !popup_running_state() ){
4272                                 flip_time1 = timer_get_fixed_seconds();
4273                                 game_flip_page_and_time_it();
4274                                 flip_time2 = timer_get_fixed_seconds();
4275                         }
4276
4277 #ifndef NDEBUG
4278                         game_maybe_dump_frame();                        // used to dump pcx files for building trailers
4279 #endif          
4280                 } else {
4281                         game_show_standalone_framerate();
4282                 }
4283         }
4284
4285         game_do_training_checks();
4286         asteroid_frame();
4287
4288         // process lightning (nebula only)
4289         nebl_process();
4290
4291         total_time2 = timer_get_fixed_seconds();
4292
4293         // Got some timing numbers
4294         Timing_total = f2fl( total_time2 - total_time1 ) * 1000.0f;
4295         Timing_clear = f2fl( clear_time2 - clear_time1 ) * 1000.0f;
4296         Timing_render2 = f2fl( render2_time2- render2_time1 ) * 1000.0f;
4297         Timing_render3 = f2fl( render3_time2- render3_time1 ) * 1000.0f;
4298         Timing_flip = f2fl( flip_time2 - flip_time1 ) * 1000.0f;
4299
4300 #ifdef DEMO_SYSTEM
4301         demo_do_frame_end();
4302         if(Demo_error){
4303                 mprintf(("Error (%d) while processing demo!\n", Demo_error));
4304                 demo_close();
4305         }
4306 #endif
4307 }
4308
4309 #define MAX_FRAMETIME   (F1_0/4)                // Frametime gets saturated at this.  Changed by MK on 11/1/97.
4310                                                                                                 //      Some bug was causing Frametime to always get saturated at 2.0 seconds after the player
4311                                                                                                 //      died.  This resulted in screwed up death sequences.
4312
4313 fix Last_time = 0;                                              // The absolute time of game at end of last frame (beginning of this frame)
4314 fix Last_delta_time = 0;                                // While game is paused, this keeps track of how much elapsed in the frame before paused.
4315 static int timer_paused=0;
4316 #if defined(TIMER_TEST) && !defined(NDEBUG)
4317 static int stop_count,start_count;
4318 static int time_stopped,time_started;
4319 #endif
4320 int saved_timestamp_ticker = -1;
4321
4322 void game_reset_time()
4323 {
4324         if((Game_mode & GM_MULTIPLAYER) && (Netgame.game_state == NETGAME_STATE_SERVER_TRANSFER)){
4325                 return ;
4326         }
4327         
4328         //      Last_time = timer_get_fixed_seconds();
4329         game_start_time();
4330         timestamp_reset();
4331         game_stop_time();
4332 }
4333
4334 void game_stop_time()
4335 {
4336         if (timer_paused==0) {
4337                 fix time;
4338                 time = timer_get_fixed_seconds();
4339                 // Save how much time progressed so far in the frame so we can
4340                 // use it when we unpause.
4341                 Last_delta_time = time - Last_time;             
4342
4343                 //mprintf(("Last_time in game_stop_time = %7.3f\n", f2fl(Last_delta_time)));
4344                 if (Last_delta_time < 0) {
4345                         #if defined(TIMER_TEST) && !defined(NDEBUG)
4346                         Int3();         //get Matt!!!!
4347                         #endif
4348                         Last_delta_time = 0;
4349                 }
4350                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4351                 time_stopped = time;
4352                 #endif
4353
4354                 // Stop the timer_tick stuff...
4355                 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4356                 saved_timestamp_ticker = timestamp_ticker;
4357         }
4358         timer_paused++;
4359
4360         #if defined(TIMER_TEST) && !defined(NDEBUG)
4361         stop_count++;
4362         #endif
4363 }
4364
4365 void game_start_time()
4366 {
4367         timer_paused--;
4368         SDL_assert(timer_paused >= 0);
4369         if (timer_paused==0) {
4370                 fix time;
4371                 time = timer_get_fixed_seconds();
4372                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4373                 if (Last_time < 0)
4374                         Int3();         //get Matt!!!!
4375                 }
4376                 #endif
4377                 // Take current time, and set it backwards to account for time  
4378                 // that the frame already executed, so that timer_get_fixed_seconds() - Last_time
4379                 // will be correct when it goes to calculate the frametime next
4380                 // frame.
4381                 Last_time = time - Last_delta_time;             
4382                 #if defined(TIMER_TEST) && !defined(NDEBUG)
4383                 time_started = time;
4384                 #endif
4385
4386                 // Restore the timer_tick stuff...
4387                 // Normally, you should never access 'timestamp_ticker', consider this a low-level routine
4388                 SDL_assert( saved_timestamp_ticker > -1 );              // Called out of order, get JAS
4389                 timestamp_ticker = saved_timestamp_ticker;
4390                 saved_timestamp_ticker = -1;
4391         }
4392
4393         #if defined(TIMER_TEST) && !defined(NDEBUG)
4394         start_count++;
4395         #endif
4396 }
4397
4398
4399 void game_set_frametime(int state)
4400 {
4401         fix thistime;
4402         float frame_cap_diff;
4403
4404         thistime = timer_get_fixed_seconds();
4405
4406         if ( Last_time == 0 )   
4407                 Frametime = F1_0 / 30;
4408         else
4409                 Frametime = thistime - Last_time;
4410
4411 //      Frametime = F1_0 / 30;
4412
4413 #ifndef NDEBUG
4414         fix     debug_frametime = Frametime;    //      Just used to display frametime.
4415 #endif
4416
4417         //      If player hasn't entered mission yet, make frame take 1/4 second.
4418         if ((Pre_player_entry) && (state == GS_STATE_GAME_PLAY))
4419                 Frametime = F1_0/4;
4420 #ifndef NDEBUG
4421         else if ((Debug_dump_frames) && (state == GS_STATE_GAME_PLAY)) {                                // note link to above if!!!!!
4422         
4423                 fix frame_speed = F1_0 / Debug_dump_frames;
4424
4425                 if (Frametime > frame_speed ){
4426                         nprintf(("warning","slow frame: %x\n",Frametime));
4427                 } else {                        
4428                         do {
4429                                 thistime = timer_get_fixed_seconds();
4430                                 Frametime = thistime - Last_time;
4431                         } while (Frametime < frame_speed );                     
4432                 }
4433                 Frametime = frame_speed;
4434         }
4435 #endif
4436
4437         SDL_assert( Framerate_cap > 0 );
4438
4439         // Cap the framerate so it doesn't get too high.
4440         {
4441                 fix cap;
4442
4443                 cap = F1_0/Framerate_cap;
4444                 if (Frametime < cap) {
4445                         thistime = cap - Frametime;
4446                         //mprintf(("Sleeping for %6.3f seconds.\n", f2fl(thistime)));
4447                         SDL_Delay( fl2i(f2fl(thistime) * 1000.0f) );
4448                         Frametime = cap;
4449                         thistime = timer_get_fixed_seconds();
4450                 }
4451         }
4452
4453         if((Game_mode & GM_STANDALONE_SERVER) && 
4454                 (f2fl(Frametime) < (1.0f/(float)Multi_options_g.std_framecap))){
4455
4456                 frame_cap_diff = (1.0f/(float)Multi_options_g.std_framecap) - f2fl(Frametime);
4457                 SDL_Delay( fl2i(frame_cap_diff * 1000.0f) );
4458                 
4459                 thistime += fl2f((frame_cap_diff));             
4460
4461                 Frametime = thistime - Last_time;
4462    }
4463
4464         // If framerate is too low, cap it.
4465         if (Frametime > MAX_FRAMETIME)  {
4466 #ifndef NDEBUG
4467                 mprintf(("Frame %2i too long!!: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4468 #endif
4469                 Frametime = MAX_FRAMETIME;
4470         }
4471
4472         Frametime = fixmul(Frametime, Game_time_compression);
4473
4474         Last_time = thistime;
4475         //mprintf(("Frame %i, Last_time = %7.3f\n", Framecount, f2fl(Last_time)));
4476
4477         flFrametime = f2fl(Frametime);
4478         //if(!(Game_mode & GM_PLAYING_DEMO)){
4479         timestamp_inc(flFrametime);
4480
4481 /*      if ((Framecount > 0) && (Framecount < 10)) {
4482                 mprintf(("Frame %2i: frametime = %.3f (%.3f)\n", Framecount, f2fl(Frametime), f2fl(debug_frametime)));
4483         }
4484 */
4485 }
4486
4487 // This is called from game_do_frame(), and from navmap_do_frame() 
4488 void game_update_missiontime()
4489 {
4490         // TODO JAS: Put in if and move this into game_set_frametime, 
4491         // fix navmap to call game_stop/start_time
4492         //if ( !timer_paused )  
4493                 Missiontime += Frametime;
4494 }
4495
4496 void game_do_frame()
4497 {       
4498         game_set_frametime(GS_STATE_GAME_PLAY);
4499         game_update_missiontime();
4500
4501         if (Game_mode & GM_STANDALONE_SERVER) {
4502                 std_multi_set_standalone_missiontime(f2fl(Missiontime));
4503         }
4504
4505         if ( game_single_step && (last_single_step == game_single_step) ) {
4506                 os_set_title( NOX("SINGLE STEP MODE (Pause exits, any other key steps)") );
4507                 while( key_checkch() == 0 )
4508                         SDL_Delay(10);
4509                 os_set_title( XSTR( "FreeSpace", 171) );
4510                 Last_time = timer_get_fixed_seconds();
4511         }
4512
4513         last_single_step = game_single_step;
4514
4515         if ((gameseq_get_state() == GS_STATE_GAME_PLAY) && Use_mouse_to_fly){
4516                 Keep_mouse_centered = 1;  // force mouse to center of our window (so we don't hit movement limits)
4517         }
4518         game_frame();
4519
4520         Keep_mouse_centered = 0;
4521         monitor_update();                       // Update monitor variables
4522 }
4523
4524 void multi_maybe_do_frame()
4525 {
4526         if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_IN_MISSION) && !Multi_pause_status){
4527                 game_do_frame(); 
4528         }
4529 }
4530
4531 int Joymouse_button_status = 0;
4532
4533 // Flush all input devices
4534 void game_flush()
4535 {
4536         key_flush();
4537         mouse_flush();
4538         joy_flush();
4539         snazzy_flush();
4540
4541         Joymouse_button_status = 0;
4542
4543         //mprintf(("Game flush!\n" ));
4544 }
4545
4546 // function for multiplayer only which calls game_do_state_common() when running the
4547 // debug console
4548 void game_do_dc_networking()
4549 {
4550         SDL_assert( Game_mode & GM_MULTIPLAYER );
4551
4552         game_do_state_common( gameseq_get_state() );
4553 }
4554
4555 // Call this whenever in a loop, or when you need to check for a keystroke.
4556 int game_check_key()
4557 {
4558         int k;
4559
4560         k = game_poll();
4561
4562         // convert keypad enter to normal enter
4563         if ((k & KEY_MASK) == SDLK_KP_ENTER)
4564                 k = (k & ~KEY_MASK) | SDLK_RETURN;
4565
4566         return k;
4567 }
4568
4569 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4570
4571 #define DEMO_TRAILER_TIMEOUT_MS         45000                   // 45 seconds of no input, play trailer
4572 static int Demo_show_trailer_timestamp = 0;
4573
4574 void demo_reset_trailer_timer()
4575 {
4576         Demo_show_trailer_timestamp = timer_get_milliseconds();
4577 }
4578
4579 void demo_maybe_show_trailer(int k)
4580 {
4581         /*
4582         // if key pressed, reset demo trailer timer
4583         if ( k > 0 ) {
4584                 demo_reset_trailer_timer();
4585                 return;
4586         }
4587
4588         // if mouse moved, reset demo trailer timer
4589         int dx = 0, dy = 0;
4590
4591         mouse_get_delta(&dx, &dy);
4592         if ( (dx > 0) || (dy > 0) ) {
4593                 demo_reset_trailer_timer();
4594                 return;
4595         }
4596
4597         // if joystick has moved, reset demo trailer timer
4598         dx = 0;
4599         dy = 0;
4600         joy_get_delta(&dx, &dy);
4601         if ( (dx > 0) || (dy > 0) ) {
4602                 demo_reset_trailer_timer();
4603                 return;
4604         }
4605
4606         // NOTE: reseting the trailer timer on mouse/joystick presses is handled in
4607         //       the low-level code.  Ugly, I know... but was the simplest and most
4608         //       robust solution.
4609                 
4610         // if 30 seconds since last demo trailer time reset, launch movie
4611         if ( os_foreground() ) {
4612                 int now = timer_get_milliseconds();
4613                 if ( (now - Demo_show_trailer_timestamp) > DEMO_TRAILER_TIMEOUT_MS ) {
4614 //              if ( (now - Demo_show_trailer_timestamp) > 10000 ) {
4615                         // play movie here
4616                         movie_play( NOX("fstrailer2.mve") );
4617                         demo_reset_trailer_timer();
4618                 }
4619         }
4620         */
4621 }
4622
4623 #endif
4624
4625 // same as game_check_key(), except this is used while actually in the game.  Since there
4626 // generally are differences between game control keys and general UI keys, makes sense to
4627 // have seperate functions for each case.  If you are not checking a game control while in a
4628 // mission, you should probably be using game_check_key() instead.
4629 int game_poll()
4630 {
4631         int k, state;
4632
4633         if (!os_foreground()) {         
4634                 game_stop_time();
4635                 SDL_Delay(100);
4636                 game_start_time();
4637
4638                 // If we're in a single player game, pause it.
4639                 if (!(Game_mode & GM_MULTIPLAYER)){
4640                         if ( (gameseq_get_state() == GS_STATE_GAME_PLAY) && (!popup_active()) && (!popupdead_is_active()) )     {
4641                                 game_process_pause_key();
4642                         }
4643                 }
4644         }
4645
4646    k = key_inkey();
4647
4648 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4649         demo_maybe_show_trailer(k);
4650 #endif
4651
4652         // Move the mouse cursor with the joystick.
4653         if (os_foreground() && (!Mouse_hidden) && (Use_joy_mouse) )     {
4654                 // Move the mouse cursor with the joystick
4655                 int mx, my, dx, dy;
4656                 int jx, jy, jz, jr;
4657
4658                 joy_get_pos( &jx, &jy, &jz, &jr );
4659
4660                 dx = fl2i(f2fl(jx)*flFrametime*500.0f);
4661                 dy = fl2i(f2fl(jy)*flFrametime*500.0f);
4662
4663                 if ( dx || dy ) {
4664                         mouse_get_real_pos( &mx, &my );
4665                         mouse_set_pos( mx+dx, my+dy );
4666                 }
4667
4668                 int j, m;
4669                 j = joy_down(0);
4670                 m = mouse_down(MOUSE_LEFT_BUTTON);
4671
4672                 if ( j != Joymouse_button_status )      {
4673                         //mprintf(( "Joy went from %d to %d, mouse is %d\n", Joymouse_button_status, j, m ));
4674                         Joymouse_button_status = j;
4675                         if ( j && (!m) )        {
4676                                 mouse_mark_button( MOUSE_LEFT_BUTTON, 1 );
4677                         } else if ( (!j) && (m) )       {
4678                                 mouse_mark_button( MOUSE_LEFT_BUTTON, 0 );
4679                         }
4680                 }
4681         }
4682
4683         // if we should be ignoring keys because of some multiplayer situations
4684         if((Game_mode & GM_MULTIPLAYER) && multi_ignore_controls(k)){
4685                 return 0;
4686         }
4687
4688         // If a popup is running, don't process all the Fn keys
4689         if( popup_active() ) {
4690                 return k;
4691         }
4692
4693         state = gameseq_get_state();
4694
4695 //      if ( k ) nprintf(( "General", "Key = %x\n", k ));
4696
4697         switch (k) {
4698                 case KEY_DEBUGGED + SDLK_BACKSPACE:
4699                         Int3();
4700                         break;
4701
4702                 case SDLK_F1:
4703                         launch_context_help();
4704                         k = 0;
4705                         break;
4706
4707                 case SDLK_F2:
4708 //                      if (state != GS_STATE_INITIAL_PLAYER_SELECT) {
4709
4710                         // don't allow f2 while warping out in multiplayer      
4711                         if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_WARPING_OUT)){
4712                                 break;
4713                         }
4714
4715                         switch (state) {
4716                                 case GS_STATE_INITIAL_PLAYER_SELECT:
4717                                 case GS_STATE_OPTIONS_MENU:
4718                                 case GS_STATE_HUD_CONFIG:
4719                                 case GS_STATE_CONTROL_CONFIG:
4720                                 case GS_STATE_DEATH_DIED:
4721                                 case GS_STATE_DEATH_BLEW_UP:            
4722                                 case GS_STATE_VIEW_MEDALS:
4723                                         break;
4724
4725                                 default:
4726                                         gameseq_post_event(GS_EVENT_OPTIONS_MENU);
4727                                         k = 0;
4728                                         break;
4729                         }
4730
4731                         break;
4732
4733                         // hotkey selection screen -- only valid from briefing and beyond.
4734                 case SDLK_F3:
4735 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
4736                                 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) ) {
4737                                         gameseq_post_event( GS_EVENT_HOTKEY_SCREEN );
4738                                         k = 0;
4739                                 }
4740 #endif
4741                         break;
4742
4743                 case KEY_DEBUGGED + SDLK_F3:
4744                         gameseq_post_event( GS_EVENT_TOGGLE_FULLSCREEN );
4745                         break;
4746
4747                 case KEY_DEBUGGED + SDLK_F4:
4748                         gameseq_post_event( GS_EVENT_TOGGLE_GLIDE );
4749                         break;
4750
4751                 case SDLK_F4:
4752                         if(Game_mode & GM_MULTIPLAYER){
4753                                 if((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_MULTI_PAUSED)){
4754                                         gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4755                                         k = 0;
4756                                 } 
4757                         } else {
4758                                 if ((state == GS_STATE_GAME_PLAY) || (state == GS_STATE_DEATH_DIED) || (state == GS_STATE_DEATH_BLEW_UP) || (state == GS_STATE_GAME_PAUSED) ) {
4759                                         gameseq_post_event( GS_EVENT_MISSION_LOG_SCROLLBACK );
4760                                         k = 0;
4761                                 }
4762                         }
4763                         break;
4764
4765                 case SDLK_ESCAPE | KEY_SHIFTED:
4766                         // make sure to quit properly out of multiplayer
4767                         if(Game_mode & GM_MULTIPLAYER){
4768                                 multi_quit_game(PROMPT_NONE);
4769                         }
4770
4771                         gameseq_post_event( GS_EVENT_QUIT_GAME );
4772                         k = 0;
4773
4774                         break;
4775
4776                 case KEY_DEBUGGED + SDLK_p:
4777                         break;                  
4778
4779                 case SDLK_PRINTSCREEN:
4780                         {
4781                                 static int counter = 0;
4782                                 char tmp_name[127];
4783
4784                                 game_stop_time();
4785
4786                                 SDL_snprintf( tmp_name, SDL_arraysize(tmp_name), NOX("screen%02d"), counter );
4787                                 counter++;
4788                                 mprintf(( "Dumping screen to '%s'\n", tmp_name ));
4789                                 gr_print_screen(tmp_name);
4790
4791                                 game_start_time();
4792                         }
4793
4794                         k = 0;
4795                         break;
4796
4797                 case KEY_SHIFTED | SDLK_RETURN: {
4798
4799 #if !defined(NDEBUG)
4800
4801                         if ( Game_mode & GM_NORMAL ){
4802                                 game_stop_time();
4803                         }
4804
4805                         // if we're in multiplayer mode, do some special networking
4806                         if(Game_mode & GM_MULTIPLAYER){
4807                                 debug_console(game_do_dc_networking);
4808                         } else {                                
4809                                 debug_console();
4810                         }
4811
4812                         game_flush();
4813
4814                         if ( Game_mode & GM_NORMAL )
4815                                 game_start_time();
4816
4817 #endif
4818
4819                         break;
4820                 }
4821         }
4822
4823         return k;
4824 }
4825
4826 void os_close()
4827 {
4828         gameseq_post_event(GS_EVENT_QUIT_GAME);
4829 }
4830
4831 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos );
4832
4833
4834 void camera_set_position( vector *pos )
4835 {
4836         Camera_pos = *pos;
4837 }
4838
4839 void camera_set_orient( matrix *orient )
4840 {
4841         Camera_orient = *orient;
4842 }
4843
4844 void camera_set_velocity( vector *vel, int instantaneous )
4845 {
4846         Camera_desired_velocity.xyz.x = 0.0f;
4847         Camera_desired_velocity.xyz.y = 0.0f;
4848         Camera_desired_velocity.xyz.z = 0.0f;
4849
4850         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.rvec, vel->xyz.x );
4851         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.uvec, vel->xyz.y );
4852         vm_vec_scale_add2( &Camera_desired_velocity, &Camera_orient.v.fvec, vel->xyz.z );
4853
4854         if ( instantaneous )    {
4855                 Camera_velocity = Camera_desired_velocity;
4856         }
4857
4858 }
4859
4860 //
4861 void camera_move()
4862 {
4863         vector new_vel, delta_pos;
4864
4865         apply_physics( Camera_damping, Camera_desired_velocity.xyz.x, Camera_velocity.xyz.x, flFrametime, &new_vel.xyz.x, &delta_pos.xyz.x );
4866         apply_physics( Camera_damping, Camera_desired_velocity.xyz.y, Camera_velocity.xyz.y, flFrametime, &new_vel.xyz.y, &delta_pos.xyz.y );
4867         apply_physics( Camera_damping, Camera_desired_velocity.xyz.z, Camera_velocity.xyz.z, flFrametime, &new_vel.xyz.z, &delta_pos.xyz.z );
4868
4869         Camera_velocity = new_vel;
4870
4871 //      mprintf(( "Camera velocity = %.1f,%.1f, %.1f\n", Camera_velocity.xyz.x, Camera_velocity.xyz.y, Camera_velocity.xyz.z ));
4872
4873         vm_vec_add2( &Camera_pos, &delta_pos );
4874
4875         float ot = Camera_time+0.0f;
4876
4877         Camera_time += flFrametime;
4878
4879         if ( (ot < 0.667f) && ( Camera_time >= 0.667f ) )       {
4880                 vector tmp;
4881                 
4882                 tmp.xyz.z = 4.739f;             // always go this fast forward.
4883
4884                 // pick x and y velocities so they are always on a 
4885                 // circle with a 25 m radius.
4886
4887                 float tmp_angle = frand()*PI2;
4888         
4889                 tmp.xyz.x = 22.0f * (float)sin(tmp_angle);
4890                 tmp.xyz.y = -22.0f * (float)cos(tmp_angle);
4891
4892                 //mprintf(( "Angle = %.1f, vx=%.1f, vy=%.1f\n", tmp_angle, tmp.xyz.x, tmp.xyz.y ));
4893
4894                 //mprintf(( "Changing velocity!\n" ));
4895                 camera_set_velocity( &tmp, 0 );
4896         }
4897
4898         if ( (ot < 3.0f ) && ( Camera_time >= 3.0f ) )  {
4899                 vector tmp = ZERO_VECTOR;
4900                 camera_set_velocity( &tmp, 0 );
4901         }
4902         
4903 }
4904
4905 void end_demo_campaign_do()
4906 {
4907 #if defined(FS2_DEMO) || defined(FS1_DEMO)
4908         // show upsell screens
4909         demo_upsell_show_screens();
4910 #elif defined(OEM_BUILD)
4911         // show oem upsell screens
4912         oem_upsell_show_screens();
4913 #endif
4914
4915         // drop into main hall
4916         gameseq_post_event( GS_EVENT_MAIN_MENU );
4917 }
4918
4919 // All code to process events.   This is the only place
4920 // that you should change the state of the game.
4921 void game_process_event( int current_state, int event )
4922 {
4923         mprintf(("Got event %s in state %s\n", GS_event_text[event], GS_state_text[current_state]));
4924
4925         switch (event) {
4926                 case GS_EVENT_SIMULATOR_ROOM:
4927                         gameseq_set_state(GS_STATE_SIMULATOR_ROOM);
4928                         break;
4929
4930                 case GS_EVENT_MAIN_MENU:
4931                         gameseq_set_state(GS_STATE_MAIN_MENU);          
4932                         break;
4933
4934                 case GS_EVENT_OPTIONS_MENU:
4935                         gameseq_push_state( GS_STATE_OPTIONS_MENU );
4936                         break;
4937
4938                 case GS_EVENT_BARRACKS_MENU:
4939                         gameseq_set_state(GS_STATE_BARRACKS_MENU);              
4940                         break;
4941
4942                 case GS_EVENT_TECH_MENU:
4943                         gameseq_set_state(GS_STATE_TECH_MENU);          
4944                         break;
4945
4946                 case GS_EVENT_TRAINING_MENU:
4947                         gameseq_set_state(GS_STATE_TRAINING_MENU);              
4948                         break;
4949
4950                 case GS_EVENT_START_GAME:
4951                         Select_default_ship = 0;                        
4952                         Player_multi_died_check = -1;
4953                         gameseq_set_state(GS_STATE_CMD_BRIEF);
4954                         break;
4955
4956                 case GS_EVENT_START_BRIEFING:
4957                         gameseq_set_state(GS_STATE_BRIEFING);           
4958                         break;
4959
4960                 case GS_EVENT_DEBRIEF:
4961                         // did we end the campaign in the main freespace 2 single player campaign?
4962 #ifdef MAKE_FS1
4963                         if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace")) {
4964 #else
4965                         if(Campaign_ended_in_mission && (Game_mode & GM_CAMPAIGN_MODE) && !SDL_strcasecmp(Campaign.filename, "freespace2")) {
4966 #endif
4967                                 gameseq_post_event(GS_EVENT_END_CAMPAIGN);
4968                         } else {
4969                                 gameseq_set_state(GS_STATE_DEBRIEF);            
4970                         }
4971
4972                         Player_multi_died_check = -1;
4973                         break;
4974
4975                 case GS_EVENT_SHIP_SELECTION:
4976                         gameseq_set_state( GS_STATE_SHIP_SELECT );
4977                         break;
4978
4979                 case GS_EVENT_WEAPON_SELECTION:
4980                         gameseq_set_state( GS_STATE_WEAPON_SELECT );
4981                         break;
4982
4983                 case GS_EVENT_ENTER_GAME:               
4984 #ifdef DEMO_SYSTEM
4985                         // maybe start recording a demo
4986                         if(Demo_make){
4987                                 demo_start_record("test.fsd");
4988                         }
4989 #endif
4990
4991                         if (Game_mode & GM_MULTIPLAYER) {
4992                                 // if we're respawning, make sure we change the view mode so that the hud shows up
4993                                 if (current_state == GS_STATE_DEATH_BLEW_UP) {
4994                                         Viewer_mode = 0;
4995                                 }
4996
4997                                 gameseq_set_state(GS_STATE_GAME_PLAY);
4998                         } else {
4999                                 gameseq_set_state(GS_STATE_GAME_PLAY, 1);
5000                         }
5001
5002                         Player_multi_died_check = -1;
5003
5004                         // clear multiplayer button info                        
5005                         extern button_info Multi_ship_status_bi;
5006                         memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5007
5008                         Start_time = f2fl(timer_get_approx_seconds());
5009                         //Framecount = 0;
5010                         mprintf(("Entering game at time = %7.3f\n", Start_time));
5011                         break;
5012
5013
5014                 case GS_EVENT_START_GAME_QUICK:
5015                         Select_default_ship = 1;
5016                         gameseq_post_event(GS_EVENT_ENTER_GAME);
5017                         break;
5018
5019
5020                 case GS_EVENT_END_GAME:
5021                         if ( (current_state == GS_STATE_GAME_PLAY) || (current_state == GS_STATE_DEATH_DIED) ||
5022                                 (current_state == GS_STATE_DEATH_BLEW_UP) ||    (current_state == GS_STATE_DEBRIEF) || (current_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) {
5023                                         gameseq_set_state(GS_STATE_MAIN_MENU);
5024
5025                         } else
5026                                 Int3();
5027
5028                         Player_multi_died_check = -1;
5029                         break;
5030
5031                 case GS_EVENT_QUIT_GAME:
5032                         main_hall_stop_music();
5033                         main_hall_stop_ambient();
5034                         gameseq_set_state(GS_STATE_QUIT_GAME);
5035
5036                         Player_multi_died_check = -1;
5037                         break;
5038
5039                 case GS_EVENT_GAMEPLAY_HELP:
5040                         gameseq_push_state( GS_STATE_GAMEPLAY_HELP );
5041                         break;
5042
5043                 case GS_EVENT_PAUSE_GAME:
5044                         gameseq_push_state(GS_STATE_GAME_PAUSED);
5045                         break;
5046
5047                 case GS_EVENT_DEBUG_PAUSE_GAME:
5048                         gameseq_push_state(GS_STATE_DEBUG_PAUSED);
5049                         break;
5050
5051                 case GS_EVENT_TRAINING_PAUSE:
5052                         gameseq_push_state(GS_STATE_TRAINING_PAUSED);
5053                         break;
5054
5055                 case GS_EVENT_PREVIOUS_STATE:
5056                         gameseq_pop_state();
5057                         break;
5058
5059                 case GS_EVENT_TOGGLE_FULLSCREEN:
5060                         gr_toggle_fullscreen();
5061                         break;
5062
5063                 case GS_EVENT_TOGGLE_GLIDE:
5064                         break;                                          
5065  
5066                 case GS_EVENT_LOAD_MISSION_MENU:
5067                         break;
5068
5069                 case GS_EVENT_MISSION_LOG_SCROLLBACK:
5070                         gameseq_push_state( GS_STATE_MISSION_LOG_SCROLLBACK );
5071                         break;
5072
5073                 case GS_EVENT_HUD_CONFIG:
5074                         gameseq_push_state( GS_STATE_HUD_CONFIG );
5075                         break;
5076
5077                 case GS_EVENT_CONTROL_CONFIG:
5078                         gameseq_push_state( GS_STATE_CONTROL_CONFIG );
5079                         break;  
5080
5081                 case GS_EVENT_DEATH_DIED:
5082                         gameseq_set_state( GS_STATE_DEATH_DIED );
5083                         break;
5084
5085                 case GS_EVENT_DEATH_BLEW_UP:
5086                         if (  current_state == GS_STATE_DEATH_DIED )    {
5087                                 gameseq_set_state( GS_STATE_DEATH_BLEW_UP );
5088                                 event_music_player_death();
5089
5090                                 // multiplayer clients set their extra check here
5091                                 if(Game_mode & GM_MULTIPLAYER){
5092                                         // set the multi died absolute last chance check                                        
5093                                         Player_multi_died_check = time(NULL);
5094                                 }                                       
5095                         } else {
5096                                 mprintf(( "Ignoring GS_EVENT_DEATH_BLEW_UP because we're in state %d\n", current_state ));
5097                         }
5098                         break;
5099
5100                 case GS_EVENT_NEW_CAMPAIGN:
5101                         if (!mission_load_up_campaign()){
5102                                 readyroom_continue_campaign();
5103                         }
5104
5105                         Player_multi_died_check = -1;
5106                         break;
5107
5108                 case GS_EVENT_CAMPAIGN_CHEAT:
5109                         if (!mission_load_up_campaign()){
5110                                 /*
5111                                 // bash campaign value
5112                                 extern char Main_hall_campaign_cheat[512];
5113                                 int idx;
5114                                 
5115                                 // look for the mission
5116                                 for(idx=0; idx<Campaign.num_missions; idx++){
5117                                         if(!SDL_strcasecmp(Campaign.missions[idx].name, Main_hall_campaign_cheat)){
5118                                                 Campaign.next_mission = idx;
5119                                                 Campaign.prev_mission = idx - 1;
5120                                                 break;
5121                                         }
5122                                 }
5123                                 */
5124
5125                                 // continue
5126                                 readyroom_continue_campaign();
5127                         }
5128
5129                         Player_multi_died_check = -1;
5130                         break;
5131
5132                 case GS_EVENT_CAMPAIGN_ROOM:
5133                         gameseq_set_state(GS_STATE_CAMPAIGN_ROOM);
5134                         break;
5135
5136                 case GS_EVENT_CMD_BRIEF:
5137                         gameseq_set_state(GS_STATE_CMD_BRIEF);
5138                         break;
5139
5140                 case GS_EVENT_RED_ALERT:
5141                         gameseq_set_state(GS_STATE_RED_ALERT);
5142                         break;
5143
5144                 case GS_EVENT_CREDITS:
5145                         gameseq_set_state( GS_STATE_CREDITS );
5146                         break;
5147
5148                 case GS_EVENT_VIEW_MEDALS:
5149                         gameseq_push_state( GS_STATE_VIEW_MEDALS );
5150                         break;
5151
5152                 case GS_EVENT_SHOW_GOALS:
5153                         gameseq_push_state( GS_STATE_SHOW_GOALS );      // use push_state() since we might get to this screen through a variety of states
5154                         break;
5155
5156                 case GS_EVENT_HOTKEY_SCREEN:
5157                         gameseq_push_state( GS_STATE_HOTKEY_SCREEN );   // use push_state() since we might get to this screen through a variety of states
5158                         break;
5159                 
5160         // multiplayer stuff follow these comments
5161
5162                 case GS_EVENT_PXO:
5163                         gameseq_set_state(GS_STATE_PXO);
5164                         break;
5165
5166                 case GS_EVENT_PXO_HELP:
5167                         gameseq_set_state(GS_STATE_PXO_HELP);
5168                         break;
5169
5170                 case GS_EVENT_MULTI_JOIN_GAME:
5171                         gameseq_set_state( GS_STATE_MULTI_JOIN_GAME );
5172                         break;
5173
5174                 case GS_EVENT_MULTI_HOST_SETUP:
5175                         gameseq_set_state( GS_STATE_MULTI_HOST_SETUP );
5176                         break;
5177
5178                 case GS_EVENT_MULTI_CLIENT_SETUP:
5179                         gameseq_set_state( GS_STATE_MULTI_CLIENT_SETUP );
5180                         break;
5181
5182                 case GS_EVENT_GOTO_VIEW_CUTSCENES_SCREEN:
5183                         gameseq_set_state(GS_STATE_VIEW_CUTSCENES);
5184                         break;
5185
5186                 case GS_EVENT_MULTI_STD_WAIT:
5187                         gameseq_set_state( GS_STATE_MULTI_STD_WAIT );
5188                         break;
5189
5190                 case GS_EVENT_STANDALONE_MAIN:
5191                         gameseq_set_state( GS_STATE_STANDALONE_MAIN );
5192                         break;   
5193
5194                 case GS_EVENT_MULTI_PAUSE:
5195                         gameseq_push_state( GS_STATE_MULTI_PAUSED );
5196                         break;                  
5197
5198                 case GS_EVENT_INGAME_PRE_JOIN:
5199                         gameseq_set_state( GS_STATE_INGAME_PRE_JOIN );
5200                         break;
5201                 
5202                 case GS_EVENT_EVENT_DEBUG:
5203                         gameseq_push_state(GS_STATE_EVENT_DEBUG);
5204                         break;
5205
5206                 // Start a warpout where player automatically goes 70 no matter what
5207                 // and can't cancel out of it.
5208                 case GS_EVENT_PLAYER_WARPOUT_START_FORCED:
5209                         Warpout_forced = 1;                                                     // If non-zero, bash the player to speed and go through effect
5210
5211                         // Same code as in GS_EVENT_PLAYER_WARPOUT_START only ignores current mode
5212                         Player->saved_viewer_mode = Viewer_mode;
5213                         Player->control_mode = PCM_WARPOUT_STAGE1;
5214                         Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5215                         Warpout_time = 0.0f;                    // Start timer!
5216                         break;
5217
5218                 case GS_EVENT_PLAYER_WARPOUT_START:
5219                         if ( Player->control_mode != PCM_NORMAL )       {
5220                                 mprintf(( "Player isn't in normal mode; cannot warp out.\n" ));
5221                         } else {
5222                                 Player->saved_viewer_mode = Viewer_mode;
5223                                 Player->control_mode = PCM_WARPOUT_STAGE1;
5224                                 Warpout_sound = snd_play(&Snds[SND_PLAYER_WARP_OUT]);
5225                                 Warpout_time = 0.0f;                    // Start timer!
5226                                 Warpout_forced = 0;                             // If non-zero, bash the player to speed and go through effect
5227                         }
5228                         break;
5229
5230                 case GS_EVENT_PLAYER_WARPOUT_STOP:
5231                         if ( Player->control_mode != PCM_NORMAL )       {
5232                                 if ( !Warpout_forced )  {               // cannot cancel forced warpout
5233                                         Player->control_mode = PCM_NORMAL;
5234                                         Viewer_mode = Player->saved_viewer_mode;
5235                                         hud_subspace_notify_abort();
5236                                         mprintf(( "Player put back to normal mode.\n" ));
5237                                         if ( Warpout_sound > -1 )       {
5238                                                 snd_stop( Warpout_sound );
5239                                                 Warpout_sound = -1;
5240                                         }
5241                                 }
5242                         }
5243                         break;
5244
5245                 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE1:               // player ship got up to speed
5246                         if ( Player->control_mode != PCM_WARPOUT_STAGE1 )       {
5247                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5248                                 mprintf(( "Player put back to normal mode, because of invalid sequence in stage1.\n" ));
5249                         } else {
5250                                 mprintf(( "Hit target speed.  Starting warp effect and moving to stage 2!\n" ));
5251                                 shipfx_warpout_start( Player_obj );
5252                                 Player->control_mode = PCM_WARPOUT_STAGE2;
5253                                 Player->saved_viewer_mode = Viewer_mode;
5254                                 Viewer_mode |= VM_WARP_CHASE;
5255                                 
5256                                 vector tmp = Player_obj->pos;
5257                                 matrix tmp_m;
5258                                 ship_get_eye( &tmp, &tmp_m, Player_obj );
5259                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.rvec, 0.0f );
5260                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.uvec, 0.952f );
5261                                 vm_vec_scale_add2( &tmp, &Player_obj->orient.v.fvec, -1.782f );
5262                                 Camera_time = 0.0f;
5263                                 camera_set_position( &tmp );
5264                                 camera_set_orient( &Player_obj->orient );
5265                                 vector tmp_vel = { { { 0.0f, 5.1919f, 14.7f } } };
5266
5267                                 //mprintf(( "Rad = %.1f\n", Player_obj->radius ));
5268                                 camera_set_velocity( &tmp_vel, 1);
5269                         }
5270                         break;
5271
5272                 case GS_EVENT_PLAYER_WARPOUT_DONE_STAGE2:               // player ship got into the warp effect
5273                         if ( Player->control_mode != PCM_WARPOUT_STAGE2 )       {
5274                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
5275                                 mprintf(( "Player put back to normal mode, because of invalid sequence in stage2.\n" ));
5276                         } else {
5277                                 mprintf(( "Hit warp effect.  Moving to stage 3!\n" ));
5278                                 Player->control_mode = PCM_WARPOUT_STAGE3;
5279                         }
5280                         break;
5281
5282                 case GS_EVENT_PLAYER_WARPOUT_DONE:      // player ship got through the warp effect
5283                         mprintf(( "Player warped out.  Going to debriefing!\n" ));
5284                         Player->control_mode = PCM_NORMAL;
5285                         Viewer_mode = Player->saved_viewer_mode;
5286                         Warpout_sound = -1;
5287
5288                         // we have a special debriefing screen for multiplayer furballs
5289                         if((Game_mode & GM_MULTIPLAYER) && (The_mission.game_type & MISSION_TYPE_MULTI_DOGFIGHT)){
5290                                 gameseq_post_event(GS_EVENT_MULTI_DOGFIGHT_DEBRIEF);
5291                         }
5292                         // do the normal debriefing for all other situations
5293                         else {
5294                                 gameseq_post_event(GS_EVENT_DEBRIEF);
5295                         }
5296                         break;
5297
5298                 case GS_EVENT_STANDALONE_POSTGAME:
5299                         gameseq_set_state(GS_STATE_STANDALONE_POSTGAME);
5300                         break;
5301
5302                 case GS_EVENT_INITIAL_PLAYER_SELECT:
5303                         gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5304                         break;
5305
5306                 case GS_EVENT_GAME_INIT:
5307 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
5308                         gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5309 #else                   
5310                         // see if the command line option has been set to use the last pilot, and act acoordingly
5311                         if( player_select_get_last_pilot() ) {                                                          
5312                                 // always enter the main menu -- do the automatic network startup stuff elsewhere
5313                                 // so that we still have valid checks for networking modes, etc.
5314                                 gameseq_set_state(GS_STATE_MAIN_MENU);
5315                         } else {
5316                                 gameseq_set_state(GS_STATE_INITIAL_PLAYER_SELECT);
5317                         }
5318 #endif
5319                         break;
5320
5321                 case GS_EVENT_MULTI_MISSION_SYNC:
5322                         gameseq_set_state(GS_STATE_MULTI_MISSION_SYNC);
5323                         break;          
5324
5325                 case GS_EVENT_MULTI_START_GAME:
5326                         gameseq_set_state(GS_STATE_MULTI_START_GAME);
5327                         break;
5328
5329                 case GS_EVENT_MULTI_HOST_OPTIONS:
5330                         gameseq_set_state(GS_STATE_MULTI_HOST_OPTIONS);
5331                         break;
5332
5333                 case GS_EVENT_MULTI_DOGFIGHT_DEBRIEF:
5334                         gameseq_set_state(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
5335                         break;
5336
5337                 case GS_EVENT_TEAM_SELECT:
5338                         gameseq_set_state(GS_STATE_TEAM_SELECT);
5339                         break;
5340
5341                 case GS_EVENT_END_CAMPAIGN:                     
5342                         gameseq_set_state(GS_STATE_END_OF_CAMPAIGN);
5343                         break;          
5344
5345                 case GS_EVENT_END_DEMO:
5346                         gameseq_set_state(GS_STATE_END_DEMO);
5347                         break;
5348
5349                 case GS_EVENT_LOOP_BRIEF:
5350                         gameseq_set_state(GS_STATE_LOOP_BRIEF);
5351                         break;
5352
5353                 default:
5354                         Int3();
5355                         break;
5356         }
5357 }
5358
5359 // Called when a state is being left.
5360 // The current state is still at old_state, but as soon as
5361 // this function leaves, then the current state will become
5362 // new state.     You should never try to change the state
5363 // in here... if you think you need to, you probably really
5364 // need to post an event, not change the state.
5365 void game_leave_state( int old_state, int new_state )
5366 {
5367         int end_mission = 1;
5368
5369         switch (new_state) {
5370                 case GS_STATE_GAME_PAUSED:
5371                 case GS_STATE_DEBUG_PAUSED:
5372                 case GS_STATE_OPTIONS_MENU:
5373                 case GS_STATE_CONTROL_CONFIG:           
5374                 case GS_STATE_MISSION_LOG_SCROLLBACK:
5375                 case GS_STATE_DEATH_DIED:
5376                 case GS_STATE_SHOW_GOALS:
5377                 case GS_STATE_HOTKEY_SCREEN:            
5378                 case GS_STATE_MULTI_PAUSED:
5379                 case GS_STATE_TRAINING_PAUSED:
5380                 case GS_STATE_EVENT_DEBUG:                              
5381                 case GS_STATE_GAMEPLAY_HELP:
5382                         end_mission = 0;  // these events shouldn't end a mission
5383                         break;
5384         }
5385
5386         switch (old_state) {
5387                 case GS_STATE_BRIEFING:
5388                         brief_stop_voices();
5389                         if ( (new_state != GS_STATE_OPTIONS_MENU) && (new_state != GS_STATE_WEAPON_SELECT)
5390                                   && (new_state != GS_STATE_SHIP_SELECT) && (new_state != GS_STATE_HOTKEY_SCREEN)
5391                                   && (new_state != GS_STATE_TEAM_SELECT) ){
5392                                 common_select_close();
5393                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5394                                         freespace_stop_mission();       
5395                                 }
5396                         }
5397                         
5398                         // COMMAND LINE OPTION
5399                         if (Cmdline_multi_stream_chat_to_file){
5400                                 cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5401                                 cfclose(Multi_chat_stream);
5402                         }
5403                         break;
5404
5405                 case GS_STATE_DEBRIEF:
5406                         if ( (new_state != GS_STATE_VIEW_MEDALS) && (new_state != GS_STATE_OPTIONS_MENU) ) {
5407                                 debrief_close();                                
5408                         }
5409                         break;
5410
5411                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5412                         multi_df_debrief_close();
5413                         break;
5414
5415                 case GS_STATE_LOAD_MISSION_MENU:
5416                         break;
5417
5418                 case GS_STATE_SIMULATOR_ROOM:
5419                         sim_room_close();
5420                         break;
5421
5422                 case GS_STATE_CAMPAIGN_ROOM:
5423                         campaign_room_close();
5424                         break;
5425
5426                 case GS_STATE_CMD_BRIEF:
5427                         if (new_state == GS_STATE_OPTIONS_MENU) {
5428                                 cmd_brief_hold();
5429
5430                         } else {
5431                                 cmd_brief_close();
5432                                 if (new_state == GS_STATE_MAIN_MENU)
5433                                         freespace_stop_mission();       
5434                         }
5435
5436                         break;
5437
5438                 case GS_STATE_RED_ALERT:
5439                         red_alert_close();
5440                         break;
5441
5442                 case GS_STATE_SHIP_SELECT:
5443                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_WEAPON_SELECT &&
5444                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5445                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5446                                 common_select_close();
5447                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5448                                         freespace_stop_mission();       
5449                                 }
5450                         }
5451                         break;
5452
5453                 case GS_STATE_WEAPON_SELECT:
5454                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5455                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5456                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_TEAM_SELECT) {
5457                                 common_select_close();
5458                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5459                                         freespace_stop_mission();       
5460                                 }
5461                         }
5462                         break;
5463
5464                 case GS_STATE_TEAM_SELECT:
5465                         if ( new_state != GS_STATE_OPTIONS_MENU && new_state != GS_STATE_SHIP_SELECT &&
5466                                   new_state != GS_STATE_HOTKEY_SCREEN &&
5467                                   new_state != GS_STATE_BRIEFING && new_state != GS_STATE_WEAPON_SELECT) {
5468                                 common_select_close();
5469                                 if ( new_state == GS_STATE_MAIN_MENU ) {
5470                                         freespace_stop_mission();       
5471                                 }
5472                         }                                       
5473                         break;
5474
5475                 case GS_STATE_MAIN_MENU:
5476 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5477                         mht_close();
5478 #else
5479                         main_hall_close();
5480 #endif
5481                         break;
5482
5483                 case GS_STATE_OPTIONS_MENU:
5484                         //game_start_time();
5485                         if(new_state == GS_STATE_MULTI_JOIN_GAME){
5486                                 multi_join_clear_game_list();
5487                         }
5488                         options_menu_close();
5489                         break;
5490
5491                 case GS_STATE_BARRACKS_MENU:
5492                         if(new_state != GS_STATE_VIEW_MEDALS){
5493                                 barracks_close();
5494                         }
5495                         break;
5496
5497                 case GS_STATE_MISSION_LOG_SCROLLBACK:
5498                         hud_scrollback_close();
5499                         break;
5500
5501                 case GS_STATE_TRAINING_MENU:
5502                         training_menu_close();
5503                         break;
5504
5505                 case GS_STATE_GAME_PLAY:
5506                         if ( !(Game_mode & GM_STANDALONE_SERVER) ) {
5507                                 player_save_target_and_weapon_link_prefs();
5508                                 game_stop_looped_sounds();
5509                         }
5510
5511                         sound_env_disable();
5512                         joy_ff_stop_effects();
5513
5514                         // stop game time under certain conditions
5515                         if ( end_mission || (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MULTI_PAUSED)) ){
5516                                 game_stop_time();
5517                         }
5518
5519                         if (end_mission) {
5520                         // shut down any recording or playing demos
5521 #ifdef DEMO_SYSTEM
5522                                 demo_close();
5523 #endif
5524
5525                                 // when in multiplayer and going back to the main menu, send a leave game packet
5526                                 // right away (before calling stop mission).  stop_mission was taking to long to
5527                                 // close mission down and I want people to get notified ASAP.
5528                                 if ( (Game_mode & GM_MULTIPLAYER) && (new_state == GS_STATE_MAIN_MENU) ){
5529                                         multi_quit_game(PROMPT_NONE);
5530                                 }
5531
5532                                 freespace_stop_mission();                       
5533                                 Game_time_compression = F1_0;
5534                         }
5535                         break;
5536
5537                 case GS_STATE_TECH_MENU:
5538                         techroom_close();
5539                         break;
5540
5541                 case GS_STATE_TRAINING_PAUSED:
5542                         Training_num_lines = 0;
5543                         // fall through to GS_STATE_GAME_PAUSED
5544
5545                 case GS_STATE_GAME_PAUSED:
5546                         game_start_time();
5547                         if ( end_mission ) {
5548                                 pause_close(0);
5549                         }
5550                         break;
5551
5552                 case GS_STATE_DEBUG_PAUSED:
5553                         #ifndef NDEBUG
5554                                 game_start_time();
5555                                 pause_debug_close();
5556                         #endif
5557                         break;
5558
5559                 case GS_STATE_HUD_CONFIG:
5560                         hud_config_close();
5561                         break;
5562
5563                 // join/start a game
5564                 case GS_STATE_MULTI_JOIN_GAME:
5565                         if(new_state != GS_STATE_OPTIONS_MENU){
5566                                 multi_join_game_close();
5567                         }
5568                         break;
5569
5570                 case GS_STATE_MULTI_HOST_SETUP:
5571                 case GS_STATE_MULTI_CLIENT_SETUP:
5572                         // if this is just the host going into the options screen, don't do anything
5573                         if((new_state == GS_STATE_MULTI_HOST_OPTIONS) || (new_state == GS_STATE_OPTIONS_MENU)){
5574                                 break;
5575                         }
5576
5577                         // close down the proper state
5578                         if(old_state == GS_STATE_MULTI_HOST_SETUP){
5579                                 multi_create_game_close();
5580                         } else {
5581                                 multi_game_client_setup_close();
5582                         }
5583
5584                         // COMMAND LINE OPTION
5585                         if (Cmdline_multi_stream_chat_to_file){
5586                                 if( (new_state != GS_STATE_TEAM_SELECT) && (Multi_chat_stream!=NULL) ) {
5587                                         cfwrite_string(NOX("-------------------------------------------\n"),Multi_chat_stream);
5588                                         cfclose(Multi_chat_stream);
5589                                 }
5590                         }                       
5591                         break;
5592
5593                 case GS_STATE_CONTROL_CONFIG:
5594                         control_config_close();
5595                         break;
5596
5597                 case GS_STATE_DEATH_DIED:
5598                         Game_mode &= ~GM_DEAD_DIED;
5599                         
5600                         // early end while respawning or blowing up in a multiplayer game
5601                         if((Game_mode & GM_MULTIPLAYER) && ((new_state == GS_STATE_DEBRIEF) || (new_state == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) ){
5602                                 game_stop_time();
5603                                 freespace_stop_mission();
5604                         }
5605                         break;
5606
5607                 case GS_STATE_DEATH_BLEW_UP:
5608                         Game_mode &= ~GM_DEAD_BLEW_UP;
5609
5610                         // for single player, we might reload mission, etc.  For multiplayer, look at my new state
5611                         // to determine if I should do anything.
5612                         if ( !(Game_mode & GM_MULTIPLAYER) ) {
5613                                 if ( end_mission ){
5614                                         freespace_stop_mission();
5615                                 }
5616                         } else {
5617                                 // if we are not respawing as an observer or as a player, our new state will not
5618                                 // be gameplay state.
5619                                 if ( (new_state != GS_STATE_GAME_PLAY) && (new_state != GS_STATE_MULTI_PAUSED) ) {
5620                                         game_stop_time();                                                                       // hasn't been called yet!!
5621                                         freespace_stop_mission();
5622                                 }
5623                         }
5624                         break;
5625
5626
5627                 case GS_STATE_CREDITS:
5628                         credits_close();
5629                         break;
5630
5631                 case GS_STATE_VIEW_MEDALS:
5632                         medal_main_close();
5633                         break;
5634
5635                 case GS_STATE_SHOW_GOALS:
5636                         mission_show_goals_close();
5637                         break;
5638
5639                 case GS_STATE_HOTKEY_SCREEN:
5640                         if ( new_state != GS_STATE_OPTIONS_MENU ) {
5641                                 mission_hotkey_close();
5642                         }
5643                         break;
5644
5645                 case GS_STATE_MULTI_MISSION_SYNC:
5646                         // if we're moving into the options menu, don't do anything
5647                         if(new_state == GS_STATE_OPTIONS_MENU){
5648                                 break;
5649                         }
5650
5651                         SDL_assert( Game_mode & GM_MULTIPLAYER );
5652                         multi_sync_close();
5653                         if ( new_state == GS_STATE_GAME_PLAY ){
5654                                 // palette_restore_palette();
5655
5656                                 // change a couple of flags to indicate our state!!!
5657                                 Net_player->state = NETPLAYER_STATE_IN_MISSION;
5658                                 send_netplayer_update_packet();
5659
5660                                 // set the game mode
5661                                 Game_mode |= GM_IN_MISSION;
5662                         }                       
5663                         break;          
5664    
5665                 case GS_STATE_VIEW_CUTSCENES:
5666                         cutscenes_screen_close();
5667                         break;
5668
5669                 case GS_STATE_MULTI_STD_WAIT:
5670                         multi_standalone_wait_close();
5671                         break;
5672
5673                 case GS_STATE_STANDALONE_MAIN:                  
5674                         standalone_main_close();
5675                         if(new_state == GS_STATE_MULTI_STD_WAIT){               
5676                                 init_multiplayer_stats();                                                                               
5677                         }                       
5678                         break;
5679
5680                 case GS_STATE_MULTI_PAUSED:
5681                         // if ( end_mission ){
5682                                 pause_close(1);
5683                         // }
5684                         break;                  
5685
5686                 case GS_STATE_INGAME_PRE_JOIN:
5687                         multi_ingame_select_close();
5688                         break;
5689
5690                 case GS_STATE_STANDALONE_POSTGAME:
5691                         multi_standalone_postgame_close();
5692                         break;
5693
5694                 case GS_STATE_INITIAL_PLAYER_SELECT:                    
5695                         player_select_close();                  
5696                         break;          
5697
5698                 case GS_STATE_MULTI_START_GAME:
5699                         multi_start_game_close();
5700                         break;
5701
5702                 case GS_STATE_MULTI_HOST_OPTIONS:
5703                         multi_host_options_close();
5704                         break;                          
5705
5706                 case GS_STATE_END_OF_CAMPAIGN:
5707                         mission_campaign_end_close();
5708                         break;
5709
5710                 case GS_STATE_LOOP_BRIEF:
5711                         loop_brief_close();
5712                         break;
5713
5714                 case GS_STATE_PXO:
5715                         if (new_state != GS_STATE_PXO_HELP) {
5716                                 multi_pxo_close();
5717                         }
5718                         break;
5719
5720                 case GS_STATE_PXO_HELP:
5721                         multi_pxo_help_close();
5722                         break;
5723         }
5724 }
5725
5726 // Called when a state is being entered.
5727 // The current state is set to the state we're entering at
5728 // this point, and old_state is set to the state we're coming
5729 // from.    You should never try to change the state
5730 // in here... if you think you need to, you probably really
5731 // need to post an event, not change the state.
5732
5733 void game_enter_state( int old_state, int new_state )
5734 {
5735         switch (new_state) {
5736                 case GS_STATE_MAIN_MENU:                                
5737                         // in multiplayer mode, be sure that we are not doing networking anymore.
5738                         if ( Game_mode & GM_MULTIPLAYER ) {
5739                                 SDL_assert( Net_player != NULL );
5740                                 Net_player->flags &= ~NETINFO_FLAG_DO_NETWORKING;
5741                         }
5742
5743                         Game_time_compression = F1_0;
5744         
5745                         // determine which ship this guy is currently based on
5746 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
5747                         mht_init();
5748 #else
5749                         if (Player->on_bastion) {
5750                                 main_hall_init(1);
5751                         } else {
5752                                 main_hall_init(0);
5753                         }
5754 #endif
5755                         break;
5756
5757                 case GS_STATE_BRIEFING:
5758                         main_hall_stop_music();
5759                         main_hall_stop_ambient();
5760                         
5761                         if (Game_mode & GM_NORMAL) {
5762                                 // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5763                                 // MWA: or from options or hotkey screens
5764                                 // JH: or if the command brief state already did this
5765                                 if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5766                                         && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT)
5767                                         && (old_state != GS_STATE_CMD_BRIEF) ) {
5768                                         if ( !game_start_mission() )                    // this should put us into a new state on failure!
5769                                                 break;
5770                                 }
5771                         }
5772                         // maybe play a movie before the briefing.  don't play if entering briefing screen from ship or weapon select.
5773                         if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5774                                 mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5775
5776                         Game_time_compression = F1_0;
5777
5778                         if ( red_alert_mission() ) {
5779                                 gameseq_post_event(GS_EVENT_RED_ALERT);
5780                         } else {
5781                                 brief_init();
5782                         }
5783
5784                         break;
5785
5786                 case GS_STATE_DEBRIEF:
5787                         game_stop_looped_sounds();
5788                         mission_goal_fail_incomplete();                         // fail all incomplete goals before entering debriefing
5789                         if ( (old_state != GS_STATE_VIEW_MEDALS) && (old_state != GS_STATE_OPTIONS_MENU) ){
5790                                 debrief_init();
5791                         }
5792                         break;
5793
5794                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
5795                         multi_df_debrief_init();
5796                         break;
5797
5798                 case GS_STATE_LOAD_MISSION_MENU:
5799                         break;
5800
5801                 case GS_STATE_SIMULATOR_ROOM:
5802                         sim_room_init();
5803                         break;
5804
5805                 case GS_STATE_CAMPAIGN_ROOM:
5806                         campaign_room_init();
5807                         break;
5808
5809                 case GS_STATE_RED_ALERT:
5810                         mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5811                         red_alert_init();
5812                         break;
5813
5814                 case GS_STATE_CMD_BRIEF: {
5815                         int team_num = 0;  // team number used as index for which cmd brief to use.
5816
5817                         if (old_state == GS_STATE_OPTIONS_MENU) {
5818                                 cmd_brief_unhold();
5819
5820                         } else {
5821                                 main_hall_stop_music();
5822                                 main_hall_stop_ambient();
5823
5824                                 if (Game_mode & GM_NORMAL) {
5825                                         // AL: Don't call freespace_start_mission() if re-entering from ship or weapon select
5826                                         // MWA: or from options or hotkey screens
5827                                         // JH: or if the command brief state already did this
5828                                         if ( (old_state != GS_STATE_OPTIONS_MENU) && (old_state != GS_STATE_HOTKEY_SCREEN)
5829                                                 && (old_state != GS_STATE_SHIP_SELECT) && (old_state != GS_STATE_WEAPON_SELECT) ) {
5830                                                 if ( !game_start_mission() )                    // this should put us into a new state on failure!
5831                                                         break;
5832                                         }
5833                                 }
5834
5835                                 // maybe play a movie before the briefing.  don't play if entering briefing screen from ship or weapon select.
5836                                 if ( (old_state == GS_STATE_DEBRIEF) || (old_state == GS_STATE_SIMULATOR_ROOM) || (old_state == GS_STATE_MAIN_MENU))
5837                                         mission_campaign_maybe_play_movie(CAMPAIGN_MOVIE_PRE_MISSION);
5838
5839                                 cmd_brief_init(team_num);
5840                         }
5841
5842                         break;
5843                 }
5844
5845                 case GS_STATE_SHIP_SELECT:
5846                         ship_select_init();
5847                         break;
5848
5849                 case GS_STATE_WEAPON_SELECT:
5850                         weapon_select_init();
5851                         break;
5852
5853                 case GS_STATE_TEAM_SELECT:              
5854                         multi_ts_init();
5855                         break;
5856
5857                 case GS_STATE_GAME_PAUSED:
5858                         game_stop_time();
5859                         pause_init(0);
5860                         break;
5861
5862                 case GS_STATE_DEBUG_PAUSED:
5863         //              game_stop_time();
5864         //              os_set_title("FreeSpace - PAUSED");
5865         //              break;
5866         //
5867                 case GS_STATE_TRAINING_PAUSED:
5868                         #ifndef NDEBUG
5869                                 game_stop_time();
5870                                 pause_debug_init();
5871                         #endif
5872                         break;
5873
5874                 case GS_STATE_OPTIONS_MENU:
5875                         //game_stop_time();
5876                         options_menu_init();
5877                         break;
5878  
5879                 case GS_STATE_GAME_PLAY:
5880                         // coming from the gameplay state or the main menu, we might need to load the mission
5881                         if ( (Game_mode & GM_NORMAL) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_GAME_PLAY) || (old_state == GS_STATE_DEATH_BLEW_UP)) ) {
5882                                 if ( !game_start_mission() )            // this should put us into a new state.
5883                                         // Failed!!!
5884                                         break;
5885                         }
5886
5887                         // if we are coming from the briefing, ship select, weapons loadout, or main menu (in the
5888                         // case of quick start), then do bitmap loads, etc  Don't do any of the loading stuff
5889                         // if we are in multiplayer -- this stuff is all handled in the multi-wait section
5890                         if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_BRIEFING) || (old_state == GS_STATE_SHIP_SELECT) ||
5891                                 (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)) ) {
5892                                         // JAS: Used to do all paging here.
5893
5894                                         #ifndef NDEBUG
5895                                         //XSTR:OFF
5896                                                 HUD_printf("Skill level is set to ** %s **", Skill_level_names(Game_skill_level));
5897                                         //XSTR:ON
5898                                         #endif
5899
5900                                         main_hall_stop_music();
5901                                         main_hall_stop_ambient();
5902                                         event_music_first_pattern();    // start the first pattern
5903                         }
5904
5905                         // special code that restores player ship selection and weapons loadout when doing a quick start
5906                         if ( !(Game_mode & GM_MULTIPLAYER) && ((old_state == GS_STATE_MAIN_MENU) || (old_state == GS_STATE_DEATH_BLEW_UP)  || (old_state == GS_STATE_GAME_PLAY)) ) {
5907                                 if ( !SDL_strcasecmp(Player_loadout.filename, Game_current_mission_filename) ) {
5908                                         wss_direct_restore_loadout();
5909                                 }
5910                         }
5911
5912                         // single-player, quick-start after just died... we need to set weapon linking and kick off the event music
5913                         if (!(Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_DEATH_BLEW_UP) ) {
5914                                 event_music_first_pattern();    // start the first pattern
5915                         }
5916
5917                         if ( !(Game_mode & GM_STANDALONE_SERVER) && (old_state != GS_STATE_GAME_PAUSED) && (old_state != GS_STATE_MULTI_PAUSED) ) {
5918                                 event_music_first_pattern();    // start the first pattern
5919                         }                       
5920                         player_restore_target_and_weapon_link_prefs();
5921
5922                         Game_mode |= GM_IN_MISSION;
5923
5924 #ifndef NDEBUG
5925                         // required to truely make mouse deltas zeroed in debug mouse code
5926 void mouse_force_pos(int x, int y);
5927                         if (!Is_standalone) {
5928                                 mouse_force_pos(gr_screen.max_w / 2, gr_screen.max_h / 2);
5929                         }
5930 #endif
5931
5932                         game_flush();
5933
5934                         // only start time if in single player, or coming from multi wait state
5935                         if (
5936                                         (
5937                                                 (Game_mode & GM_NORMAL) && 
5938                                                 (old_state != GS_STATE_VIEW_CUTSCENES)
5939                                         ) || (
5940                                                 (Game_mode & GM_MULTIPLAYER) && (
5941                                                         (old_state == GS_STATE_MULTI_PAUSED) ||
5942                                                         (old_state == GS_STATE_MULTI_MISSION_SYNC)
5943                                                 )
5944                                         )
5945                                 )
5946                                         game_start_time();
5947
5948                         // when coming from the multi paused state, reset the timestamps
5949                         if ( (Game_mode & GM_MULTIPLAYER) && (old_state == GS_STATE_MULTI_PAUSED) ){
5950                                 multi_reset_timestamps();
5951                         }
5952
5953                         if ((Game_mode & GM_MULTIPLAYER) && (old_state != GS_STATE_DEATH_BLEW_UP) ) {
5954                                 // initialize all object update details
5955                                 multi_oo_gameplay_init();
5956                         }
5957         
5958                         // under certain circumstances, the server should reset the object update rate limiting stuff
5959                         if( ((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)) &&
5960                                  ((old_state == GS_STATE_MULTI_PAUSED) || (old_state == GS_STATE_MULTI_MISSION_SYNC)) ){
5961                                 
5962                                 // reinitialize the rate limiting system for all clients
5963                                 multi_oo_rate_init_all();
5964                         }
5965
5966                         // multiplayer clients should always re-initialize their control info rate limiting system                      
5967                         if((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
5968                                 multi_oo_rate_init_all();
5969                         }
5970                         
5971                         // reset ping times
5972                         if(Game_mode & GM_MULTIPLAYER){
5973                                 multi_ping_reset_players();
5974                         }
5975
5976                         Game_subspace_effect = 0;
5977                         if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
5978                                 Game_subspace_effect = 1;
5979                                 if( !(Game_mode & GM_STANDALONE_SERVER) ){      
5980                                         game_start_subspace_ambient_sound();
5981                                 }
5982                         }
5983
5984                         sound_env_set(&Game_sound_env);
5985                         joy_ff_mission_init(Ship_info[Player_ship->ship_info_index].rotation_time);
5986
5987                         // clear multiplayer button info                        i
5988                         extern button_info Multi_ship_status_bi;
5989                         memset(&Multi_ship_status_bi, 0, sizeof(button_info));
5990                         break;
5991
5992                 case GS_STATE_HUD_CONFIG:
5993                         hud_config_init();
5994                         break;
5995
5996                 case GS_STATE_MULTI_JOIN_GAME:
5997                         multi_join_clear_game_list();
5998
5999                         if (old_state != GS_STATE_OPTIONS_MENU) {
6000                                 multi_join_game_init();
6001                         }
6002
6003                         break;
6004
6005                 case GS_STATE_MULTI_HOST_SETUP:         
6006                         // don't reinitialize if we're coming back from the host options screen
6007                         if ((old_state != GS_STATE_MULTI_HOST_OPTIONS) && (old_state != GS_STATE_OPTIONS_MENU)) {
6008                                 multi_create_game_init();
6009                         }
6010
6011                         break;
6012
6013                 case GS_STATE_MULTI_CLIENT_SETUP:               
6014                         if (old_state != GS_STATE_OPTIONS_MENU) {
6015                                 multi_game_client_setup_init();
6016                         }
6017
6018                         break;
6019
6020                 case GS_STATE_CONTROL_CONFIG:
6021                         control_config_init();
6022                         break;
6023
6024                 case GS_STATE_TECH_MENU:
6025                         techroom_init();
6026                         break;
6027
6028                 case GS_STATE_BARRACKS_MENU:
6029                         if(old_state != GS_STATE_VIEW_MEDALS){
6030                                 barracks_init();
6031                         }
6032                         break;
6033
6034                 case GS_STATE_MISSION_LOG_SCROLLBACK:
6035                         hud_scrollback_init();
6036                         break;
6037
6038                 case GS_STATE_DEATH_DIED:
6039                         Player_died_time = timestamp(10);
6040
6041                         if(!(Game_mode & GM_MULTIPLAYER)){
6042                                 player_show_death_message();
6043                         }
6044                         Game_mode |= GM_DEAD_DIED;
6045                         break;
6046
6047                 case GS_STATE_DEATH_BLEW_UP:
6048                         if ( !popupdead_is_active() ) {
6049                                 Player_ai->target_objnum = -1;
6050                         }
6051
6052                         // stop any local EMP effect
6053                         emp_stop_local();
6054
6055                         Players[Player_num].flags &= ~PLAYER_FLAGS_AUTO_TARGETING;      //      Prevent immediate switch to a hostile ship.
6056                         Game_mode |= GM_DEAD_BLEW_UP;           
6057                         Show_viewing_from_self = 0;
6058
6059                         // timestamp how long we should wait before displaying the died popup
6060                         if ( !popupdead_is_active() ) {
6061                                 Player_died_popup_wait = timestamp(PLAYER_DIED_POPUP_WAIT);
6062                         }
6063                         break;
6064
6065                 case GS_STATE_GAMEPLAY_HELP:
6066                         gameplay_help_init();
6067                         break;
6068
6069                 case GS_STATE_CREDITS:
6070                         main_hall_stop_music();
6071                         main_hall_stop_ambient();
6072                         credits_init();
6073                         break;
6074
6075                 case GS_STATE_VIEW_MEDALS:
6076                         medal_main_init(Player);
6077                         break;
6078
6079                 case GS_STATE_SHOW_GOALS:
6080                         mission_show_goals_init();
6081                         break;
6082
6083                 case GS_STATE_HOTKEY_SCREEN:
6084                         mission_hotkey_init();
6085                         break;
6086
6087                 case GS_STATE_MULTI_MISSION_SYNC:
6088                         // if we're coming from the options screen, don't do any
6089                         if(old_state == GS_STATE_OPTIONS_MENU){
6090                                 break;
6091                         }
6092
6093                         switch(Multi_sync_mode){
6094                         case MULTI_SYNC_PRE_BRIEFING:
6095                                 // if moving from game forming to the team select state                                         
6096                                 multi_sync_init();                      
6097                                 break;
6098                         case MULTI_SYNC_POST_BRIEFING:
6099                                 // if moving from briefing into the mission itself                      
6100                                 multi_sync_init();
6101                         
6102                                 // tell everyone that we're now loading data
6103                                 Net_player->state = NETPLAYER_STATE_DATA_LOAD;
6104                                 send_netplayer_update_packet();
6105
6106                                 // JAS: Used to do all paging here!!!!
6107                                                                 
6108                                 Net_player->state = NETPLAYER_STATE_WAITING;                    
6109                                 send_netplayer_update_packet();                         
6110                                 Missiontime = 0;
6111                                 Game_time_compression = F1_0;
6112                                 break;
6113                         case MULTI_SYNC_INGAME:
6114                                 multi_sync_init();
6115                                 break;
6116                         }
6117                         break;          
6118    
6119                 case GS_STATE_VIEW_CUTSCENES:
6120                         cutscenes_screen_init();
6121                         break;
6122
6123                 case GS_STATE_MULTI_STD_WAIT:
6124                         multi_standalone_wait_init();
6125                         break;
6126
6127                 case GS_STATE_STANDALONE_MAIN:
6128                         // don't initialize if we're coming from one of these 2 states unless there are no 
6129                         // players left (reset situation)
6130                         if((old_state != GS_STATE_STANDALONE_POSTGAME) || multi_endgame_ending()){
6131                                 standalone_main_init();
6132                         }
6133                         break;  
6134
6135                 case GS_STATE_MULTI_PAUSED:
6136                         pause_init(1);
6137                         break;
6138                 
6139                 case GS_STATE_INGAME_PRE_JOIN:
6140                         multi_ingame_select_init();
6141                         break;
6142
6143                 case GS_STATE_STANDALONE_POSTGAME:
6144                         multi_standalone_postgame_init();
6145                         break;
6146
6147                 case GS_STATE_INITIAL_PLAYER_SELECT:
6148                         player_select_init();
6149                         break;          
6150
6151                 case GS_STATE_MULTI_START_GAME:
6152                         multi_start_game_init();
6153                         break;
6154
6155                 case GS_STATE_MULTI_HOST_OPTIONS:
6156                         multi_host_options_init();
6157                         break;          
6158
6159                 case GS_STATE_END_OF_CAMPAIGN:
6160                         mission_campaign_end_init();
6161                         break;          
6162
6163                 case GS_STATE_LOOP_BRIEF:
6164                         loop_brief_init();
6165                         break;
6166
6167                 case GS_STATE_PXO:
6168                         if (old_state != GS_STATE_PXO_HELP) {
6169                                 STUB_FUNCTION;
6170                                 // TODO: use_last_channel?
6171
6172                                 multi_pxo_init(0);
6173                         }
6174                         break;
6175
6176                 case GS_STATE_PXO_HELP:
6177                         multi_pxo_help_init();
6178                         break;
6179
6180         } // end switch
6181 }
6182
6183 // do stuff that may need to be done regardless of state
6184 void game_do_state_common(int state,int no_networking)
6185 {
6186         game_maybe_draw_mouse(flFrametime);             // determine if to draw the mouse this frame
6187         snd_do_frame();                                                         // update sound system
6188         event_music_do_frame();                                         // music needs to play across many states
6189
6190         multi_log_process();    
6191
6192         if (no_networking) {
6193                 return;
6194         }
6195
6196         // maybe do a multiplayer frame based on game mode and state type       
6197         if (Game_mode & GM_MULTIPLAYER) {
6198                 switch (state) {
6199                         case GS_STATE_OPTIONS_MENU:
6200                         case GS_STATE_GAMEPLAY_HELP:
6201                         case GS_STATE_HOTKEY_SCREEN:
6202                         case GS_STATE_HUD_CONFIG:
6203                         case GS_STATE_CONTROL_CONFIG:
6204                         case GS_STATE_MISSION_LOG_SCROLLBACK:
6205                         case GS_STATE_SHOW_GOALS:
6206                         case GS_STATE_VIEW_CUTSCENES:
6207                         case GS_STATE_EVENT_DEBUG:
6208                                 multi_maybe_do_frame();
6209                                 break;
6210                 }
6211                 
6212                 game_do_networking();
6213         }
6214 }
6215
6216 // Called once a frame.
6217 // You should never try to change the state
6218 // in here... if you think you need to, you probably really
6219 // need to post an event, not change the state.
6220 int Game_do_state_should_skip = 0;
6221 void game_do_state(int state)
6222 {
6223         // always lets the do_state_common() function determine if the state should be skipped
6224         Game_do_state_should_skip = 0;
6225         
6226         // legal to set the should skip state anywhere in this function
6227         game_do_state_common(state);    // do stuff that may need to be done regardless of state
6228
6229         if(Game_do_state_should_skip){
6230                 return;
6231         }
6232         
6233         switch (state) {
6234                 case GS_STATE_MAIN_MENU:
6235                         game_set_frametime(GS_STATE_MAIN_MENU);
6236 #if defined(PRESS_TOUR_BUILD) || defined(PD_BUILD)
6237                         mht_do();
6238 #else
6239                         main_hall_do(flFrametime);
6240 #endif
6241                         break;
6242
6243                 case GS_STATE_OPTIONS_MENU:
6244                         game_set_frametime(GS_STATE_OPTIONS_MENU);
6245                         options_menu_do_frame(flFrametime);
6246                         break;
6247
6248                 case GS_STATE_BARRACKS_MENU:
6249                         game_set_frametime(GS_STATE_BARRACKS_MENU);
6250                         barracks_do_frame(flFrametime);
6251                         break;
6252
6253                 case GS_STATE_TRAINING_MENU:
6254                         game_set_frametime(GS_STATE_TRAINING_MENU);
6255                         training_menu_do_frame(flFrametime);
6256                         break;
6257
6258                 case GS_STATE_TECH_MENU:
6259                         game_set_frametime(GS_STATE_TECH_MENU);
6260                         techroom_do_frame(flFrametime);
6261                         break;
6262
6263                 case GS_STATE_GAMEPLAY_HELP:
6264                         game_set_frametime(GS_STATE_GAMEPLAY_HELP);
6265                         gameplay_help_do_frame(flFrametime);
6266                         break;
6267
6268                 case GS_STATE_GAME_PLAY:        // do stuff that should be done during gameplay
6269                         game_do_frame();
6270                         break;
6271
6272                 case GS_STATE_GAME_PAUSED:
6273                         pause_do(0);
6274                         break;
6275
6276                 case GS_STATE_DEBUG_PAUSED:
6277                         #ifndef NDEBUG
6278                                 game_set_frametime(GS_STATE_DEBUG_PAUSED);
6279                                 pause_debug_do();
6280                         #endif
6281                         break;
6282
6283                 case GS_STATE_TRAINING_PAUSED:
6284                         game_training_pause_do();
6285                         break;
6286
6287                 case GS_STATE_LOAD_MISSION_MENU:
6288                         Int3();
6289                         break;
6290                 
6291                 case GS_STATE_BRIEFING:
6292                         game_set_frametime(GS_STATE_BRIEFING);
6293                         brief_do_frame(flFrametime);
6294                         break;
6295
6296                 case GS_STATE_DEBRIEF:
6297                         game_set_frametime(GS_STATE_DEBRIEF);
6298                         debrief_do_frame(flFrametime);
6299                         break;
6300
6301                 case GS_STATE_MULTI_DOGFIGHT_DEBRIEF:
6302                         game_set_frametime(GS_STATE_MULTI_DOGFIGHT_DEBRIEF);
6303                         multi_df_debrief_do();
6304                         break;
6305
6306                 case GS_STATE_SHIP_SELECT:
6307                         game_set_frametime(GS_STATE_SHIP_SELECT);
6308                         ship_select_do(flFrametime);
6309                         break;
6310
6311                 case GS_STATE_WEAPON_SELECT:
6312                         game_set_frametime(GS_STATE_WEAPON_SELECT);
6313                         weapon_select_do(flFrametime);
6314                         break;
6315
6316                 case GS_STATE_MISSION_LOG_SCROLLBACK:
6317                         game_set_frametime(GS_STATE_MISSION_LOG_SCROLLBACK);
6318                         hud_scrollback_do_frame(flFrametime);
6319                         break;
6320
6321                 case GS_STATE_HUD_CONFIG:
6322                         game_set_frametime(GS_STATE_HUD_CONFIG);
6323                         hud_config_do_frame(flFrametime);
6324                         break;
6325
6326                 case GS_STATE_MULTI_JOIN_GAME:
6327                         game_set_frametime(GS_STATE_MULTI_JOIN_GAME);
6328                         multi_join_game_do_frame();
6329                         break;
6330
6331                 case GS_STATE_MULTI_HOST_SETUP:
6332                         game_set_frametime(GS_STATE_MULTI_HOST_SETUP);
6333                         multi_create_game_do();
6334                         break;
6335
6336                 case GS_STATE_MULTI_CLIENT_SETUP:
6337                         game_set_frametime(GS_STATE_MULTI_CLIENT_SETUP);
6338                         multi_game_client_setup_do_frame();
6339                         break;
6340
6341                 case GS_STATE_CONTROL_CONFIG:
6342                         game_set_frametime(GS_STATE_CONTROL_CONFIG);
6343                         control_config_do_frame(flFrametime);
6344                         break;  
6345
6346                 case GS_STATE_DEATH_DIED:
6347                         game_do_frame();                        
6348                         break;
6349
6350                 case GS_STATE_DEATH_BLEW_UP:
6351                         game_do_frame();
6352                         break;
6353
6354                 case GS_STATE_SIMULATOR_ROOM:
6355                         game_set_frametime(GS_STATE_SIMULATOR_ROOM);
6356                         sim_room_do_frame(flFrametime);
6357                         break;
6358
6359                 case GS_STATE_CAMPAIGN_ROOM:
6360                         game_set_frametime(GS_STATE_CAMPAIGN_ROOM);
6361                         campaign_room_do_frame(flFrametime);
6362                         break;
6363
6364                 case GS_STATE_RED_ALERT:
6365                         game_set_frametime(GS_STATE_RED_ALERT);
6366                         red_alert_do_frame(flFrametime);
6367                         break;
6368
6369                 case GS_STATE_CMD_BRIEF:
6370                         game_set_frametime(GS_STATE_CMD_BRIEF);
6371                         cmd_brief_do_frame(flFrametime);
6372                         break;
6373
6374                 case GS_STATE_CREDITS:
6375                         game_set_frametime(GS_STATE_CREDITS);
6376                         credits_do_frame(flFrametime);
6377                         break;
6378
6379                 case GS_STATE_VIEW_MEDALS:
6380                         game_set_frametime(GS_STATE_VIEW_MEDALS);
6381                         medal_main_do();
6382                         break;
6383
6384                 case GS_STATE_SHOW_GOALS:
6385                         game_set_frametime(GS_STATE_SHOW_GOALS);
6386                         mission_show_goals_do_frame(flFrametime);
6387                         break;
6388
6389                 case GS_STATE_HOTKEY_SCREEN:
6390                         game_set_frametime(GS_STATE_HOTKEY_SCREEN);
6391                         mission_hotkey_do_frame(flFrametime);
6392                         break;  
6393    
6394                 case GS_STATE_VIEW_CUTSCENES:
6395                         game_set_frametime(GS_STATE_VIEW_CUTSCENES);
6396                         cutscenes_screen_do_frame();
6397                         break;
6398
6399                 case GS_STATE_MULTI_STD_WAIT:
6400                         game_set_frametime(GS_STATE_STANDALONE_MAIN);
6401                         multi_standalone_wait_do();
6402                         break;
6403
6404                 case GS_STATE_STANDALONE_MAIN:
6405                         game_set_frametime(GS_STATE_STANDALONE_MAIN);
6406                         standalone_main_do();
6407                         break;  
6408
6409                 case GS_STATE_MULTI_PAUSED:
6410                         game_set_frametime(GS_STATE_MULTI_PAUSED);
6411                         pause_do(1);
6412                         break;
6413
6414                 case GS_STATE_TEAM_SELECT:
6415                         game_set_frametime(GS_STATE_TEAM_SELECT);
6416                         multi_ts_do();
6417                         break;
6418
6419                 case GS_STATE_INGAME_PRE_JOIN:
6420                         game_set_frametime(GS_STATE_INGAME_PRE_JOIN);
6421                         multi_ingame_select_do();
6422                         break;
6423
6424                 case GS_STATE_EVENT_DEBUG:
6425         #ifndef NDEBUG
6426                         game_set_frametime(GS_STATE_EVENT_DEBUG);
6427                         game_show_event_debug(flFrametime);
6428         #endif
6429                         break;
6430
6431                 case GS_STATE_STANDALONE_POSTGAME:
6432                         game_set_frametime(GS_STATE_STANDALONE_POSTGAME);
6433                         multi_standalone_postgame_do();
6434                         break;
6435
6436                 case GS_STATE_INITIAL_PLAYER_SELECT:
6437                         game_set_frametime(GS_STATE_INITIAL_PLAYER_SELECT);
6438                         player_select_do();
6439                         break;
6440
6441                 case GS_STATE_MULTI_MISSION_SYNC:
6442                         game_set_frametime(GS_STATE_MULTI_MISSION_SYNC);
6443                         multi_sync_do();
6444                         break;          
6445
6446                 case GS_STATE_MULTI_START_GAME:
6447                         game_set_frametime(GS_STATE_MULTI_START_GAME);
6448                         multi_start_game_do();
6449                         break;
6450                 
6451                 case GS_STATE_MULTI_HOST_OPTIONS:
6452                         game_set_frametime(GS_STATE_MULTI_HOST_OPTIONS);
6453                         multi_host_options_do();
6454                         break;          
6455
6456                 case GS_STATE_END_OF_CAMPAIGN:
6457                         mission_campaign_end_do();
6458                         break;          
6459
6460                 case GS_STATE_END_DEMO:
6461                         game_set_frametime(GS_STATE_END_DEMO);
6462                         end_demo_campaign_do();
6463                         break;
6464
6465                 case GS_STATE_LOOP_BRIEF:
6466                         game_set_frametime(GS_STATE_LOOP_BRIEF);
6467                         loop_brief_do();
6468                         break;
6469
6470                 case GS_STATE_PXO:
6471                         game_set_frametime(GS_STATE_PXO);
6472                         multi_pxo_do();
6473                         break;
6474
6475                 case GS_STATE_PXO_HELP:
6476                         game_set_frametime(GS_STATE_PXO_HELP);
6477                         multi_pxo_help_do();
6478                         break;
6479
6480    } // end switch(gs_current_state)
6481 }
6482
6483
6484 // return 0 if there is enough RAM to run FreeSpace, otherwise return -1
6485 int game_do_ram_check(int ram_in_mbytes)
6486 {
6487         if ( ram_in_mbytes < 30 ) {
6488                 int allowed_to_run = 1;
6489                 if ( ram_in_mbytes < 25 ) {
6490                         allowed_to_run = 0;
6491                 }
6492
6493                 char tmp[1024];
6494
6495                 if ( allowed_to_run ) {
6496                         SDL_MessageBoxData mboxd;
6497                         SDL_MessageBoxButtonData mboxbuttons[2];
6498                         int msgbox_rval;
6499
6500                         // not a translated string, but it's too long and smartdrv isn't
6501                         // really a thing for any OS we now support :p
6502                 //      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);
6503                         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);
6504
6505                         mboxbuttons[0].buttonid = 0;
6506                         mboxbuttons[0].text = XSTR("Ok", 503);
6507                         mboxbuttons[0].flags = 0;
6508
6509                         mboxbuttons[1].buttonid = 1;
6510                         mboxbuttons[1].text = XSTR("Cancel", 504);
6511                         mboxbuttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
6512
6513                         mboxd.flags = SDL_MESSAGEBOX_ERROR;
6514                         mboxd.title = XSTR( "Not Enough RAM", 194);
6515                         mboxd.message = tmp;
6516                         mboxd.numbuttons = 2;
6517                         mboxd.buttons = mboxbuttons;
6518                         mboxd.window = NULL;
6519                         mboxd.colorScheme = NULL;
6520
6521                         SDL_ShowMessageBox(&mboxd, &msgbox_rval);
6522
6523                         if ( msgbox_rval == 1 ) {
6524                                 return -1;
6525                         }
6526                 } else {
6527                         // not a translated string, but it's too long and smartdrv isn't
6528                         // really a thing for any OS we now support :p
6529                 //      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);
6530                         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);
6531
6532                         SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, XSTR( "Not Enough RAM", 194), tmp, NULL);
6533
6534                         return -1;
6535                 }
6536         }
6537
6538         return 0;
6539 }
6540
6541 // Check if there is a freespace.exe in the /update directory (relative to where fs.exe is installed).
6542 // If so, copy it over and remove the update directory.
6543 void game_maybe_update_launcher(char *exe_dir)
6544 {
6545         STUB_FUNCTION;
6546 }
6547
6548 void game_spew_pof_info_sub(int model_num, polymodel *pm, int sm, CFILE *out, int *out_total, int *out_destroyed_total)
6549 {
6550         int i;
6551         int sub_total = 0;
6552         int sub_total_destroyed = 0;
6553         int total = 0;
6554         char str[255] = "";             
6555         
6556         // get the total for all his children
6557         for (i=pm->submodel[sm].first_child; i>-1; i = pm->submodel[i].next_sibling )   {
6558                 game_spew_pof_info_sub(model_num, pm, i, out, &sub_total, &sub_total_destroyed);
6559         }       
6560
6561         // find the # of faces for this _individual_ object     
6562         total = submodel_get_num_polys(model_num, sm);
6563         if(strstr(pm->submodel[sm].name, "-destroyed")){
6564                 sub_total_destroyed = total;
6565         }
6566         
6567         // write out total
6568         SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[sm].name, total);
6569         cfputs(str, out);               
6570
6571         *out_total += total + sub_total;
6572         *out_destroyed_total += sub_total_destroyed;
6573 }
6574
6575 #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);
6576 void game_spew_pof_info()
6577 {
6578         char *pof_list[1000];
6579         int num_files;  
6580         CFILE *out;
6581         int idx, model_num, i, j;
6582         polymodel *pm;
6583         int total, root_total, model_total, destroyed_total, counted;
6584         char str[255] = "";
6585
6586         // get file list
6587         num_files = cf_get_file_list(1000, pof_list, CF_TYPE_MODELS, "*.pof");
6588
6589         // spew info on all the pofs
6590         if(!num_files){
6591                 return;
6592         }
6593
6594         // go
6595         out = cfopen("pofspew.txt", "wt", CFILE_NORMAL, CF_TYPE_DATA);
6596         if(out == NULL){
6597                 BAIL();
6598         }       
6599         counted = 0;    
6600         for(idx=0; idx<num_files; idx++, counted++){
6601                 SDL_snprintf(str, SDL_arraysize(str), "%s.pof", pof_list[idx]);
6602                 model_num = model_load(str, 0, NULL);
6603                 if(model_num >= 0){
6604                         pm = model_get(model_num);
6605
6606                         // if we have a real model
6607                         if(pm != NULL){                         
6608                                 cfputs(str, out);
6609                                 cfputs("\n", out);
6610                                 
6611                                 // go through and print all raw submodels
6612                                 cfputs("RAW\n", out);
6613                                 total = 0;
6614                                 model_total = 0;                                
6615                                 for (i=0; i<pm->n_models; i++)  {                                       
6616                                         total = submodel_get_num_polys(model_num, i);                                   
6617                                         
6618                                         model_total += total;
6619                                         SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[i].name, total);
6620                                         cfputs(str, out);
6621                                 }                               
6622                                 SDL_snprintf(str, SDL_arraysize(str), "Model total %d\n", model_total);
6623                                 cfputs(str, out);                               
6624
6625                                 // now go through and do it by LOD
6626                                 cfputs("BY LOD\n\n", out);                              
6627                                 for(i=0; i<pm->n_detail_levels; i++){
6628                                         SDL_snprintf(str, SDL_arraysize(str), "LOD %d\n", i);
6629                                         cfputs(str, out);
6630
6631                                         // submodels
6632                                         root_total = submodel_get_num_polys(model_num, pm->detail[i] );
6633                                         total = 0;
6634                                         destroyed_total = 0;
6635                                         for (j=pm->submodel[pm->detail[i]].first_child; j>-1; j = pm->submodel[j].next_sibling )        {
6636                                                 game_spew_pof_info_sub(model_num, pm, j, out, &total, &destroyed_total);
6637                                         }
6638
6639                                         SDL_snprintf(str, SDL_arraysize(str), "Submodel %s total : %d faces\n", pm->submodel[pm->detail[i]].name, root_total);
6640                                         cfputs(str, out);
6641
6642                                         SDL_snprintf(str, SDL_arraysize(str), "TOTAL: %d\n", total + root_total);
6643                                         cfputs(str, out);
6644                                         SDL_snprintf(str, SDL_arraysize(str), "TOTAL not counting destroyed faces %d\n", (total + root_total) - destroyed_total);
6645                                         cfputs(str, out);
6646                                         SDL_snprintf(str, SDL_arraysize(str), "TOTAL destroyed faces %d\n\n", destroyed_total);
6647                                         cfputs(str, out);
6648                                 }                               
6649                                 cfputs("------------------------------------------------------------------------\n\n", out);                            
6650                         }
6651                 }
6652
6653                 if(counted >= MAX_POLYGON_MODELS - 5){
6654                         model_free_all();
6655                         counted = 0;
6656                 }
6657         }
6658
6659         cfclose(out);
6660         model_free_all();
6661         BAIL();
6662 }
6663
6664 DCF(pofspew, "")
6665 {
6666         game_spew_pof_info();
6667 }
6668
6669 int game_main(const char *szCmdLine)
6670 {
6671         int state;
6672
6673         // Find out how much RAM is on this machine
6674         Freespace_total_ram = SDL_GetSystemRAM();
6675
6676         if ( game_do_ram_check(Freespace_total_ram) == -1 ) {
6677                 return 0;
6678         }
6679
6680         if (!vm_init(24*1024*1024)) {
6681                 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);
6682                 return 0;
6683         }
6684
6685         char *tmp_mem = (char *) malloc(16 * 1024 * 1024);
6686         if (!tmp_mem) {
6687                 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);
6688                 return 0;
6689         }
6690
6691         free(tmp_mem);
6692         tmp_mem = NULL;
6693
6694         #ifndef NDEBUG                          
6695         {
6696                 extern void windebug_memwatch_init();
6697                 windebug_memwatch_init();
6698         }
6699         #endif
6700
6701 #ifndef NDEBUG
6702         outwnd_init(1);
6703 #endif
6704
6705         mprintf(("Platform: %s\n", SDL_GetPlatform()));
6706         mprintf(("CPU: %d %s\n", SDL_GetCPUCount(), (SDL_GetCPUCount() == 1) ? "core" : "cores"));
6707         mprintf(("Memory: %dMB\n", Freespace_total_ram));
6708         mprintf(("Build: %d-bit, %s-endian\n", sizeof(void*) * 8, (SDL_BYTEORDER == SDL_LIL_ENDIAN) ? "little" : "big"));
6709
6710         parse_cmdline(szCmdLine);       
6711
6712         mprintf(("--------------------------------------------------------------------------------\n"));
6713
6714 #ifdef STANDALONE_ONLY_BUILD
6715         Is_standalone = 1;
6716         nprintf(("Network", "Standalone running"));
6717 #else
6718         if (Is_standalone){
6719                 nprintf(("Network", "Standalone running"));
6720         }
6721 #endif
6722
6723         game_init();
6724         game_stop_time();
6725
6726         // maybe spew pof stuff
6727         if(Cmdline_spew_pof_info){
6728                 game_spew_pof_info();
6729                 game_shutdown();
6730                 return 1;
6731         }
6732
6733         // non-demo, non-standalone, play the intro movie
6734 #ifndef DEMO
6735         if ( !Is_standalone ) {
6736
6737                 // release -- movies always play
6738 #if defined(NDEBUG)
6739
6740                 // 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
6741                 movie_play( NOX("intro.mve") );
6742
6743                 // debug version, movie will only play with -showmovies
6744 #elif !defined(NDEBUG)
6745
6746                 movie_play( NOX("intro.mve") );
6747 /*
6748 #ifndef NDEBUG
6749                 if ( Cmdline_show_movies )
6750                         movie_play( NOX("intro.mve") );
6751 #endif
6752 */
6753 #endif // NDEBUG
6754         }
6755
6756 #endif // DEMO
6757
6758         if (Is_standalone){
6759                 gameseq_post_event(GS_EVENT_STANDALONE_MAIN);
6760         } else {
6761                 gameseq_post_event(GS_EVENT_GAME_INIT);         // start the game rolling -- check for default pilot, or go to the pilot select screen
6762         }
6763
6764         while (1) {
6765                 // only important for non THREADED mode
6766                 os_poll();
6767
6768                 state = gameseq_process_events();
6769                 if ( state == GS_STATE_QUIT_GAME ){
6770                         break;
6771                 }
6772         } 
6773
6774 #if defined(FS2_DEMO) || defined(FS1_DEMO)
6775         if(!Is_standalone){
6776                 demo_upsell_show_screens();
6777         }
6778 #elif defined(OEM_BUILD)
6779         // show upsell screens on exit
6780         oem_upsell_show_screens();
6781 #endif
6782
6783         game_shutdown();
6784         return 1;
6785 }
6786
6787 // launcher the fslauncher program on exit
6788 void game_launch_launcher_on_exit()
6789 {
6790         STUB_FUNCTION;
6791 }
6792
6793
6794 // game_shutdown()
6795 //
6796 // This function is called when FreeSpace terminates normally.  
6797 //
6798 void game_shutdown(void)
6799 {
6800         // don't ever flip a page on the standalone!
6801         if(!(Game_mode & GM_STANDALONE_SERVER)){
6802                 gr_reset_clip();
6803                 gr_clear();
6804                 gr_flip();
6805         }
6806
6807    // if the player has left the "player select" screen and quit the game without actually choosing
6808         // a player, Player will be NULL, in which case we shouldn't write the player file out!
6809         if (!(Game_mode & GM_STANDALONE_SERVER) && (Player!=NULL) && !Is_standalone){
6810                 write_pilot_file();
6811         }
6812
6813         // load up common multiplayer icons
6814         multi_unload_common_icons();
6815         
6816         shockwave_close();                      // release any memory used by shockwave system  
6817         fireball_close();                               // free fireball system
6818         ship_close();                                   // free any memory that was allocated for the ships
6819         weapon_close();                                 // free any memory that was allocated for the weapons
6820         hud_free_scrollback_list();// free space allocated to store hud messages in hud scrollback
6821         unload_animating_pointer();// frees the frames used for the animating mouse pointer
6822         bm_unload_all();                                // free bitmaps
6823         mission_campaign_close();       // close out the campaign stuff
6824         mission_campaign_shutdown();    // get anything that mission_campaign_close can't do
6825         multi_voice_close();                    // close down multiplayer voice (including freeing buffers, etc)
6826         multi_log_close();
6827 #ifdef MULTI_USE_LAG
6828         multi_lag_close();
6829 #endif
6830
6831         // the menu close functions will unload the bitmaps if they were displayed during the game
6832 #if !defined(PRESS_TOUR_BUILD) && !defined(PD_BUILD)
6833         main_hall_close();
6834 #endif
6835         context_help_close();           // close out help system
6836         training_menu_close();
6837         lcl_close();                            // be sure localization is closed out
6838         gr_close();
6839
6840         // free left-over memory from parsed tables
6841         cutscene_tbl_close();
6842         medal_tbl_close();
6843         scoring_tbl_close();
6844         player_tips_close();
6845
6846         extern void joy_close();
6847         joy_close();
6848
6849         audiostream_close();
6850         snd_close();
6851         event_music_close();
6852         psnet_close();
6853         os_cleanup();
6854
6855         // HACKITY HACK HACK
6856         // if this flag is set, we should be firing up the launcher when exiting freespace
6857         extern int Multi_update_fireup_launcher_on_exit;
6858         if(Multi_update_fireup_launcher_on_exit){
6859                 game_launch_launcher_on_exit();
6860         }
6861 }
6862
6863 // game_stop_looped_sounds()
6864 //
6865 // This function will call the appropriate stop looped sound functions for those
6866 // modules which use looping sounds.  It is not enough just to stop a looping sound
6867 // at the DirectSound level, the game is keeping track of looping sounds, and this
6868 // function is used to inform the game that looping sounds are being halted.
6869 //
6870 void game_stop_looped_sounds()
6871 {
6872         hud_stop_looped_locking_sounds();
6873         hud_stop_looped_engine_sounds();
6874         afterburner_stop_sounds();
6875         player_stop_looped_sounds();
6876         obj_snd_stop_all();             // stop all object-linked persistant sounds
6877         game_stop_subspace_ambient_sound();
6878         snd_stop(Radar_static_looping);
6879         Radar_static_looping = -1;
6880         snd_stop(Target_static_looping);
6881         shipfx_stop_engine_wash_sound();
6882         Target_static_looping = -1;
6883 }
6884
6885 //////////////////////////////////////////////////////////////////////////
6886 //
6887 // Code for supporting an animating mouse pointer
6888 //
6889 //
6890 //////////////////////////////////////////////////////////////////////////
6891
6892 typedef struct animating_obj
6893 {
6894         int     first_frame;
6895         int     num_frames;
6896         int     current_frame;
6897         float time;
6898         float elapsed_time;
6899 } animating_obj;
6900
6901 static animating_obj Animating_mouse;
6902
6903 // ----------------------------------------------------------------------------
6904 // init_animating_pointer()
6905 //
6906 // Called by load_animating_pointer() to ensure the Animating_mouse struct
6907 // gets properly initialized
6908 //
6909 void init_animating_pointer()
6910 {
6911         Animating_mouse.first_frame     = -1;
6912         Animating_mouse.num_frames              = 0;
6913         Animating_mouse.current_frame   = -1;
6914         Animating_mouse.time                            = 0.0f;
6915         Animating_mouse.elapsed_time    = 0.0f;
6916 }
6917
6918 // ----------------------------------------------------------------------------
6919 // load_animating_pointer()
6920 //
6921 // Called at game init to load in the frames for the animating mouse pointer
6922 //
6923 // input:       filename        =>      filename of animation file that holds the animation
6924 // 
6925 void load_animating_pointer(const char *filename, int dx, int dy)
6926 {
6927         int                             fps;
6928         animating_obj *am;
6929
6930         init_animating_pointer();
6931
6932         am = &Animating_mouse;
6933         am->first_frame = bm_load_animation(filename, &am->num_frames, &fps);
6934         if ( am->first_frame == -1 ) 
6935                 Error(LOCATION, "Could not load animation %s for the mouse pointer\n", filename);
6936         am->current_frame = 0;
6937         am->time = am->num_frames / i2fl(fps);
6938 }
6939
6940 // ----------------------------------------------------------------------------
6941 // unload_animating_pointer()
6942 //
6943 // Called at game shutdown to free the memory used to store the animation frames
6944 //
6945 void unload_animating_pointer()
6946 {
6947         int                             i;
6948         animating_obj   *am;
6949
6950         am = &Animating_mouse;
6951         for ( i = 0; i < am->num_frames; i++ ) {
6952                 SDL_assert( (am->first_frame+i) >= 0 );
6953                 bm_release(am->first_frame + i);
6954         }
6955
6956         am->first_frame = -1;
6957         am->num_frames          = 0;
6958         am->current_frame = -1;
6959 }
6960
6961 // draw the correct frame of the game mouse... called from game_maybe_draw_mouse()
6962 void game_render_mouse(float frametime)
6963 {
6964         int                             mx, my;
6965         animating_obj   *am;
6966
6967         // if animating cursor exists, play the next frame
6968         am = &Animating_mouse;
6969         if ( am->first_frame != -1 ) {
6970                 mouse_get_pos(&mx, &my);
6971                 am->elapsed_time += frametime;
6972                 am->current_frame = fl2i( ( am->elapsed_time / am->time ) * (am->num_frames-1) );
6973                 if ( am->current_frame >= am->num_frames ) {
6974                         am->current_frame = 0;
6975                         am->elapsed_time = 0.0f;
6976                 }
6977                 gr_set_cursor_bitmap(am->first_frame + am->current_frame);
6978         }
6979 }
6980
6981 // ----------------------------------------------------------------------------
6982 // game_maybe_draw_mouse()
6983 //
6984 // determines whether to draw the mouse pointer at all, and what frame of
6985 // animation to use if the mouse is animating
6986 //
6987 // Sets mouse.cpp globals Mouse_hidden and Mouse_moved based on the state of the game.
6988 //
6989 // input:       frametime => elapsed frame time in seconds since last call
6990 //
6991 void game_maybe_draw_mouse(float frametime)
6992 {
6993         int game_state;
6994
6995         game_state = gameseq_get_state();
6996
6997         switch ( game_state ) {
6998                 case GS_STATE_GAME_PAUSED:
6999                 // case GS_STATE_MULTI_PAUSED:
7000                 case GS_STATE_GAME_PLAY:
7001                 case GS_STATE_DEATH_DIED:
7002                 case GS_STATE_DEATH_BLEW_UP:
7003                         if ( popup_active() || popupdead_is_active() ) {
7004                                 Mouse_hidden = 0;
7005                         } else {
7006                                 Mouse_hidden = 1;       
7007                         }
7008                         break;
7009
7010                 default:
7011                         Mouse_hidden = 0;
7012                         break;
7013         }       // end switch
7014
7015         if ( !Mouse_hidden ) 
7016                 game_render_mouse(frametime);
7017
7018 }
7019
7020 void game_do_training_checks()
7021 {
7022         int i, s;
7023         float d;
7024         waypoint_list *wplp;
7025
7026         if (Training_context & TRAINING_CONTEXT_SPEED) {
7027                 s = (int) Player_obj->phys_info.fspeed;
7028                 if ((s >= Training_context_speed_min) && (s <= Training_context_speed_max)) {
7029                         if (!Training_context_speed_set) {
7030                                 Training_context_speed_set = 1;
7031                                 Training_context_speed_timestamp = timestamp();
7032                         }
7033
7034                 } else
7035                         Training_context_speed_set = 0;
7036         }
7037
7038         if (Training_context & TRAINING_CONTEXT_FLY_PATH) {
7039                 wplp = &Waypoint_lists[Training_context_path];
7040                 if (wplp->count > Training_context_goal_waypoint) {
7041                         i = Training_context_goal_waypoint;
7042                         do {
7043                                 d = vm_vec_dist(&wplp->waypoints[i], &Player_obj->pos);
7044                                 if (d <= Training_context_distance) {
7045                                         Training_context_at_waypoint = i;
7046                                         if (Training_context_goal_waypoint == i) {
7047                                                 Training_context_goal_waypoint++;
7048                                                 snd_play(&Snds[SND_CARGO_REVEAL], 0.0f);
7049                                         }
7050
7051                                         break;
7052                                 }
7053
7054                                 i++;
7055                                 if (i == wplp->count)
7056                                         i = 0;
7057
7058                         } while (i != Training_context_goal_waypoint);
7059                 }
7060         }
7061
7062         if ((Players_target == UNINITIALIZED) || (Player_ai->target_objnum != Players_target) || (Player_ai->targeted_subsys != Players_targeted_subsys)) {
7063                 Players_target = Player_ai->target_objnum;
7064                 Players_targeted_subsys = Player_ai->targeted_subsys;
7065                 Players_target_timestamp = timestamp();
7066         }
7067 }
7068
7069 /////////// Following is for event debug view screen
7070
7071 #ifndef NDEBUG
7072
7073 #define EVENT_DEBUG_MAX 5000
7074 #define EVENT_DEBUG_EVENT 0x8000
7075
7076 int Event_debug_index[EVENT_DEBUG_MAX];
7077 int ED_count;
7078
7079 void game_add_event_debug_index(int n, int indent)
7080 {
7081         if (ED_count < EVENT_DEBUG_MAX)
7082                 Event_debug_index[ED_count++] = n | (indent << 16);
7083 }
7084
7085 void game_add_event_debug_sexp(int n, int indent)
7086 {
7087         if (n < 0)
7088                 return;
7089
7090         if (Sexp_nodes[n].first >= 0) {
7091                 game_add_event_debug_sexp(Sexp_nodes[n].first, indent);
7092                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7093                 return;
7094         }
7095
7096         game_add_event_debug_index(n, indent);
7097         if (Sexp_nodes[n].subtype == SEXP_ATOM_OPERATOR)
7098                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent + 1);
7099         else
7100                 game_add_event_debug_sexp(Sexp_nodes[n].rest, indent);
7101 }
7102
7103 void game_event_debug_init()
7104 {
7105         int e;
7106
7107         ED_count = 0;
7108         for (e=0; e<Num_mission_events; e++) {
7109                 game_add_event_debug_index(e | EVENT_DEBUG_EVENT, 0);
7110                 game_add_event_debug_sexp(Mission_events[e].formula, 1);
7111         }
7112 }
7113
7114 void game_show_event_debug(float frametime) 
7115 {
7116         char buf[256];
7117         int i, k, z;
7118         int font_height, font_width;    
7119         int y_index, y_max;
7120         static int scroll_offset = 0;
7121         
7122         k = game_check_key();
7123         if (k)
7124                 switch (k) {
7125                         case SDLK_UP:
7126                         case SDLK_KP_8:
7127                                 scroll_offset--;
7128                                 if (scroll_offset < 0)
7129                                         scroll_offset = 0;
7130                                 break;
7131
7132                         case SDLK_DOWN:
7133                         case SDLK_KP_2:
7134                                 scroll_offset++;
7135                                 break;
7136
7137                         case SDLK_PAGEUP:
7138                                 scroll_offset -= 20;
7139                                 if (scroll_offset < 0)
7140                                         scroll_offset = 0;
7141                                 break;
7142
7143                         case SDLK_PAGEDOWN:
7144                                 scroll_offset += 20;    // not font-independent, hard-coded since I counted the lines!
7145                                 break;
7146
7147                         default:
7148                                 gameseq_post_event(GS_EVENT_PREVIOUS_STATE);
7149                                 key_flush();
7150                                 break;
7151                 } // end switch
7152
7153         gr_clear();
7154         gr_set_color_fast(&Color_bright);
7155         gr_set_font(FONT1);
7156         gr_printf(0x8000, 5, NOX("EVENT DEBUG VIEW"));
7157
7158         gr_set_color_fast(&Color_normal);
7159         gr_set_font(FONT1);
7160         gr_get_string_size(&font_width, &font_height, NOX("test"));
7161         y_max = gr_screen.max_h - font_height - 5;
7162         y_index = 45;
7163
7164         k = scroll_offset;
7165         while (k < ED_count) {
7166                 if (y_index > y_max)
7167                         break;
7168
7169                 z = Event_debug_index[k];
7170                 if (z & EVENT_DEBUG_EVENT) {
7171                         z &= 0x7fff;
7172                         SDL_snprintf(buf, SDL_arraysize(buf), NOX("%s%s (%s) %s%d %d"), (Mission_events[z].flags & MEF_CURRENT) ? NOX("* ") : "",
7173                                 Mission_events[z].name, Mission_events[z].result ? NOX("True") : NOX("False"),
7174                                 (Mission_events[z].chain_delay < 0) ? "" : NOX("x "),
7175                                 Mission_events[z].repeat_count, Mission_events[z].interval);
7176
7177                 } else {
7178                         i = (z >> 16) * 3;
7179                         buf[i] = 0;
7180                         while (i--)
7181                                 buf[i] = ' ';
7182
7183                         SDL_strlcat(buf, Sexp_nodes[z & 0x7fff].text, SDL_arraysize(buf));
7184                         switch (Sexp_nodes[z & 0x7fff].value) {
7185                                 case SEXP_TRUE:
7186                                         SDL_strlcat(buf, NOX(" (True)"), SDL_arraysize(buf));
7187                                         break;
7188
7189                                 case SEXP_FALSE:
7190                                         SDL_strlcat(buf, NOX(" (False)"), SDL_arraysize(buf));
7191                                         break;
7192
7193                                 case SEXP_KNOWN_TRUE:
7194                                         SDL_strlcat(buf, NOX(" (Always true)"), SDL_arraysize(buf));
7195                                         break;
7196
7197                                 case SEXP_KNOWN_FALSE:
7198                                         SDL_strlcat(buf, NOX(" (Always false)"), SDL_arraysize(buf));
7199                                         break;
7200
7201                                 case SEXP_CANT_EVAL:
7202                                         SDL_strlcat(buf, NOX(" (Can't eval)"), SDL_arraysize(buf));
7203                                         break;
7204
7205                                 case SEXP_NAN:
7206                                 case SEXP_NAN_FOREVER:
7207                                         SDL_strlcat(buf, NOX(" (Not a number)"), SDL_arraysize(buf));
7208                                         break;
7209                         }
7210                 }
7211
7212                 gr_printf(10, y_index, buf);
7213                 y_index += font_height;
7214                 k++;
7215         }
7216
7217         gr_flip();
7218 }
7219
7220 #endif // NDEBUG
7221
7222 #ifndef NDEBUG
7223 FILE * Time_fp;
7224 FILE * Texture_fp;
7225
7226 int Tmap_num_too_big = 0;
7227 int Num_models_needing_splitting = 0;
7228
7229 void Time_model( int modelnum )
7230 {
7231 //      mprintf(( "Timing ship '%s'\n", si->name ));
7232
7233         vector eye_pos, model_pos;
7234         matrix eye_orient, model_orient;
7235
7236         polymodel *pm = model_get( modelnum );
7237
7238         int l = strlen(pm->filename);
7239         while( (l>0) )  {
7240                 if ( (l == '/') || (l=='\\') || (l==':'))       {
7241                         l++;
7242                         break;
7243                 }
7244                 l--;
7245         }
7246         char *pof_file = &pm->filename[l];
7247
7248         int model_needs_splitting = 0;
7249
7250         //fprintf( Texture_fp, "Model: %s\n", pof_file );
7251         int i;
7252         for (i=0; i<pm->n_textures; i++ )       {
7253                 char filename[1024];
7254                 ubyte pal[768];
7255
7256                 int bmp_num = pm->original_textures[i];
7257                 if ( bmp_num > -1 )     {
7258                         bm_get_palette(pm->original_textures[i], pal, filename, SDL_arraysize(filename) );
7259                         int w,h;
7260                         bm_get_info( pm->original_textures[i],&w, &h );
7261
7262
7263                         if ( (w > 512) || (h > 512) )   {
7264                                 fprintf( Texture_fp, "%s\t%s\t%d\t%d\n", pof_file, filename, w, h );
7265                                 Tmap_num_too_big++;
7266                                 model_needs_splitting++;
7267                         }
7268                 } else {
7269                         //fprintf( Texture_fp, "\tTexture %d is bogus\n", i );
7270                 }
7271         }
7272
7273         if ( model_needs_splitting )    {
7274                 Num_models_needing_splitting++;
7275         }
7276         eye_orient = model_orient = vmd_identity_matrix;
7277         eye_pos = model_pos = vmd_zero_vector;
7278
7279         eye_pos.xyz.z = -pm->rad*2.0f;
7280
7281         vector eye_to_model;
7282
7283         vm_vec_sub( &eye_to_model, &model_pos, &eye_pos );
7284         vm_vector_2_matrix( &eye_orient, &eye_to_model, NULL, NULL );
7285
7286         fix t1 = timer_get_fixed_seconds();
7287
7288         angles ta;
7289         ta.p = ta.b = ta.h = 0.0f; 
7290         int framecount = 0;
7291
7292         int bitmaps_used_this_frame, bitmaps_new_this_frame;
7293                 
7294         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7295
7296         modelstats_num_polys = modelstats_num_verts = 0;
7297
7298         while( ta.h < PI2 )     {
7299
7300                 matrix m1;
7301                 vm_angles_2_matrix(&m1, &ta );
7302                 vm_matrix_x_matrix( &model_orient, &vmd_identity_matrix, &m1 );
7303
7304                 gr_reset_clip();
7305 //              gr_clear();
7306
7307                 g3_start_frame(1);
7308
7309                 g3_set_view_matrix( &eye_pos, &eye_orient, Viewer_zoom );       
7310
7311                 model_clear_instance( modelnum );
7312                 model_set_detail_level(0);              // use highest detail level
7313                 model_render( modelnum, &model_orient, &model_pos, MR_LOCK_DETAIL);     //|MR_NO_POLYS );
7314
7315                 g3_end_frame();
7316 //              gr_flip();
7317
7318                 framecount++;
7319                 ta.h += 0.1f;
7320
7321                 int k = key_inkey();
7322                 if ( k == SDLK_ESCAPE ) {
7323                         exit(1);
7324                 }
7325         }
7326
7327         fix t2 = timer_get_fixed_seconds();
7328
7329         if (framecount < 1) {
7330                 return;
7331         }
7332
7333         bm_get_frame_usage(&bitmaps_used_this_frame,&bitmaps_new_this_frame);
7334         //bitmaps_used_this_frame /= framecount;
7335
7336         modelstats_num_polys /= framecount;
7337         modelstats_num_verts /= framecount;
7338
7339         mprintf(( "'%s' is %.2f FPS\n", pof_file, i2fl(framecount)/f2fl(t2-t1) ));
7340         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 );
7341
7342 //      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 );
7343
7344                 
7345 //      key_getch();
7346 }
7347
7348 int Time_models = 0;
7349 DCF_BOOL( time_models, Time_models );
7350
7351 void Do_model_timings_test()
7352 {
7353         
7354
7355         if ( !Time_models ) return;
7356
7357         mprintf(( "Timing models!\n" ));
7358
7359         int i;
7360
7361         ubyte model_used[MAX_POLYGON_MODELS];
7362         int model_id[MAX_POLYGON_MODELS];
7363         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7364                 model_used[i] = 0;
7365         }
7366         
7367         // Load them all
7368         for (i=0; i<Num_ship_types; i++ )       {
7369                 Ship_info[i].modelnum = model_load( Ship_info[i].pof_file, 0, NULL );
7370
7371                 model_used[Ship_info[i].modelnum%MAX_POLYGON_MODELS]++;
7372                 model_id[Ship_info[i].modelnum%MAX_POLYGON_MODELS] = Ship_info[i].modelnum;
7373         }
7374
7375         Texture_fp = fopen( NOX("ShipTextures.txt"), "wt" );
7376         if ( !Texture_fp ) return;
7377
7378         Time_fp = fopen( NOX("ShipTimings.txt"), "wt" );
7379         if ( !Time_fp ) return;
7380
7381         fprintf( Time_fp, "Name\tFPS\tTRAM\tPolys\tVerts\tPixels\n" );
7382 //      fprintf( Time_fp, "FPS\tTRAM\tPolys\tVerts\tPixels\n" );
7383         
7384         for (i=0; i<MAX_POLYGON_MODELS; i++ )   {
7385                 if ( model_used[i] )    {
7386                         Time_model( model_id[i] );
7387                 }
7388         }
7389         
7390         fprintf( Texture_fp, "Number too big: %d\n", Tmap_num_too_big );
7391         fprintf( Texture_fp, "Number of models needing splitting: %d\n", Num_models_needing_splitting );
7392         
7393         fclose(Time_fp);
7394         fclose(Texture_fp);
7395
7396         exit(1);
7397 }
7398 #endif
7399
7400 // Call this function when you want to inform the player that a feature is not
7401 // enabled in the DEMO version of FreSpace
7402 void game_feature_not_in_demo_popup()
7403 {
7404         popup(PF_USE_AFFIRMATIVE_ICON|PF_BODY_BIG, 1, POPUP_OK, XSTR( "Sorry, this feature is available only in the retail version", 200));
7405 }
7406
7407 // format the specified time (fixed point) into a nice string
7408 void game_format_time(fix m_time, char *time_str, const int time_str_len)
7409 {
7410         float mtime;
7411         int hours,minutes,seconds;
7412
7413         mtime = f2fl(m_time);           
7414
7415         // get the hours, minutes and seconds   
7416         hours = (int)(mtime / 3600.0f);
7417         if(hours > 0){
7418                 mtime -= (3600.0f * (float)hours);
7419         }
7420         seconds = (int)mtime%60;
7421         minutes = (int)mtime/60;                        
7422
7423         if (hours > 0) {
7424                 SDL_snprintf(time_str, time_str_len, "%d:%02d:%02d", hours, minutes, seconds);
7425         } else {
7426                 SDL_snprintf(time_str, time_str_len, "%d:%02d", minutes, seconds);
7427         }
7428 }
7429
7430 //      Stuff version string in *str.
7431 void get_version_string(char *str, const int str_len)
7432 {
7433 //XSTR:OFF
7434         if ( FS_VERSION_BUILD == 0 ) {
7435                 SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7436         } else {
7437                 SDL_snprintf(str, str_len, "v%d.%02d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD );
7438         }
7439
7440 #if defined (FS2_DEMO) || defined(FS1_DEMO)
7441         SDL_strlcat(str, " D", str_len);
7442 #elif defined (OEM_BUILD)
7443         SDL_strlcat(str, " (OEM)", str_len);
7444 #endif
7445 //XSTR:ON
7446         /*
7447         HMODULE hMod;
7448         DWORD bogus_handle;
7449         char myname[_MAX_PATH];
7450         int namelen, major, minor, build, waste;
7451         unsigned int buf_size;
7452         DWORD version_size;
7453         char *infop;
7454         VOID *bufp;
7455         BOOL result;
7456
7457         // Find my EXE file name
7458         hMod = GetModuleHandle(NULL);
7459         namelen = GetModuleFileName( hMod, myname, _MAX_PATH );
7460
7461         version_size = GetFileVersionInfoSize(myname, &bogus_handle );
7462         infop = (char *)malloc(version_size);
7463         result = GetFileVersionInfo( myname, 0, version_size, (LPVOID)infop );
7464
7465         // get the product version
7466         result = VerQueryValue((LPVOID)infop, TEXT("\\StringFileInfo\\040904b0\\ProductVersion"), &bufp, &buf_size );
7467         sscanf( (char *)bufp, "%d, %d, %d, %d", &major, &minor, &build, &waste );
7468 #ifdef DEMO
7469         sprintf(str,"Dv%d.%02d",major, minor);
7470 #else
7471         sprintf(str,"v%d.%02d",major, minor);
7472 #endif
7473         */
7474 }
7475
7476 void get_version_string_short(char *str, const int str_len)
7477 {
7478         SDL_snprintf(str, str_len, "v%d.%02d", FS_VERSION_MAJOR, FS_VERSION_MINOR);
7479 }
7480
7481 // ----------------------------------------------------------------
7482 //
7483 // OEM UPSELL SCREENS BEGIN
7484 //
7485 // ----------------------------------------------------------------
7486 #if defined(OEM_BUILD)
7487
7488 #define NUM_OEM_UPSELL_SCREENS                          3
7489 #define OEM_UPSELL_SCREEN_DELAY                         10000
7490
7491 static int Oem_upsell_bitmaps_loaded = 0;
7492 static int Oem_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS];
7493 static int Oem_upsell_screen_number = 0;
7494 static int Oem_upsell_show_next_bitmap_time;
7495
7496 //XSTR:OFF
7497 static char *Oem_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_OEM_UPSELL_SCREENS] = 
7498 {
7499         {       "OEMUpSell02",
7500                 "OEMUpSell01",
7501                 "OEMUpSell03",
7502         },
7503         {       "2_OEMUpSell02",
7504                 "2_OEMUpSell01",
7505                 "2_OEMUpSell03",
7506         },
7507 };
7508 //XSTR:ON
7509
7510 static int Oem_normal_cursor = -1;
7511 static int Oem_web_cursor = -1;
7512 //#define OEM_UPSELL_URL                "http://www.interplay-store.com/"
7513 #define OEM_UPSELL_URL          "http://www.interplay.com/cgi-bin/oemlinks.pl/pid=483421&cid=18384"
7514
7515 void oem_upsell_next_screen()
7516 {
7517         Oem_upsell_screen_number++;
7518         if ( Oem_upsell_screen_number == (NUM_OEM_UPSELL_SCREENS-1) ) {
7519                 // extra long delay, mouse shown on last upsell
7520                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY*2;
7521                 Mouse_hidden = 0;
7522
7523         } else {
7524                 Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7525         }
7526 }
7527
7528 void oem_upsell_load_bitmaps()
7529 {
7530         int i;
7531
7532         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7533                 Oem_upsell_bitmaps[gr_screen.res][i] = bm_load(Oem_upsell_bitmap_filenames[gr_screen.res][i]);
7534         }
7535 }
7536
7537 void oem_upsell_unload_bitmaps()
7538 {
7539         int i;
7540
7541         for ( i = 0; i < NUM_OEM_UPSELL_SCREENS; i++ ) {
7542                 if(Oem_upsell_bitmaps[gr_screen.res][i] >= 0){
7543                         bm_unload(Oem_upsell_bitmaps[gr_screen.res][i]);
7544                 }
7545         }
7546
7547         // unloaded
7548         Oem_upsell_bitmaps_loaded = 0;
7549 }
7550
7551 // clickable hotspot on 3rd OEM upsell screen
7552 static int Oem_upsell3_button_coords[GR_NUM_RESOLUTIONS][4] = {
7553         {       // GR_640
7554                 28, 350, 287, 96                                        // x, y, w, h
7555         },
7556         {       // GR_1024
7557                 45, 561, 460, 152                                       // x, y, w, h
7558         }
7559 };
7560
7561 void oem_upsell_show_screens()
7562 {
7563         int current_time, k;
7564         int done = 0;
7565
7566         if ( !Oem_upsell_bitmaps_loaded ) {
7567                 oem_upsell_load_bitmaps();
7568                 Oem_upsell_bitmaps_loaded = 1;
7569         }
7570
7571         // may use upsell screens more than once
7572         Oem_upsell_show_next_bitmap_time = timer_get_milliseconds() + OEM_UPSELL_SCREEN_DELAY;
7573         Oem_upsell_screen_number = 0;
7574         
7575         key_flush();
7576         Mouse_hidden = 1;
7577
7578         // set up cursors
7579         int nframes;                                            // used to pass, not really needed (should be 1)
7580         Oem_normal_cursor = gr_get_cursor_bitmap();
7581         Oem_web_cursor = bm_load_animation("cursorweb", &nframes);
7582         SDL_assert(Oem_web_cursor >= 0);
7583         if (Oem_web_cursor < 0) {
7584                 Oem_web_cursor = Oem_normal_cursor;
7585         }
7586
7587         while(!done) {
7588
7589                 //oem_reset_trailer_timer();
7590
7591                 current_time = timer_get_milliseconds();
7592
7593                 os_poll();
7594                 k = key_inkey();
7595
7596                 // advance screen on keypress or timeout
7597                 if (( k > 0 ) || (mouse_up_count(MOUSE_LEFT_BUTTON) > 0) || (current_time > Oem_upsell_show_next_bitmap_time)) {
7598                         oem_upsell_next_screen();
7599                 }
7600
7601                 // check if we are done
7602                 if ( Oem_upsell_screen_number >= NUM_OEM_UPSELL_SCREENS ) {
7603                         Oem_upsell_screen_number--;
7604                         done = 1;
7605                 } else {
7606                         if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] < 0 ) {
7607                                 done = 1;
7608                         }
7609                 }
7610
7611                 // show me the upsell
7612                 if ( Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number] >= 0 ) {               
7613                         gr_set_bitmap(Oem_upsell_bitmaps[gr_screen.res][Oem_upsell_screen_number]);
7614                         gr_bitmap(0,0);
7615                 }
7616
7617                 // if this is the 3rd upsell, make it clickable, d00d
7618                 if ( Oem_upsell_screen_number == NUM_OEM_UPSELL_SCREENS-1 ) {
7619                         int mx, my;
7620                         int button_state = mouse_get_pos(&mx, &my);
7621                         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])
7622                                 && (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]) )
7623                         {
7624                                 // switch cursors
7625                                 gr_set_cursor_bitmap(Oem_web_cursor); //, GR_CURSOR_LOCK);
7626
7627                                 // check for clicks
7628                                 if (button_state & MOUSE_LEFT_BUTTON) {
7629                                         // launch URL
7630                                         multi_pxo_url(OEM_UPSELL_URL);
7631                                         done = 1;
7632                                 } 
7633                         } else {
7634                                 // switch cursor back to normal one
7635                                 gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7636                         }
7637                 }
7638
7639                 if ( done ) {
7640                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
7641                                 gr_fade_out(0);
7642                                 SDL_Delay(300);
7643                         }
7644                 }
7645
7646                 gr_flip();
7647         }
7648
7649         // unload bitmap
7650         oem_upsell_unload_bitmaps();
7651
7652         // switch cursor back to normal one
7653         gr_set_cursor_bitmap(Oem_normal_cursor); //, GR_CURSOR_UNLOCK);
7654
7655 }
7656
7657 #endif // defined(OEM_BUILD)
7658 // ----------------------------------------------------------------
7659 //
7660 // OEM UPSELL SCREENS END
7661 //
7662 // ----------------------------------------------------------------
7663
7664
7665
7666 // ----------------------------------------------------------------
7667 //
7668 // DEMO UPSELL SCREENS BEGIN
7669 //
7670 // ----------------------------------------------------------------
7671
7672 #if defined(FS2_DEMO) || defined(FS1_DEMO)
7673
7674 #ifdef FS2_DEMO
7675 #define NUM_DEMO_UPSELL_SCREENS                         2
7676 #elif FS1_DEMO
7677 #define NUM_DEMO_UPSELL_SCREENS                         4
7678 #endif
7679 #define DEMO_UPSELL_SCREEN_DELAY                                3000
7680
7681 static int Demo_upsell_bitmaps_loaded = 0;
7682 static int Demo_upsell_bitmaps[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS];
7683 static int Demo_upsell_screen_number = 0;
7684 static int Demo_upsell_show_next_bitmap_time;
7685
7686 //XSTR:OFF
7687 static char *Demo_upsell_bitmap_filenames[GR_NUM_RESOLUTIONS][NUM_DEMO_UPSELL_SCREENS] = 
7688 {
7689 #ifdef FS1_DEMO
7690         {       "DemoUpsell1",
7691                 "DemoUpsell2",
7692                 "DemoUpsell3",
7693                 "DemoUpsell4"
7694         },
7695         {       "DemoUpsell1",
7696                 "DemoUpsell2",
7697                 "DemoUpsell3",
7698                 "DemoUpsell4"
7699         },
7700 #else
7701         {       "UpSell02",
7702                 "UpSell01",
7703         },
7704         {       "2_UpSell02",
7705                 "2_UpSell01",
7706         },
7707 #endif
7708         // "DemoUpsell3",
7709         // "DemoUpsell4",
7710 };
7711 //XSTR:ON
7712
7713 void demo_upsell_next_screen()
7714 {
7715         Demo_upsell_screen_number++;
7716         if ( Demo_upsell_screen_number == (NUM_DEMO_UPSELL_SCREENS-1) ) {
7717                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY*4;
7718         } else {
7719                 Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7720         }
7721 }
7722
7723 void demo_upsell_load_bitmaps()
7724 {
7725         int i;
7726
7727         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7728                 Demo_upsell_bitmaps[gr_screen.res][i] = bm_load(Demo_upsell_bitmap_filenames[gr_screen.res][i]);
7729         }
7730 }
7731
7732 void demo_upsell_unload_bitmaps()
7733 {
7734         int i;
7735
7736         for ( i = 0; i < NUM_DEMO_UPSELL_SCREENS; i++ ) {
7737                 if(Demo_upsell_bitmaps[gr_screen.res][i] >= 0){
7738                         bm_unload(Demo_upsell_bitmaps[gr_screen.res][i]);
7739                 }
7740         }
7741
7742         // unloaded
7743         Demo_upsell_bitmaps_loaded = 0;
7744 }
7745
7746 void demo_upsell_show_screens()
7747 {
7748         int current_time, k;
7749         int done = 0;
7750
7751         if ( !Demo_upsell_bitmaps_loaded ) {
7752                 demo_upsell_load_bitmaps();
7753                 Demo_upsell_bitmaps_loaded = 1;
7754         }
7755
7756         // may use upsell screens more than once
7757         Demo_upsell_show_next_bitmap_time = timer_get_milliseconds() + DEMO_UPSELL_SCREEN_DELAY;
7758         Demo_upsell_screen_number = 0;
7759         
7760         key_flush();
7761         Mouse_hidden = 1;
7762
7763         while(!done) {
7764
7765                 demo_reset_trailer_timer();
7766
7767                 current_time = timer_get_milliseconds();
7768
7769 // #ifndef THREADED
7770                 os_poll();
7771 // #endif
7772                 k = key_inkey();
7773
7774                 // don't time out, wait for keypress
7775                 /*
7776                 if ( current_time > Demo_upsell_show_next_bitmap_time ) {
7777                         demo_upsell_next_screen();
7778                         k = 0;
7779                 }*/
7780
7781                 if ( k > 0 ) {
7782                         demo_upsell_next_screen();
7783                 }
7784
7785                 if ( Demo_upsell_screen_number >= NUM_DEMO_UPSELL_SCREENS ) {
7786                         Demo_upsell_screen_number--;
7787                         done = 1;
7788                 } else {
7789                         if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] < 0 ) {
7790                                 done = 1;
7791                         }
7792                 }
7793
7794                 if ( Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number] >= 0 ) {             
7795                         gr_set_bitmap(Demo_upsell_bitmaps[gr_screen.res][Demo_upsell_screen_number]);
7796                         gr_bitmap(0,0);
7797                 }
7798
7799                 if ( done ) {
7800                         if (gameseq_get_state() != GS_STATE_END_DEMO) {
7801                                 gr_fade_out(0);
7802                                 SDL_Delay(300);
7803                         }
7804                 }
7805
7806                 gr_flip();
7807         }
7808
7809         // unload bitmap
7810         demo_upsell_unload_bitmaps();
7811 }
7812
7813 #endif // DEMO
7814
7815 // ----------------------------------------------------------------
7816 //
7817 // DEMO UPSELL SCREENS END
7818 //
7819 // ----------------------------------------------------------------
7820
7821
7822 // ----------------------------------------------------------------
7823 //
7824 // Subspace Ambient Sound START
7825 //
7826 // ----------------------------------------------------------------
7827
7828 static int Subspace_ambient_left_channel = -1;
7829 static int Subspace_ambient_right_channel = -1;
7830
7831 // 
7832 void game_start_subspace_ambient_sound()
7833 {
7834         if ( Subspace_ambient_left_channel < 0 ) {
7835                 Subspace_ambient_left_channel = snd_play_looping(&Snds[SND_SUBSPACE_LEFT_CHANNEL], -1.0f);
7836         }
7837
7838         if ( Subspace_ambient_right_channel < 0 ) {
7839                 Subspace_ambient_right_channel = snd_play_looping(&Snds[SND_SUBSPACE_RIGHT_CHANNEL], 1.0f);
7840         }
7841 }
7842
7843 void game_stop_subspace_ambient_sound()
7844 {
7845         if ( Subspace_ambient_left_channel >= 0 ) {
7846                 snd_stop(Subspace_ambient_left_channel);
7847                 Subspace_ambient_left_channel = -1;
7848         }
7849
7850         if ( Subspace_ambient_right_channel >= 0 ) {
7851                 snd_stop(Subspace_ambient_right_channel);
7852                 Subspace_ambient_right_channel = -1;
7853         }
7854 }
7855
7856 // ----------------------------------------------------------------
7857 //
7858 // Subspace Ambient Sound END
7859 //
7860 // ----------------------------------------------------------------
7861
7862 // ----------------------------------------------------------------
7863 //
7864 // Language Autodetection stuff
7865 //
7866
7867 // this layout order must match Lcl_languages in localize.cpp in order for the
7868 // correct language to be detected
7869 int Lang_auto_detect_checksums[LCL_NUM_LANGUAGES] = {
7870 #ifdef MAKE_FS1
7871         1366105450,                             // English
7872 #else
7873         589986744,                              // English
7874 #endif
7875         -1132430286,                    // German
7876         0,                                              // French
7877         -1131728960,                                    // Polish
7878 };
7879
7880 // default setting is "-1" to use config file with English as fall back
7881 // DO NOT change the default setting here or something uncouth might happen
7882 // in the localization code
7883 int detect_lang()
7884 {
7885         uint file_checksum;             
7886         int idx;
7887
7888         // try and open the file to verify
7889         CFILE *detect = cfopen("font01.vf", "rb");
7890         
7891         // will use default setting if something went wrong
7892         if (!detect) {
7893                 return -1;
7894         }       
7895
7896         // get the long checksum of the file
7897         file_checksum = 0;
7898         cfseek(detect, 0, SEEK_SET);    
7899         cf_chksum_long(detect, &file_checksum);
7900         cfclose(detect);
7901         detect = NULL;  
7902
7903         // now compare the checksum/filesize against known #'s
7904         for (idx=0; idx<LCL_NUM_LANGUAGES; idx++) {
7905                 if (Lang_auto_detect_checksums[idx] == (int)file_checksum) {
7906                         return idx;
7907                 }
7908         }
7909
7910         // notify if a match was not found, include detected checksum
7911         printf("ERROR: Unknown Language Checksum: %i\n", (int)file_checksum);
7912         printf("Using default language...\n\n");
7913         
7914         return -1;
7915 }
7916
7917 //
7918 // End Auto Lang stuff
7919 //
7920 // ----------------------------------------------------------------
7921
7922 // ----------------------------------------------------------------
7923 // SHIPS TBL VERIFICATION STUFF
7924 //
7925
7926 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
7927 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
7928         #define NUM_SHIPS_TBL_CHECKSUMS         3
7929 #else
7930         #define NUM_SHIPS_TBL_CHECKSUMS         1
7931 #endif
7932
7933 #ifdef FS2_DEMO
7934 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7935         1696074201,                                             // FS2 demo
7936 };
7937 #elif FS1_DEMO
7938 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7939         1603375034,                                             // FS1 DEMO
7940 };
7941 #elif MAKE_FS1
7942 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7943         -129679197,                                             // FS1 Full 1.06 (US)
7944         7762567,                                                // FS1 SilentThreat
7945         1555372475                                              // FS1 Full 1.06 (German)
7946 };
7947 #else
7948 /*
7949 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7950         -463907578,                                             // US - beta 1
7951         1696074201,                                             // FS2 demo
7952 };
7953 */
7954 int Game_ships_tbl_checksums[NUM_SHIPS_TBL_CHECKSUMS] = {
7955 //      -1022810006,                                    // 1.0 FULL
7956         -1254285366                                             // 1.2 FULL (German)
7957 };
7958 #endif
7959
7960 void verify_ships_tbl()
7961 {       
7962         /*
7963 #ifdef NDEBUG
7964         Game_ships_tbl_valid = 1;
7965 #else
7966         */
7967         uint file_checksum;             
7968         int idx;
7969
7970         // detect if the packfile exists
7971         CFILE *detect = cfopen("ships.tbl", "rb");
7972         Game_ships_tbl_valid = 0;        
7973         
7974         // not mission-disk
7975         if(!detect){
7976                 Game_ships_tbl_valid = 0;
7977                 return;
7978         }       
7979
7980         // get the long checksum of the file
7981         file_checksum = 0;
7982         cfseek(detect, 0, SEEK_SET);    
7983         cf_chksum_long(detect, &file_checksum);
7984         cfclose(detect);
7985         detect = NULL;  
7986
7987         // now compare the checksum/filesize against known #'s
7988         for(idx=0; idx<NUM_SHIPS_TBL_CHECKSUMS; idx++){
7989                 if(Game_ships_tbl_checksums[idx] == (int)file_checksum){
7990                         Game_ships_tbl_valid = 1;
7991                         return;
7992                 }
7993         }
7994 // #endif
7995 }
7996
7997 DCF(shipspew, "display the checksum for the current ships.tbl")
7998 {
7999         uint file_checksum;
8000         CFILE *detect = cfopen("ships.tbl", "rb");
8001         // get the long checksum of the file
8002         file_checksum = 0;
8003         cfseek(detect, 0, SEEK_SET);    
8004         cf_chksum_long(detect, &file_checksum);
8005         cfclose(detect);
8006
8007         dc_printf("%d", file_checksum);
8008 }
8009
8010 // ----------------------------------------------------------------
8011 // WEAPONS TBL VERIFICATION STUFF
8012 //
8013
8014 // checksums, just keep a list of all valid ones, if it matches any of them, keep it
8015 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
8016         #define NUM_WEAPONS_TBL_CHECKSUMS               3
8017 #else
8018         #define NUM_WEAPONS_TBL_CHECKSUMS               1
8019 #endif
8020
8021 #ifdef FS2_DEMO
8022 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8023         -266420030,                             // demo 1
8024 };
8025 #elif FS1_DEMO
8026 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8027         -1246928725,                    // FS1 DEMO
8028 };
8029 #elif MAKE_FS1
8030 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8031         -834598107,                             // FS1 1.06 Full (US)
8032         -1652231417,                    // FS1 SilentThreat
8033         720209793                               // FS1 1.06 Full (German)
8034 };
8035 #else
8036 /*
8037 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8038         141718090,                              // US - beta 1
8039         -266420030,                             // demo 1
8040 };
8041 */
8042 int Game_weapons_tbl_checksums[NUM_WEAPONS_TBL_CHECKSUMS] = {
8043 //      399297860,                              // 1.0 FULL     
8044         -553984927                              // 1.2 FULL (german)
8045 };
8046 #endif
8047
8048 void verify_weapons_tbl()
8049 {       
8050         /*
8051 #ifdef NDEBUG
8052         Game_weapons_tbl_valid = 1;
8053 #else
8054         */
8055         uint file_checksum;
8056         int idx;
8057
8058         // detect if the packfile exists
8059         CFILE *detect = cfopen("weapons.tbl", "rb");
8060         Game_weapons_tbl_valid = 0;      
8061         
8062         // not mission-disk
8063         if(!detect){
8064                 Game_weapons_tbl_valid = 0;
8065                 return;
8066         }       
8067
8068         // get the long checksum of the file
8069         file_checksum = 0;
8070         cfseek(detect, 0, SEEK_SET);    
8071         cf_chksum_long(detect, &file_checksum);
8072         cfclose(detect);
8073         detect = NULL;  
8074
8075         // now compare the checksum/filesize against known #'s
8076         for(idx=0; idx<NUM_WEAPONS_TBL_CHECKSUMS; idx++){
8077                 if(Game_weapons_tbl_checksums[idx] == (int)file_checksum){
8078                         Game_weapons_tbl_valid = 1;
8079                         return;
8080                 }
8081         }
8082 // #endif
8083 }
8084
8085 DCF(wepspew, "display the checksum for the current weapons.tbl")
8086 {
8087         uint file_checksum;
8088         CFILE *detect = cfopen("weapons.tbl", "rb");
8089         // get the long checksum of the file
8090         file_checksum = 0;
8091         cfseek(detect, 0, SEEK_SET);    
8092         cf_chksum_long(detect, &file_checksum);
8093         cfclose(detect);
8094
8095         dc_printf("%d", file_checksum);
8096 }
8097
8098 // if the game is running using hacked data
8099 int game_hacked_data()
8100 {
8101         // hacked!
8102         if(!Game_weapons_tbl_valid || !Game_ships_tbl_valid){
8103                 return 1;
8104         }
8105
8106         // not hacked
8107         return 0;
8108 }
8109
8110 void display_title_screen()
8111 {
8112 #if defined(FS2_DEMO) || defined(OEM_BUILD) || defined(FS1_DEMO)
8113         ///int title_bitmap;
8114
8115         // load bitmap
8116         int title_bitmap = bm_load(Game_demo_title_screen_fname[gr_screen.res]);
8117         if (title_bitmap == -1) {
8118                 return;
8119         }
8120
8121         // set
8122         gr_set_bitmap(title_bitmap);
8123
8124         // draw
8125         gr_bitmap(0, 0);
8126
8127         // flip
8128         gr_flip();
8129
8130         bm_unload(title_bitmap);
8131 #endif  // FS2_DEMO || OEM_BUILD || FS1_DEMO
8132 }
8133
8134 // return true if the game is running with "low memory", which is less than 48MB
8135 bool game_using_low_mem()
8136 {
8137         if (Use_low_mem == 0) {
8138                 return false;
8139         } else {
8140                 return true;
8141         }
8142 }