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