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