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