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