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