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