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