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