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