Files
fs2open.github.com/code/pilotfile/plr.cpp
T
jg18 1adb64e39d Remove IPX support.
Remove support for the IPX protocol. The IPX selector button in the multi
options menu is now hidden, and the TCP button is disabled since there is no other option.
2016-02-25 10:28:49 -08:00

1122 lines
29 KiB
C++

#include "freespace2/freespace.h"
#include "gamesnd/eventmusic.h"
#include "hud/hudconfig.h"
#include "hud/hudsquadmsg.h"
#include "io/joy.h"
#include "io/mouse.h"
#include "localization/localize.h"
#include "menuui/techmenu.h"
#include "network/multi.h"
#include "osapi/osregistry.h"
#include "pilotfile/pilotfile.h"
#include "playerman/managepilot.h"
#include "playerman/player.h"
#include "ship/ship.h"
#include "sound/audiostr.h"
#include "stats/medals.h"
#include "weapon/weapon.h"
void pilotfile::plr_read_flags()
{
// tips?
p->tips = (int)cfread_ubyte(cfp);
// saved flags
p->save_flags = cfread_int(cfp);
// listing mode (single or campaign missions
p->readyroom_listing_mode = cfread_int(cfp);
// briefing auto-play
p->auto_advance = cfread_int(cfp);
// special rank setting (to avoid having to read all stats on verify)
// will be the multi rank
// if there's a valid CSG, this will be overwritten
p->stats.rank = cfread_int(cfp);
if (version > 0)
{
p->player_was_multi = cfread_int(cfp);
} else
{
p->player_was_multi = 0; // Default to single player
}
// which language was this pilot created with
if (version > 1) {
cfread_string_len(p->language, sizeof(p->language), cfp);
} else {
// if we don't know, default to the current language setting
lcl_get_language_name(p->language);
}
}
void pilotfile::plr_write_flags()
{
startSection(Section::Flags);
// tips
cfwrite_ubyte((unsigned char)p->tips, cfp);
// saved flags
cfwrite_int(p->save_flags, cfp);
// listing mode (single or campaign missions)
cfwrite_int(p->readyroom_listing_mode, cfp);
// briefing auto-play
cfwrite_int(p->auto_advance, cfp);
// special rank setting (to avoid having to read all stats on verify)
// should be multi only from now on
cfwrite_int(multi_stats.rank, cfp);
// What game mode we were in last on this pilot
cfwrite_int(p->player_was_multi, cfp);
// which language was this pilot created with
cfwrite_string_len(p->language, cfp);
endSection();
}
void pilotfile::plr_read_info()
{
if ( !m_have_flags ) {
throw "Info before Flags!";
}
// pilot image
cfread_string_len(p->image_filename, MAX_FILENAME_LEN, cfp);
// multi squad name
cfread_string_len(p->m_squad_name, NAME_LENGTH, cfp);
// squad image
cfread_string_len(p->m_squad_filename, MAX_FILENAME_LEN, cfp);
// active campaign
cfread_string_len(p->current_campaign, MAX_FILENAME_LEN, cfp);
}
void pilotfile::plr_write_info()
{
startSection(Section::Info);
// pilot image
cfwrite_string_len(p->image_filename, cfp);
// multi squad name
cfwrite_string_len(p->m_squad_name, cfp);
// squad image
cfwrite_string_len(p->m_squad_filename, cfp);
// active campaign
cfwrite_string_len(p->current_campaign, cfp);
endSection();
}
void pilotfile::plr_read_hud()
{
int idx;
// flags
HUD_config.show_flags = cfread_int(cfp);
HUD_config.show_flags2 = cfread_int(cfp);
HUD_config.popup_flags = cfread_int(cfp);
HUD_config.popup_flags2 = cfread_int(cfp);
// settings
HUD_config.num_msg_window_lines = cfread_ubyte(cfp);
HUD_config.rp_flags = cfread_int(cfp);
HUD_config.rp_dist = cfread_int(cfp);
// basic colors
HUD_config.main_color = cfread_int(cfp);
HUD_color_alpha = cfread_int(cfp);
if (HUD_color_alpha < HUD_COLOR_ALPHA_USER_MIN) {
HUD_color_alpha = HUD_COLOR_ALPHA_DEFAULT;
}
hud_config_set_color(HUD_config.main_color);
// gauge-specific colors
int num_gauges = cfread_int(cfp);
for (idx = 0; idx < num_gauges; idx++) {
ubyte red = cfread_ubyte(cfp);
ubyte green = cfread_ubyte(cfp);
ubyte blue = cfread_ubyte(cfp);
ubyte alpha = cfread_ubyte(cfp);
if (idx >= NUM_HUD_GAUGES) {
continue;
}
HUD_config.clr[idx].red = red;
HUD_config.clr[idx].green = green;
HUD_config.clr[idx].blue = blue;
HUD_config.clr[idx].alpha = alpha;
}
}
void pilotfile::plr_write_hud()
{
int idx;
startSection(Section::HUD);
// flags
cfwrite_int(HUD_config.show_flags, cfp);
cfwrite_int(HUD_config.show_flags2, cfp);
cfwrite_int(HUD_config.popup_flags, cfp);
cfwrite_int(HUD_config.popup_flags2, cfp);
// settings
cfwrite_ubyte(HUD_config.num_msg_window_lines, cfp);
cfwrite_int(HUD_config.rp_flags, cfp);
cfwrite_int(HUD_config.rp_dist, cfp);
// basic colors
cfwrite_int(HUD_config.main_color, cfp);
cfwrite_int(HUD_color_alpha, cfp);
// gauge-specific colors
cfwrite_int(NUM_HUD_GAUGES, cfp);
for (idx = 0; idx < NUM_HUD_GAUGES; idx++) {
cfwrite_ubyte(HUD_config.clr[idx].red, cfp);
cfwrite_ubyte(HUD_config.clr[idx].green, cfp);
cfwrite_ubyte(HUD_config.clr[idx].blue, cfp);
cfwrite_ubyte(HUD_config.clr[idx].alpha, cfp);
}
endSection();
}
void pilotfile::plr_read_variables()
{
int list_size = 0;
int idx;
sexp_variable n_var;
list_size = cfread_int(cfp);
if (list_size <= 0) {
return;
}
p->variables.reserve(list_size);
for (idx = 0; idx < list_size; idx++) {
n_var.type = cfread_int(cfp);
cfread_string_len(n_var.text, TOKEN_LENGTH, cfp);
cfread_string_len(n_var.variable_name, TOKEN_LENGTH, cfp);
p->variables.push_back( n_var );
}
}
void pilotfile::plr_write_variables()
{
int list_size = 0;
int idx;
startSection(Section::Variables);
list_size = (int)p->variables.size();
cfwrite_int(list_size, cfp);
for (idx = 0; idx < list_size; idx++) {
cfwrite_int(p->variables[idx].type, cfp);
cfwrite_string_len(p->variables[idx].text, cfp);
cfwrite_string_len(p->variables[idx].variable_name, cfp);
}
endSection();
}
void pilotfile::plr_read_multiplayer()
{
// netgame options
p->m_server_options.squad_set = cfread_ubyte(cfp);
p->m_server_options.endgame_set = cfread_ubyte(cfp);
p->m_server_options.flags = cfread_int(cfp);
p->m_server_options.respawn = cfread_uint(cfp);
p->m_server_options.max_observers = cfread_ubyte(cfp);
p->m_server_options.skill_level = cfread_ubyte(cfp);
p->m_server_options.voice_qos = cfread_ubyte(cfp);
p->m_server_options.voice_token_wait = cfread_int(cfp);
p->m_server_options.voice_record_time = cfread_int(cfp);
p->m_server_options.mission_time_limit = (fix)cfread_int(cfp);
p->m_server_options.kill_limit = cfread_int(cfp);
// local options
p->m_local_options.flags = cfread_int(cfp);
p->m_local_options.obj_update_level = cfread_int(cfp);
// netgame protocol
Multi_options_g.protocol = cfread_int(cfp);
if (Multi_options_g.protocol != NET_TCP) {
Multi_options_g.protocol = NET_TCP;
}
}
void pilotfile::plr_write_multiplayer()
{
startSection(Section::Multiplayer);
// netgame options
cfwrite_ubyte(p->m_server_options.squad_set, cfp);
cfwrite_ubyte(p->m_server_options.endgame_set, cfp);
cfwrite_int(p->m_server_options.flags, cfp);
cfwrite_uint(p->m_server_options.respawn, cfp);
cfwrite_ubyte(p->m_server_options.max_observers, cfp);
cfwrite_ubyte(p->m_server_options.skill_level, cfp);
cfwrite_ubyte(p->m_server_options.voice_qos, cfp);
cfwrite_int(p->m_server_options.voice_token_wait, cfp);
cfwrite_int(p->m_server_options.voice_record_time, cfp);
cfwrite_int((int)p->m_server_options.mission_time_limit, cfp);
cfwrite_int(p->m_server_options.kill_limit, cfp);
// local options
cfwrite_int(p->m_local_options.flags, cfp);
cfwrite_int(p->m_local_options.obj_update_level, cfp);
// netgame protocol
cfwrite_int(Multi_options_g.protocol, cfp);
endSection();
}
void pilotfile::plr_read_stats()
{
int idx, j, list_size = 0;
index_list_t ilist;
char t_string[NAME_LENGTH+1];
// global, all-time stats (used only until campaign stats are loaded)
all_time_stats.score = cfread_int(cfp);
all_time_stats.rank = cfread_int(cfp);
all_time_stats.assists = cfread_int(cfp);
all_time_stats.kill_count = cfread_int(cfp);
all_time_stats.kill_count_ok = cfread_int(cfp);
all_time_stats.bonehead_kills = cfread_int(cfp);
all_time_stats.p_shots_fired = cfread_uint(cfp);
all_time_stats.p_shots_hit = cfread_uint(cfp);
all_time_stats.p_bonehead_hits = cfread_uint(cfp);
all_time_stats.s_shots_fired = cfread_uint(cfp);
all_time_stats.s_shots_hit = cfread_uint(cfp);
all_time_stats.s_bonehead_hits = cfread_uint(cfp);
all_time_stats.flight_time = cfread_uint(cfp);
all_time_stats.missions_flown = cfread_uint(cfp);
all_time_stats.last_flown = (_fs_time_t)cfread_int(cfp);
all_time_stats.last_backup = (_fs_time_t)cfread_int(cfp);
// ship kills (contains ships across all mods, not just current)
list_size = cfread_int(cfp);
all_time_stats.ship_kills.reserve(list_size);
for (idx = 0; idx < list_size; idx++) {
cfread_string_len(t_string, NAME_LENGTH, cfp);
ilist.name = t_string;
ilist.index = ship_info_lookup(t_string);
ilist.val = cfread_int(cfp);
all_time_stats.ship_kills.push_back(ilist);
}
// medals earned (contains medals across all mods, not just current)
list_size = cfread_int(cfp);
all_time_stats.medals_earned.reserve(list_size);
for (idx = 0; idx < list_size; idx++) {
cfread_string_len(t_string, NAME_LENGTH,cfp);
ilist.name = t_string;
ilist.index = medals_info_lookup(t_string);
ilist.val = cfread_int(cfp);
all_time_stats.medals_earned.push_back(ilist);
}
// if not in multiplayer mode then set these stats as the player stats
if ( !(Game_mode & GM_MULTIPLAYER) ) {
p->stats.score = all_time_stats.score;
p->stats.rank = all_time_stats.rank;
p->stats.assists = all_time_stats.assists;
p->stats.kill_count = all_time_stats.kill_count;
p->stats.kill_count_ok = all_time_stats.kill_count_ok;
p->stats.bonehead_kills = all_time_stats.bonehead_kills;
p->stats.p_shots_fired = all_time_stats.p_shots_fired;
p->stats.p_shots_hit = all_time_stats.p_shots_hit;
p->stats.p_bonehead_hits = all_time_stats.p_bonehead_hits;
p->stats.s_shots_fired = all_time_stats.s_shots_fired;
p->stats.s_shots_hit = all_time_stats.s_shots_hit;
p->stats.s_bonehead_hits = all_time_stats.s_bonehead_hits;
p->stats.flight_time = all_time_stats.flight_time;
p->stats.missions_flown = all_time_stats.missions_flown;
p->stats.last_flown = all_time_stats.last_flown;
p->stats.last_backup = all_time_stats.last_backup;
// ship kills (have to find ones that match content)
list_size = (int)all_time_stats.ship_kills.size();
for (idx = 0; idx < list_size; idx++) {
j = all_time_stats.ship_kills[idx].index;
if (j >= 0) {
p->stats.kills[j] = all_time_stats.ship_kills[idx].val;
}
}
// medals earned (have to find ones that match content)
list_size = (int)all_time_stats.medals_earned.size();
for (idx = 0; idx < list_size; idx++) {
j = all_time_stats.medals_earned[idx].index;
if (j >= 0) {
p->stats.medal_counts[j] = all_time_stats.medals_earned[idx].val;
}
}
}
}
void pilotfile::plr_write_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::plr_read_stats_multi()
{
int idx, j, list_size = 0;
index_list_t ilist;
char t_string[NAME_LENGTH+1];
// global, all-time stats (used only until campaign stats are loaded)
multi_stats.score = cfread_int(cfp);
multi_stats.rank = cfread_int(cfp);
multi_stats.assists = cfread_int(cfp);
multi_stats.kill_count = cfread_int(cfp);
multi_stats.kill_count_ok = cfread_int(cfp);
multi_stats.bonehead_kills = cfread_int(cfp);
multi_stats.p_shots_fired = cfread_uint(cfp);
multi_stats.p_shots_hit = cfread_uint(cfp);
multi_stats.p_bonehead_hits = cfread_uint(cfp);
multi_stats.s_shots_fired = cfread_uint(cfp);
multi_stats.s_shots_hit = cfread_uint(cfp);
multi_stats.s_bonehead_hits = cfread_uint(cfp);
multi_stats.flight_time = cfread_uint(cfp);
multi_stats.missions_flown = cfread_uint(cfp);
multi_stats.last_flown = (_fs_time_t)cfread_int(cfp);
multi_stats.last_backup = (_fs_time_t)cfread_int(cfp);
// ship kills (contains ships across all mods, not just current)
list_size = cfread_int(cfp);
multi_stats.ship_kills.reserve(list_size);
for (idx = 0; idx < list_size; idx++) {
cfread_string_len(t_string, NAME_LENGTH, cfp);
ilist.name = t_string;
ilist.index = ship_info_lookup(t_string);
ilist.val = cfread_int(cfp);
multi_stats.ship_kills.push_back(ilist);
}
// medals earned (contains medals across all mods, not just current)
list_size = cfread_int(cfp);
multi_stats.medals_earned.reserve(list_size);
for (idx = 0; idx < list_size; idx++) {
cfread_string_len(t_string, NAME_LENGTH,cfp);
ilist.name = t_string;
ilist.index = medals_info_lookup(t_string);
ilist.val = cfread_int(cfp);
multi_stats.medals_earned.push_back(ilist);
}
// if in multiplayer mode then set these stats as the player stats
if (Game_mode & GM_MULTIPLAYER) {
p->stats.score = multi_stats.score;
p->stats.rank = multi_stats.rank;
p->stats.assists = multi_stats.assists;
p->stats.kill_count = multi_stats.kill_count;
p->stats.kill_count_ok = multi_stats.kill_count_ok;
p->stats.bonehead_kills = multi_stats.bonehead_kills;
p->stats.p_shots_fired = multi_stats.p_shots_fired;
p->stats.p_shots_hit = multi_stats.p_shots_hit;
p->stats.p_bonehead_hits = multi_stats.p_bonehead_hits;
p->stats.s_shots_fired = multi_stats.s_shots_fired;
p->stats.s_shots_hit = multi_stats.s_shots_hit;
p->stats.s_bonehead_hits = multi_stats.s_bonehead_hits;
p->stats.flight_time = multi_stats.flight_time;
p->stats.missions_flown = multi_stats.missions_flown;
p->stats.last_flown = multi_stats.last_flown;
p->stats.last_backup = multi_stats.last_backup;
// ship kills (have to find ones that match content)
list_size = (int)multi_stats.ship_kills.size();
for (idx = 0; idx < list_size; idx++) {
j = multi_stats.ship_kills[idx].index;
if (j >= 0) {
p->stats.kills[j] = multi_stats.ship_kills[idx].val;
}
}
// medals earned (have to find ones that match content)
list_size = (int)multi_stats.medals_earned.size();
for (idx = 0; idx < list_size; idx++) {
j = multi_stats.medals_earned[idx].index;
if (j >= 0) {
p->stats.medal_counts[j] = multi_stats.medals_earned[idx].val;
}
}
}
}
void pilotfile::plr_write_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::plr_read_controls()
{
int idx, list_size, list_axis;
short id1, id2, id3 __UNUSED;
int axi, inv;
list_size = (int)cfread_ushort(cfp);
for (idx = 0; idx < list_size; idx++) {
id1 = cfread_short(cfp);
id2 = cfread_short(cfp);
id3 = cfread_short(cfp); // unused, at the moment
if (idx < CCFG_MAX) {
Control_config[idx].key_id = id1;
Control_config[idx].joy_id = id2;
}
}
list_axis = cfread_int(cfp);
for (idx = 0; idx < list_axis; idx++) {
axi = cfread_int(cfp);
inv = cfread_int(cfp);
if (idx < NUM_JOY_AXIS_ACTIONS) {
Axis_map_to[idx] = axi;
Invert_axis[idx] = inv;
}
}
}
void pilotfile::plr_write_controls()
{
int idx;
startSection(Section::Controls);
cfwrite_ushort(CCFG_MAX, cfp);
for (idx = 0; idx < CCFG_MAX; idx++) {
cfwrite_short(Control_config[idx].key_id, cfp);
cfwrite_short(Control_config[idx].joy_id, cfp);
// placeholder? for future mouse_id?
cfwrite_short(-1, cfp);
}
cfwrite_int(NUM_JOY_AXIS_ACTIONS, cfp);
for (idx = 0; idx < NUM_JOY_AXIS_ACTIONS; idx++) {
cfwrite_int(Axis_map_to[idx], cfp);
cfwrite_int(Invert_axis[idx], cfp);
}
endSection();
}
void pilotfile::plr_read_settings()
{
// sound/voice/music
Master_sound_volume = cfread_float(cfp);
Master_event_music_volume = cfread_float(cfp);
Master_voice_volume = cfread_float(cfp);
audiostream_set_volume_all(Master_voice_volume, ASF_VOICE);
audiostream_set_volume_all(Master_event_music_volume, ASF_EVENTMUSIC);
if (Master_event_music_volume > 0.0f) {
Event_music_enabled = 1;
} else {
Event_music_enabled = 0;
}
Briefing_voice_enabled = cfread_int(cfp);
// skill level
Game_skill_level = cfread_int(cfp);
// input options
Use_mouse_to_fly = cfread_int(cfp);
Mouse_sensitivity = cfread_int(cfp);
Joy_sensitivity = cfread_int(cfp);
Dead_zone_size = cfread_int(cfp);
// detail
Detail.setting = cfread_int(cfp);
Detail.nebula_detail = cfread_int(cfp);
Detail.detail_distance = cfread_int(cfp);
Detail.hardware_textures = cfread_int(cfp);
Detail.num_small_debris = cfread_int(cfp);
Detail.num_particles = cfread_int(cfp);
Detail.num_stars = cfread_int(cfp);
Detail.shield_effects = cfread_int(cfp);
Detail.lighting = cfread_int(cfp);
Detail.targetview_model = cfread_int(cfp);
Detail.planets_suns = cfread_int(cfp);
Detail.weapon_extras = cfread_int(cfp);
}
void pilotfile::plr_write_settings()
{
startSection(Section::Settings);
// sound/voice/music
cfwrite_float(Master_sound_volume, cfp);
cfwrite_float(Master_event_music_volume, cfp);
cfwrite_float(Master_voice_volume, cfp);
cfwrite_int(Briefing_voice_enabled, cfp);
// skill level
cfwrite_int(Game_skill_level, cfp);
// input options
cfwrite_int(Use_mouse_to_fly, cfp);
cfwrite_int(Mouse_sensitivity, cfp);
cfwrite_int(Joy_sensitivity, cfp);
cfwrite_int(Dead_zone_size, cfp);
// detail
cfwrite_int(Detail.setting, cfp);
cfwrite_int(Detail.nebula_detail, cfp);
cfwrite_int(Detail.detail_distance, cfp);
cfwrite_int(Detail.hardware_textures, cfp);
cfwrite_int(Detail.num_small_debris, cfp);
cfwrite_int(Detail.num_particles, cfp);
cfwrite_int(Detail.num_stars, cfp);
cfwrite_int(Detail.shield_effects, cfp);
cfwrite_int(Detail.lighting, cfp);
cfwrite_int(Detail.targetview_model, cfp);
cfwrite_int(Detail.planets_suns, cfp);
cfwrite_int(Detail.weapon_extras, cfp);
endSection();
}
void pilotfile::plr_reset_data()
{
// internals
m_have_flags = false;
m_have_info = false;
m_data_invalid = false;
// set all the entries in the control config arrays to -1 (undefined)
control_config_clear();
// init stats
p->stats.init();
// reset scoring lists
all_time_stats.ship_kills.clear();
all_time_stats.medals_earned.clear();
multi_stats.ship_kills.clear();
multi_stats.medals_earned.clear();
// clear variables
p->variables.clear();
// reset techroom to defaults (CSG will override this, multi will use defaults)
tech_reset_to_default();
}
void pilotfile::plr_close()
{
if (cfp) {
cfclose(cfp);
cfp = NULL;
}
p = NULL;
filename = "";
ship_list.clear();
weapon_list.clear();
intel_list.clear();
medals_list.clear();
m_have_flags = false;
m_have_info = false;
}
bool pilotfile::load_player(const char *callsign, player *_p)
{
// if we're a standalone server in multiplayer, just fill in some bogus values
// since we don't have a pilot file
if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) {
Player->insignia_texture = -1;
strcpy_s(Player->callsign, NOX("Standalone"));
strcpy_s(Player->short_callsign, NOX("Standalone"));
return true;
}
// set player ptr first thing
p = _p;
if ( !p ) {
Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
p = &Players[Player_num];
}
filename = callsign;
filename += ".plr";
if ( filename.size() == 4 ) {
mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
return false;
}
cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
if ( !cfp ) {
mprintf(("PLR => Unable to open '%s' for reading!\n", filename.c_str()));
return false;
}
unsigned int plr_id = cfread_uint(cfp);
if (plr_id != PLR_FILE_ID) {
mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str()));
plr_close();
return false;
}
// version, now used
version = cfread_ubyte(cfp);
mprintf(("PLR => Loading '%s' with version %d...\n", filename.c_str(), version));
plr_reset_data();
// the point of all this: read in the PLR contents
while ( !cfeof(cfp) ) {
ushort section_id = cfread_ushort(cfp);
uint section_size = cfread_uint(cfp);
size_t start_pos = cftell(cfp);
// safety, to help protect against long reads
cf_set_max_read_len(cfp, section_size);
try {
switch (section_id) {
case Section::Flags:
mprintf(("PLR => Parsing: Flags...\n"));
m_have_flags = true;
plr_read_flags();
break;
case Section::Info:
mprintf(("PLR => Parsing: Info...\n"));
m_have_info = true;
plr_read_info();
break;
case Section::Variables:
mprintf(("PLR => Parsing: Variables...\n"));
plr_read_variables();
break;
case Section::HUD:
mprintf(("PLR => Parsing: HUD...\n"));
plr_read_hud();
break;
case Section::Scoring:
mprintf(("PLR => Parsing: Scoring...\n"));
plr_read_stats();
break;
case Section::ScoringMulti:
mprintf(("PLR => Parsing: ScoringMulti...\n"));
plr_read_stats_multi();
break;
case Section::Multiplayer:
mprintf(("PLR => Parsing: Multiplayer...\n"));
plr_read_multiplayer();
break;
case Section::Controls:
mprintf(("PLR => Parsing: Controls...\n"));
plr_read_controls();
break;
case Section::Settings:
mprintf(("PLR => Parsing: Settings...\n"));
plr_read_settings();
break;
default:
mprintf(("PLR => Skipping unknown section 0x%04x!\n", section_id));
break;
}
} catch (cfile::max_read_length &msg) {
// read to max section size, move to next section, discarding
// extra/unknown data
mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what()));
} catch (const char *err) {
mprintf(("PLR => ERROR: %s\n", err));
plr_close();
return false;
}
// reset safety catch
cf_set_max_read_len(cfp, 0);
// skip to next section (if not already there)
size_t offset_pos = (start_pos + section_size) - cftell(cfp);
if (offset_pos) {
cfseek(cfp, offset_pos, CF_SEEK_CUR);
mprintf(("PLR => WARNING: Advancing to the next section. " SIZE_T_ARG " bytes were skipped!\n", offset_pos));
}
}
// restore the callsign into the Player structure
strcpy_s(p->callsign, callsign);
// restore the truncated callsign into Player structure
pilot_set_short_callsign(p, SHORT_CALLSIGN_PIXEL_W);
player_set_squad_bitmap(p, p->m_squad_filename, true);
hud_squadmsg_save_keys();
// set last pilot
os_config_write_string(NULL, "LastPlayer", (char*)callsign);
mprintf(("PLR => Loading complete!\n"));
// cleanup and return
plr_close();
return true;
}
bool pilotfile::save_player(player *_p)
{
// never save a pilot file for the standalone server in multiplayer
if ( (Game_mode & GM_MULTIPLAYER) && (Game_mode & GM_STANDALONE_SERVER) ) {
return false;
}
// set player ptr first thing
p = _p;
if ( !p ) {
Assert( (Player_num >= 0) && (Player_num < MAX_PLAYERS) );
p = &Players[Player_num];
}
if ( !strlen(p->callsign) ) {
return false;
}
filename = p->callsign;
filename += ".plr";
if ( filename.size() == 4 ) {
mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
return false;
}
// open it, hopefully...
cfp = cfopen((char*)filename.c_str(), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS);
if ( !cfp ) {
mprintf(("PLR => Unable to open '%s' for saving!\n", filename.c_str()));
return false;
}
// header and version
cfwrite_int(PLR_FILE_ID, cfp);
cfwrite_ubyte(PLR_VERSION, cfp);
mprintf(("PLR => Saving '%s' with version %d...\n", filename.c_str(), (int)PLR_VERSION));
// flags and info sections go first
mprintf(("PLR => Saving: Flags...\n"));
plr_write_flags();
mprintf(("PLR => Saving: Info...\n"));
plr_write_info();
// everything else is next, not order specific
mprintf(("PLR => Saving: Scoring...\n"));
plr_write_stats();
mprintf(("PLR => Saving: ScoringMulti...\n"));
plr_write_stats_multi();
mprintf(("PLR => Saving: HUD...\n"));
plr_write_hud();
mprintf(("PLR => Saving: Variables...\n"));
plr_write_variables();
mprintf(("PLR => Saving: Multiplayer...\n"));
plr_write_multiplayer();
mprintf(("PLR => Saving: Controls...\n"));
plr_write_controls();
mprintf(("PLR => Saving: Settings...\n"));
plr_write_settings();
// Done!
mprintf(("PLR => Saving complete!\n"));
plr_close();
return true;
}
bool pilotfile::verify(const char *fname, int *rank, char *valid_language)
{
player t_plr;
// set player ptr first thing
p = &t_plr;
filename = fname;
if ( filename.size() == 4 ) {
mprintf(("PLR => Invalid filename '%s'!\n", filename.c_str()));
return false;
}
cfp = cfopen((char*)filename.c_str(), "rb", CFILE_NORMAL, CF_TYPE_PLAYERS);
if ( !cfp ) {
mprintf(("PLR => Unable to open '%s'!\n", filename.c_str()));
return false;
}
unsigned int plr_id = cfread_uint(cfp);
if (plr_id != PLR_FILE_ID) {
mprintf(("PLR => Invalid header id for '%s'!\n", filename.c_str()));
plr_close();
return false;
}
// version, now used
version = cfread_ubyte(cfp);
mprintf(("PLR => Verifying '%s' with version %d...\n", filename.c_str(), (int)version));
// the point of all this: read in the PLR contents
while ( !(m_have_flags && m_have_info) && !cfeof(cfp) ) {
ushort section_id = cfread_ushort(cfp);
uint section_size = cfread_uint(cfp);
size_t start_pos = cftell(cfp);
// safety, to help protect against long reads
cf_set_max_read_len(cfp, section_size);
try {
switch (section_id) {
case Section::Flags:
mprintf(("PLR => Parsing: Flags...\n"));
m_have_flags = true;
plr_read_flags();
break;
// now reading the Info section to get the campaign
// and be able to lookup the campaign rank
case Section::Info:
mprintf(("PLR => Parsing: Info...\n"));
m_have_info = true;
plr_read_info();
break;
default:
break;
}
} catch (cfile::max_read_length &msg) {
// read to max section size, move to next section, discarding
// extra/unknown data
mprintf(("PLR => (0x%04x) %s\n", section_id, msg.what()));
} catch (const char *err) {
mprintf(("PLR => ERROR: %s\n", err));
plr_close();
return false;
}
// reset safety catch
cf_set_max_read_len(cfp, 0);
// skip to next section (if not already there)
size_t offset_pos = (start_pos + section_size) - cftell(cfp);
if (offset_pos) {
mprintf(("PLR => Warning: (0x%04x) Short read, information may have been lost!\n", section_id));
cfseek(cfp, offset_pos, CF_SEEK_CUR);
}
}
if (valid_language) {
strncpy(valid_language, p->language, sizeof(p->language));
}
// need to cleanup early to ensure everything is OK for use in the CSG next
// also means we can't use *p from now on, use t_plr instead for a few vars
plr_close();
if (rank) {
// maybe get the rank from the CSG
if ( !(Game_mode & GM_MULTIPLAYER) ) {
// build the csg filename
// since filename/fname was validated above, perform less safety checks here
filename = fname;
filename = filename.replace(filename.find_last_of('.')+1,filename.npos, t_plr.current_campaign);
filename.append(".csg");
if (!this->get_csg_rank(rank)) {
// if we failed to get the csg rank, default to multi rank
*rank = t_plr.stats.rank;
}
} else {
// if the CSG isn't valid, or for multi, use this rank
*rank = t_plr.stats.rank;
}
}
mprintf(("PLR => Verifying complete!\n"));
return true;
}