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