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