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