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