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