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