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