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