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