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