mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
* add subfolder support to cfile * sort files in VP archives before indexing them * fix indexing of sub-subfolders * remove unused 8B22K & 16B11K sound path types * add more items to skip subfolder scanning * fix windows build issues * fix unit tests by allowing 0-byte files to be indexed * fix file indexing on windows * add test for cfile subfolders * remove specific 'markup' and 'css' interface subfolders They aren't directly referenced anywhere by pathtype and the new subfolder code will continue to index and load files from them * add player binds to list of always-root locations * remove file-based localization support An alternative is left in place for old fonts, as that was the only place it appeared to be used. This method of file localization conflicts with subfolder support however so if it's needed in the future then changes to the subfolder code will be necessary. * add subfolder support to cf_find_file_location_ext() * add subfolder tests for cf_find_file_location*() * add shlwapi to needed win32 libs * small bit of cleanup * add subfolder support to cf_get_file_list() * add tests for cfile subfolder lists * report files that might be shadowed * fix issue with lists when a filter is used Also fixes discrepancy in older cf_get_file_list() when a sub path is specified (should be used in all cases, not just glob). * address review suggestions
927 lines
22 KiB
C++
927 lines
22 KiB
C++
|
|
/* WARNING:
|
|
* This is magic-number central, but these numbers are set specifically
|
|
* to the acceptable defaults or range values that were used when the
|
|
* pl2/plr files were created. Standard game defines should not be used in
|
|
* place of these major numbers for /any/ reason, *ever*!
|
|
*/
|
|
|
|
#include "cfile/cfilesystem.h"
|
|
#include "mission/missionbriefcommon.h"
|
|
#include "network/psnet2.h"
|
|
#include "pilotfile/pilotfile_convert.h"
|
|
|
|
|
|
// this struct isn't well packed, and is written whole to the pilot file, so
|
|
// we can't easily just get the RGBA that we need and instead must retain this
|
|
typedef struct conv_color { //-V802
|
|
uint screen_sig;
|
|
ubyte red;
|
|
ubyte green;
|
|
ubyte blue;
|
|
ubyte alpha;
|
|
ubyte ac_type;
|
|
int is_alphacolor;
|
|
ubyte raw8;
|
|
int alphacolor;
|
|
int magic;
|
|
} conv_color;
|
|
|
|
|
|
plr_data::plr_data()
|
|
{
|
|
// not carried over, just for reference during conversion process
|
|
version = 0;
|
|
is_multi = 0;
|
|
lcl_get_language_name(language);
|
|
|
|
// basic flags and settings
|
|
tips = 0;
|
|
rank = 0;
|
|
skill_level = 1;
|
|
save_flags = 0;
|
|
readyroom_listing_mode = 0;
|
|
voice_enabled = 1;
|
|
auto_advance = 1;
|
|
Use_mouse_to_fly = 0;
|
|
Mouse_sensitivity = 4;
|
|
Joy_sensitivity = 9;
|
|
Dead_zone_size = 10;
|
|
|
|
// multiplayer settings/options
|
|
net_protocol = 1;
|
|
|
|
multi_squad_set = 2;
|
|
multi_endgame_set = 3;
|
|
multi_flags = 3;
|
|
multi_respawn = 2;
|
|
multi_max_observers = 2;
|
|
multi_skill_level = 2;
|
|
multi_voice_qos = 10;
|
|
multi_voice_token_wait = 2000;
|
|
multi_voice_record_time = 5000;
|
|
multi_time_limit = -65536;
|
|
multi_kill_limit = 9999;
|
|
|
|
multi_local_flags = 5;
|
|
multi_local_update_level = 0;
|
|
|
|
// pilot info stuff
|
|
memset(image_filename, 0, sizeof(image_filename));
|
|
memset(squad_name, 0, sizeof(squad_name));
|
|
memset(squad_filename, 0, sizeof(squad_filename));
|
|
memset(current_campaign, 0, sizeof(current_campaign));
|
|
memset(last_ship_flown, 0, sizeof(last_ship_flown));
|
|
|
|
// HUD config
|
|
hud_show_flags = -1;
|
|
hud_show_flags2 = 31;
|
|
hud_popup_flags = 0;
|
|
hud_popup_flags2 = 0;
|
|
hud_num_lines = 4;
|
|
hud_rp_flags = 7;
|
|
hud_rp_dist = 2;
|
|
|
|
for (int idx = 0; idx < 39; idx++) {
|
|
hud_colors[idx][0] = 0;
|
|
hud_colors[idx][1] = 255;
|
|
hud_colors[idx][2] = 0;
|
|
hud_colors[idx][3] = 144;
|
|
}
|
|
|
|
// control setup
|
|
joy_axis_map_to[0] = 0;
|
|
joy_axis_map_to[1] = 1;
|
|
joy_axis_map_to[2] = 3;
|
|
joy_invert_axis[3] = -1;
|
|
joy_invert_axis[4] = -1;
|
|
|
|
memset(joy_invert_axis, 0, sizeof(joy_invert_axis));
|
|
|
|
// audio
|
|
sound_volume = 1.0f;
|
|
music_volume = 0.5f;
|
|
voice_volume = 0.7f;
|
|
|
|
// detail settings
|
|
detail_setting = 3;
|
|
detail_nebula = 3;
|
|
detail_distance = 3;
|
|
detail_hardware_textures = 4;
|
|
detail_num_debris = 4;
|
|
detail_num_particles = 3;
|
|
detail_num_stars = 4;
|
|
detail_shield_effects = 4;
|
|
detail_lighting = 4;
|
|
detail_targetview_model = 1;
|
|
detail_planets_suns = 1;
|
|
detail_weapon_extras = 1;
|
|
}
|
|
|
|
plr_data::~plr_data()
|
|
{
|
|
controls.clear();
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_controls()
|
|
{
|
|
int idx;
|
|
CCI con;
|
|
short buf;
|
|
|
|
unsigned char num_controls = cfread_ubyte(cfp);
|
|
|
|
if ( !num_controls ) {
|
|
return;
|
|
}
|
|
|
|
// it may be less than 118, but it shouldn't be more than 118
|
|
// Don't touch this magic number! This is for old playerfiles. See banner at top of this file.
|
|
if (num_controls > 118) {
|
|
throw "Data check failure in controls!";
|
|
}
|
|
|
|
plr->controls.reserve(num_controls);
|
|
|
|
for (idx = 0; idx < num_controls; idx++) {
|
|
buf = cfread_short(cfp);
|
|
if (buf == 255) {
|
|
buf = -1;
|
|
}
|
|
con.take(CC_bind(CID_KEYBOARD, buf), 0);
|
|
|
|
buf = cfread_short(cfp);
|
|
if (buf == 255) {
|
|
buf = -1;
|
|
}
|
|
con.take(CC_bind(CID_JOY0, buf), 1);
|
|
|
|
plr->controls.push_back( con );
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_hud()
|
|
{
|
|
int idx;
|
|
conv_color c;
|
|
|
|
plr->hud_show_flags = cfread_int(cfp);
|
|
plr->hud_show_flags2 = cfread_int(cfp);
|
|
|
|
plr->hud_popup_flags = cfread_int(cfp);
|
|
plr->hud_popup_flags2 = cfread_int(cfp);
|
|
|
|
plr->hud_num_lines = cfread_ubyte(cfp);
|
|
plr->hud_rp_flags = cfread_int(cfp);
|
|
plr->hud_rp_dist = cfread_int(cfp);
|
|
|
|
for (idx = 0; idx < 39; idx++) {
|
|
cfread(&c, sizeof(conv_color), 1, cfp);
|
|
|
|
if ( (c.alphacolor != -1) || (c.is_alphacolor != 1) ) {
|
|
throw "Data check failure in hud!";
|
|
}
|
|
|
|
plr->hud_colors[idx][0] = c.red;
|
|
plr->hud_colors[idx][1] = c.green;
|
|
plr->hud_colors[idx][2] = c.blue;
|
|
plr->hud_colors[idx][3] = c.alpha;
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_detail()
|
|
{
|
|
bool data_failure = false;
|
|
|
|
plr->detail_setting = cfread_int(cfp);
|
|
plr->detail_nebula = cfread_int(cfp);
|
|
plr->detail_distance = cfread_int(cfp);
|
|
plr->detail_hardware_textures = cfread_int(cfp);
|
|
plr->detail_num_debris = cfread_int(cfp);
|
|
plr->detail_num_particles = cfread_int(cfp);
|
|
plr->detail_num_stars = cfread_int(cfp);
|
|
plr->detail_shield_effects = cfread_int(cfp);
|
|
plr->detail_lighting = cfread_int(cfp);
|
|
plr->detail_targetview_model = cfread_int(cfp);
|
|
plr->detail_planets_suns = cfread_int(cfp);
|
|
plr->detail_weapon_extras = cfread_int(cfp);
|
|
|
|
if ( (plr->detail_setting < -1) || (plr->detail_setting > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_nebula < 0) || (plr->detail_nebula > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_distance < 0) || (plr->detail_distance > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_hardware_textures < 0) || (plr->detail_hardware_textures > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_num_debris < 0) || (plr->detail_num_debris > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_num_particles < 0) || (plr->detail_num_particles > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_num_stars < 0) || (plr->detail_num_stars > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_shield_effects < 0) || (plr->detail_shield_effects > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_lighting < 0) || (plr->detail_lighting > 4) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_targetview_model < 0) || (plr->detail_targetview_model > 1) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_planets_suns < 0) || (plr->detail_planets_suns > 1) ) {
|
|
data_failure = true;
|
|
} else if ( (plr->detail_weapon_extras < 0) || (plr->detail_weapon_extras > 1) ) {
|
|
data_failure = true;
|
|
}
|
|
|
|
if (data_failure) {
|
|
throw "Data check failure in details!";
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_stats()
|
|
{
|
|
int idx;
|
|
char name[35];
|
|
|
|
if (fver >= 242) {
|
|
return;
|
|
}
|
|
|
|
// read everything, but we don't need any of it ...
|
|
|
|
cfread_int(cfp); // score
|
|
cfread_int(cfp); // rank
|
|
cfread_int(cfp); // assists
|
|
|
|
// medals
|
|
for (idx = 0; idx < 18; idx++) {
|
|
cfread_int(cfp);
|
|
}
|
|
|
|
// kills per ship
|
|
int count = cfread_int(cfp);
|
|
|
|
for (idx = 0; idx < count; idx++) {
|
|
cfread_ushort(cfp);
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
}
|
|
|
|
cfread_int(cfp); // kill_count
|
|
cfread_int(cfp); // kill_count_ok
|
|
|
|
cfread_uint(cfp); // p_shots_fired
|
|
cfread_uint(cfp); // s_shots_fired
|
|
cfread_uint(cfp); // p_shots_hit
|
|
cfread_uint(cfp); // s_shots_hit
|
|
|
|
cfread_uint(cfp); // p_bonehead_hits
|
|
cfread_uint(cfp); // s_bonehead_hits
|
|
cfread_uint(cfp); // bonehead_kills
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_loadout()
|
|
{
|
|
int idx, j;
|
|
int s_count, w_count;
|
|
char name[52];
|
|
|
|
if (fver >= 242) {
|
|
return;
|
|
}
|
|
|
|
// have to read it, but don't need any of it ...
|
|
|
|
cfread_string_len(name, sizeof(name), cfp); // filename
|
|
cfread_string_len(name, sizeof(name), cfp); // last_modified
|
|
|
|
s_count = cfread_int(cfp); // num ships
|
|
w_count = cfread_int(cfp); // num weapons
|
|
|
|
// ships
|
|
for (idx = 0; idx < s_count; idx++) {
|
|
cfread_int(cfp); // count
|
|
cfread_string_len(name, sizeof(name), cfp); // name
|
|
}
|
|
|
|
// weapons
|
|
for (idx = 0; idx < w_count; idx++) {
|
|
cfread_int(cfp); // count
|
|
cfread_string_len(name, sizeof(name), cfp); // name
|
|
}
|
|
|
|
// loadout info
|
|
for (idx = 0; idx < 12; idx++) {
|
|
cfread_int(cfp); // ship class
|
|
cfread_string_len(name, sizeof(name), cfp); // ship name
|
|
|
|
for (j = 0; j < 12; j++) {
|
|
cfread_int(cfp); // weapon type
|
|
cfread_int(cfp); // weapon count
|
|
cfread_string_len(name, sizeof(name), cfp); // weapon name
|
|
}
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_multiplayer()
|
|
{
|
|
plr->multi_squad_set = cfread_ubyte(cfp);
|
|
plr->multi_endgame_set = cfread_ubyte(cfp);
|
|
plr->multi_flags = cfread_int(cfp);
|
|
plr->multi_respawn = cfread_uint(cfp);
|
|
plr->multi_max_observers = cfread_ubyte(cfp);
|
|
plr->multi_skill_level = cfread_ubyte(cfp);
|
|
plr->multi_voice_qos = cfread_ubyte(cfp);
|
|
plr->multi_voice_token_wait = cfread_int(cfp);
|
|
plr->multi_voice_record_time = cfread_int(cfp);
|
|
plr->multi_time_limit = cfread_int(cfp);
|
|
plr->multi_kill_limit = cfread_int(cfp);
|
|
|
|
plr->multi_local_flags = cfread_int(cfp);
|
|
plr->multi_local_update_level = cfread_int(cfp);
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_red_alert()
|
|
{
|
|
int idx, j;
|
|
char name[35];
|
|
|
|
if (fver >= 242) {
|
|
return;
|
|
}
|
|
|
|
// have to read it, but don't need any of it ...
|
|
|
|
int num_slots = cfread_int(cfp);
|
|
|
|
if ( (num_slots < 0) || (num_slots >= 32) ) {
|
|
throw "Data check failure in red-alert!";
|
|
}
|
|
|
|
if ( !num_slots ) {
|
|
return;
|
|
}
|
|
|
|
for (idx = 0; idx < num_slots; idx++) {
|
|
cfread_string(name, sizeof(name) - 1, cfp);
|
|
cfread_float(cfp);
|
|
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
|
|
// subsystem hits
|
|
for (j = 0; j < 64; j++) {
|
|
cfread_float(cfp);
|
|
}
|
|
|
|
// aggregate hits
|
|
for (j = 0; j < 12; j++) {
|
|
cfread_float(cfp);
|
|
}
|
|
|
|
// weapons
|
|
for (j = 0; j < 12; j++) {
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
cfread_int(cfp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import_variables()
|
|
{
|
|
int idx;
|
|
sexp_variable nvar;
|
|
|
|
int num_variables = cfread_int(cfp);
|
|
|
|
if ( (num_variables < 0) || (num_variables >= 100) ) {
|
|
throw "Data check failure in variables!";
|
|
}
|
|
|
|
plr->variables.reserve(num_variables);
|
|
|
|
for (idx = 0; idx < num_variables; idx++) {
|
|
nvar.type = cfread_int(cfp);
|
|
cfread_string_len(nvar.text, sizeof(nvar.text), cfp);
|
|
cfread_string_len(nvar.variable_name, sizeof(nvar.variable_name), cfp);
|
|
|
|
plr->variables.push_back( nvar );
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::plr_import()
|
|
{
|
|
char name[35];
|
|
int idx;
|
|
|
|
unsigned int plr_id = cfread_uint(cfp);
|
|
|
|
if (plr_id != 0x46505346) {
|
|
throw "Invalid file signature!";
|
|
}
|
|
|
|
fver = cfread_uint(cfp);
|
|
|
|
if ( (fver != 142) && (fver != 242) ) {
|
|
throw "Unsupported file version!";
|
|
}
|
|
|
|
// multi flag
|
|
plr->is_multi = (int)cfread_ubyte(cfp);
|
|
|
|
// rank
|
|
plr->rank = cfread_int(cfp);
|
|
|
|
// mainhall, don't need it
|
|
if (fver < 242) {
|
|
cfread_ubyte(cfp);
|
|
}
|
|
|
|
plr->tips = cfread_int(cfp);
|
|
|
|
if ( (plr->tips < 0) || (plr->tips > 1) ) {
|
|
throw "Data check failure!";
|
|
}
|
|
|
|
cfread_string_len(plr->image_filename, sizeof(plr->image_filename), cfp);
|
|
cfread_string_len(plr->squad_name, sizeof(plr->squad_name), cfp);
|
|
cfread_string_len(plr->squad_filename, sizeof(plr->squad_filename), cfp);
|
|
cfread_string_len(plr->current_campaign, sizeof(plr->current_campaign), cfp);
|
|
cfread_string_len(plr->last_ship_flown, sizeof(plr->last_ship_flown), cfp);
|
|
|
|
// controls
|
|
plr_import_controls();
|
|
|
|
// hud config
|
|
plr_import_hud();
|
|
|
|
// cutscenes, don't need it
|
|
if (fver < 242) {
|
|
cfread_int(cfp);
|
|
}
|
|
|
|
// volume stuff
|
|
plr->sound_volume = cfread_float(cfp);
|
|
plr->music_volume = cfread_float(cfp);
|
|
plr->voice_volume = cfread_float(cfp);
|
|
|
|
// detail settings
|
|
plr_import_detail();
|
|
|
|
// recent missions, don't need it
|
|
int num_missions = cfread_int(cfp);
|
|
|
|
for (idx = 0; idx < num_missions; idx++) {
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
}
|
|
|
|
// stats, will skip if fver < 242
|
|
plr_import_stats();
|
|
|
|
plr->skill_level = cfread_int(cfp);
|
|
|
|
if ( (plr->skill_level < 0) || (plr->skill_level > 4) ) {
|
|
throw "Data check failure!";
|
|
}
|
|
|
|
// extra joystick stuff
|
|
for (idx = 0; idx < 5; idx++) {
|
|
plr->joy_axis_map_to[idx] = cfread_int(cfp);
|
|
plr->joy_invert_axis[idx] = cfread_int(cfp);
|
|
}
|
|
|
|
// flags
|
|
plr->save_flags = cfread_int(cfp);
|
|
|
|
// loadout, will skip if fver < 242
|
|
plr_import_loadout();
|
|
|
|
// multiplayer
|
|
plr_import_multiplayer();
|
|
|
|
// two briefing related values
|
|
plr->readyroom_listing_mode = cfread_int(cfp);
|
|
Briefing_voice_enabled = cfread_int(cfp) != 0;
|
|
|
|
plr->net_protocol = cfread_int(cfp);
|
|
|
|
// protocol must be set to something
|
|
if (plr->net_protocol == NET_NONE) {
|
|
plr->net_protocol = NET_TCP;
|
|
} else if ( (plr->net_protocol < 0) || (plr->net_protocol > NET_VMT) ) {
|
|
throw "Data check failure!";
|
|
}
|
|
|
|
// red alert status, will skip if fver < 242 (and should be empty if multi)
|
|
plr_import_red_alert();
|
|
|
|
// briefing auto-advance
|
|
plr->auto_advance = cfread_int(cfp);
|
|
|
|
if ( (plr->auto_advance < 0) || (plr->auto_advance > 1) ) {
|
|
throw "Data check failure!";
|
|
}
|
|
|
|
// some input options
|
|
plr->Use_mouse_to_fly = cfread_int(cfp);
|
|
plr->Mouse_sensitivity = cfread_int(cfp);
|
|
plr->Joy_sensitivity = cfread_int(cfp);
|
|
plr->Dead_zone_size = cfread_int(cfp);
|
|
|
|
// variables
|
|
plr_import_variables();
|
|
|
|
|
|
// and... we're done! :)
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_flags()
|
|
{
|
|
startSection(Section::Flags);
|
|
|
|
// tips
|
|
cfwrite_ubyte((unsigned char)plr->tips, cfp);
|
|
|
|
// saved flags
|
|
cfwrite_int(plr->save_flags, cfp);
|
|
|
|
// listing mode (single or campaign missions)
|
|
cfwrite_int(plr->readyroom_listing_mode, cfp);
|
|
|
|
// briefing auto-play
|
|
cfwrite_int(plr->auto_advance, cfp);
|
|
|
|
// special rank setting (to avoid having to read all stats on verify)
|
|
cfwrite_int(plr->rank, cfp);
|
|
|
|
// What game mode we were in last on this pilot
|
|
cfwrite_int(plr->is_multi, cfp);
|
|
|
|
// which language was this pilot created with
|
|
cfwrite_string_len(plr->language, cfp);
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_info()
|
|
{
|
|
startSection(Section::Info);
|
|
|
|
// pilot image
|
|
cfwrite_string_len(plr->image_filename, cfp);
|
|
|
|
// squad name
|
|
cfwrite_string_len(plr->squad_name, cfp);
|
|
|
|
// squad image
|
|
cfwrite_string_len(plr->squad_filename, cfp);
|
|
|
|
// active campaign
|
|
cfwrite_string_len(plr->current_campaign, cfp);
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_stats()
|
|
{
|
|
int idx, list_size = 0;
|
|
|
|
startSection(Section::Scoring);
|
|
|
|
// global, all-time stats
|
|
cfwrite_int(all_time_stats.score, cfp);
|
|
cfwrite_int(all_time_stats.rank, cfp);
|
|
cfwrite_int(all_time_stats.assists, cfp);
|
|
cfwrite_int(all_time_stats.kill_count, cfp);
|
|
cfwrite_int(all_time_stats.kill_count_ok, cfp);
|
|
cfwrite_int(all_time_stats.bonehead_kills, cfp);
|
|
|
|
cfwrite_uint(all_time_stats.p_shots_fired, cfp);
|
|
cfwrite_uint(all_time_stats.p_shots_hit, cfp);
|
|
cfwrite_uint(all_time_stats.p_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(all_time_stats.s_shots_fired, cfp);
|
|
cfwrite_uint(all_time_stats.s_shots_hit, cfp);
|
|
cfwrite_uint(all_time_stats.s_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(all_time_stats.flight_time, cfp);
|
|
cfwrite_uint(all_time_stats.missions_flown, cfp);
|
|
cfwrite_int((int)all_time_stats.last_flown, cfp);
|
|
cfwrite_int((int)all_time_stats.last_backup, cfp);
|
|
|
|
// ship kills (contains ships across all mods, not just current)
|
|
list_size = (int)all_time_stats.ship_kills.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(all_time_stats.ship_kills[idx].name.c_str(), cfp);
|
|
cfwrite_int(all_time_stats.ship_kills[idx].val, cfp);
|
|
}
|
|
|
|
// medals earned (contains medals across all mods, not just current)
|
|
list_size = (int)all_time_stats.medals_earned.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(all_time_stats.medals_earned[idx].name.c_str(), cfp);
|
|
cfwrite_int(all_time_stats.medals_earned[idx].val, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_stats_multi()
|
|
{
|
|
int idx, list_size = 0;
|
|
|
|
startSection(Section::ScoringMulti);
|
|
|
|
// global, all-time stats
|
|
cfwrite_int(multi_stats.score, cfp);
|
|
cfwrite_int(multi_stats.rank, cfp);
|
|
cfwrite_int(multi_stats.assists, cfp);
|
|
cfwrite_int(multi_stats.kill_count, cfp);
|
|
cfwrite_int(multi_stats.kill_count_ok, cfp);
|
|
cfwrite_int(multi_stats.bonehead_kills, cfp);
|
|
|
|
cfwrite_uint(multi_stats.p_shots_fired, cfp);
|
|
cfwrite_uint(multi_stats.p_shots_hit, cfp);
|
|
cfwrite_uint(multi_stats.p_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(multi_stats.s_shots_fired, cfp);
|
|
cfwrite_uint(multi_stats.s_shots_hit, cfp);
|
|
cfwrite_uint(multi_stats.s_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(multi_stats.flight_time, cfp);
|
|
cfwrite_uint(multi_stats.missions_flown, cfp);
|
|
cfwrite_int((int)multi_stats.last_flown, cfp);
|
|
cfwrite_int((int)multi_stats.last_backup, cfp);
|
|
|
|
// ship kills (contains medals across all mods, not just current)
|
|
list_size = (int)multi_stats.ship_kills.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(multi_stats.ship_kills[idx].name.c_str(), cfp);
|
|
cfwrite_int(multi_stats.ship_kills[idx].val, cfp);
|
|
}
|
|
|
|
// medals earned (contains medals across all mods, not just current)
|
|
list_size = (int)multi_stats.medals_earned.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(multi_stats.medals_earned[idx].name.c_str(), cfp);
|
|
cfwrite_int(multi_stats.medals_earned[idx].val, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_hud()
|
|
{
|
|
int idx;
|
|
|
|
startSection(Section::HUD);
|
|
|
|
// flags
|
|
cfwrite_int(plr->hud_show_flags, cfp);
|
|
cfwrite_int(plr->hud_show_flags2, cfp);
|
|
|
|
cfwrite_int(plr->hud_popup_flags, cfp);
|
|
cfwrite_int(plr->hud_popup_flags2, cfp);
|
|
|
|
// settings
|
|
cfwrite_ubyte(plr->hud_num_lines, cfp);
|
|
|
|
cfwrite_int(plr->hud_rp_flags, cfp);
|
|
cfwrite_int(plr->hud_rp_dist, cfp);
|
|
|
|
// basic colors
|
|
cfwrite_int(0, cfp); // color
|
|
cfwrite_int(8, cfp); // alpha
|
|
|
|
// gauge-specific colors
|
|
cfwrite_int(39, cfp);
|
|
|
|
for (idx = 0; idx < 39; idx++) {
|
|
cfwrite_ubyte(plr->hud_colors[idx][0], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][1], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][2], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][3], cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_variables()
|
|
{
|
|
int list_size = 0;
|
|
int idx;
|
|
|
|
startSection(Section::Variables);
|
|
|
|
list_size = (int)plr->variables.size();
|
|
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(plr->variables[idx].type, cfp);
|
|
cfwrite_string_len(plr->variables[idx].text, cfp);
|
|
cfwrite_string_len(plr->variables[idx].variable_name, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_multiplayer()
|
|
{
|
|
startSection(Section::Multiplayer);
|
|
|
|
// netgame options
|
|
cfwrite_ubyte(plr->multi_squad_set, cfp);
|
|
cfwrite_ubyte(plr->multi_endgame_set, cfp);
|
|
cfwrite_int(plr->multi_flags, cfp);
|
|
cfwrite_uint(plr->multi_respawn, cfp);
|
|
cfwrite_ubyte(plr->multi_max_observers, cfp);
|
|
cfwrite_ubyte(plr->multi_skill_level, cfp);
|
|
cfwrite_ubyte(plr->multi_voice_qos, cfp);
|
|
cfwrite_int(plr->multi_voice_token_wait, cfp);
|
|
cfwrite_int(plr->multi_voice_record_time, cfp);
|
|
cfwrite_int(plr->multi_time_limit, cfp);
|
|
cfwrite_int(plr->multi_kill_limit, cfp);
|
|
|
|
// local options
|
|
cfwrite_int(plr->multi_local_flags, cfp);
|
|
cfwrite_int(plr->multi_local_update_level, cfp);
|
|
|
|
// netgame protocol
|
|
cfwrite_int(plr->net_protocol, cfp);
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_controls()
|
|
{
|
|
unsigned int idx;
|
|
|
|
startSection(Section::Controls);
|
|
|
|
cfwrite_ushort((unsigned short)plr->controls.size(), cfp);
|
|
|
|
for (idx = 0; idx < plr->controls.size(); idx++) {
|
|
cfwrite_short(plr->controls[idx].get_btn(CID_KEYBOARD), cfp);
|
|
cfwrite_short(plr->controls[idx].get_btn(CID_JOY0), cfp);
|
|
// placeholder? for future mouse_id?
|
|
cfwrite_short(-1, cfp);
|
|
}
|
|
|
|
// extra joystick stuff
|
|
cfwrite_int(MAX_JOY_AXES_CONV, cfp);
|
|
for (idx = 0; idx < MAX_JOY_AXES_CONV; idx++) {
|
|
cfwrite_int(plr->joy_axis_map_to[idx], cfp);
|
|
cfwrite_int(plr->joy_invert_axis[idx], cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export_settings()
|
|
{
|
|
startSection(Section::Settings);
|
|
|
|
// sound/voice/music
|
|
cfwrite_float(plr->sound_volume, cfp);
|
|
cfwrite_float(plr->music_volume, cfp);
|
|
cfwrite_float(plr->voice_volume, cfp);
|
|
|
|
cfwrite_int(plr->voice_enabled, cfp);
|
|
|
|
// skill level
|
|
cfwrite_int(plr->skill_level, cfp);
|
|
|
|
// input options
|
|
cfwrite_int(plr->Use_mouse_to_fly, cfp);
|
|
cfwrite_int(plr->Mouse_sensitivity, cfp);
|
|
cfwrite_int(plr->Joy_sensitivity, cfp);
|
|
cfwrite_int(plr->Dead_zone_size, cfp);
|
|
|
|
// detail
|
|
cfwrite_int(plr->detail_setting, cfp);
|
|
cfwrite_int(plr->detail_nebula, cfp);
|
|
cfwrite_int(plr->detail_distance, cfp);
|
|
cfwrite_int(plr->detail_hardware_textures, cfp);
|
|
cfwrite_int(plr->detail_num_debris, cfp);
|
|
cfwrite_int(plr->detail_num_particles, cfp);
|
|
cfwrite_int(plr->detail_num_stars, cfp);
|
|
cfwrite_int(plr->detail_shield_effects, cfp);
|
|
cfwrite_int(plr->detail_lighting, cfp);
|
|
cfwrite_int(plr->detail_targetview_model, cfp);
|
|
cfwrite_int(plr->detail_planets_suns, cfp);
|
|
cfwrite_int(plr->detail_weapon_extras, cfp);
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::plr_export()
|
|
{
|
|
Assert( cfp != NULL );
|
|
|
|
// header and version
|
|
cfwrite_int(PLR_FILE_ID, cfp);
|
|
cfwrite_ubyte(PLR_VERSION, cfp);
|
|
|
|
// flags and info sections go first
|
|
plr_export_flags();
|
|
plr_export_info();
|
|
|
|
// everything else is next, not order specific
|
|
plr_export_stats();
|
|
plr_export_stats_multi();
|
|
plr_export_hud();
|
|
plr_export_variables();
|
|
plr_export_multiplayer();
|
|
plr_export_controls();
|
|
plr_export_settings();
|
|
|
|
|
|
// and... we're done! :)
|
|
}
|
|
|
|
bool pilotfile_convert::plr_convert(const char *fname, bool inferno)
|
|
{
|
|
Assert( fname != NULL );
|
|
|
|
SCP_string filename;
|
|
bool rval = true;
|
|
|
|
|
|
if (plr == NULL) {
|
|
plr = new(std::nothrow) plr_data;
|
|
}
|
|
|
|
if (plr == NULL) {
|
|
return false;
|
|
}
|
|
|
|
filename.reserve(200);
|
|
|
|
cf_create_default_path_string(filename, CF_TYPE_SINGLE_PLAYERS, (inferno) ? "inferno" : nullptr,
|
|
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
|
|
|
if (inferno) {
|
|
filename.append(DIR_SEPARATOR_STR);
|
|
}
|
|
|
|
filename.append(fname);
|
|
filename.append(".pl2");
|
|
|
|
mprintf((" PL2 => Converting '%s'...\n", filename.c_str()));
|
|
|
|
cfp = cfopen(filename.c_str(), "rb", CFILE_NORMAL);
|
|
|
|
if ( !cfp ) {
|
|
mprintf((" PL2 => Unable to open '%s' for import!\n", fname));
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
plr_import();
|
|
} catch (const char *err) {
|
|
mprintf(( " PL2 => Import ERROR: %s\n", err));
|
|
rval = false;
|
|
}
|
|
|
|
cfclose(cfp);
|
|
cfp = NULL;
|
|
|
|
if ( !rval ) {
|
|
return false;
|
|
}
|
|
|
|
filename.assign(fname);
|
|
filename.append(".plr");
|
|
|
|
cfp = cfopen(filename.c_str(), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS, false,
|
|
CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
|
|
|
|
if ( !cfp ) {
|
|
mprintf((" PLR => Unable to open '%s' for export!\n", fname));
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
plr_export();
|
|
} catch (const char *err) {
|
|
mprintf((" PLR => Export ERROR: %s\n", err));
|
|
rval = false;
|
|
}
|
|
|
|
cfclose(cfp);
|
|
cfp = NULL;
|
|
|
|
if (rval) {
|
|
mprintf((" PLR => Conversion complete!\n"));
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|