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