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