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