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