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