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