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