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