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