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