Files
fs2open.github.com/code/pilotfile/plr.cpp
T
Goober5000 7248acc004 use a copy method rather than memcpy to clone stats (Mantis #2922)
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@9813 387891d4-d844-0410-90c0-e4c51a9137d3
2013-09-26 18:51:35 +10:00

1083 lines
28 KiB
C++

#include "globalincs/pstypes.h"
#include "pilotfile/pilotfile.h"
#include "playerman/player.h"
#include "ship/ship.h"
#include "menuui/techmenu.h"
#include "weapon/weapon.h"
#include "hud/hudconfig.h"
#include "stats/medals.h"
#include "hud/hudsquadmsg.h"
#include "gamesnd/eventmusic.h"
#include "osapi/osregistry.h"
#include "sound/audiostr.h"
#include "io/joy.h"
#include "io/mouse.h"
#include "network/multi.h"
#include "freespace2/freespace.h"
#include "playerman/managepilot.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)
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
}
}
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)
cfwrite_int(p->stats.rank, cfp);
// What game mode we were in last on this pilot
cfwrite_int(p->player_was_multi, 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_VMT) {
Multi_options_g.protocol = NET_TCP;
}
Assert( (Multi_options_g.protocol == NET_IPX) || (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;
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, should be able to just ignore it
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. %i 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)
{
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, should be able to just ignore it
ubyte plr_ver = cfread_ubyte(cfp);
mprintf(("PLR => Verifying '%s' with version %d...\n", filename.c_str(), (int)plr_ver));
// the point of all this: read in the PLR contents
while ( !m_have_flags && !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;
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 (rank) {
*rank = p->stats.rank;
}
mprintf(("PLR => Verifying complete!\n"));
// cleanup and return
plr_close();
return true;
}