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