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