mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
In other words, a pilot can only be used in the same language it was created with. Checks both the initial selection screen and in the barracks. Also fixes issue with PLR version being ignored in pilotfile::verify() git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@10817 387891d4-d844-0410-90c0-e4c51a9137d3
1098 lines
28 KiB
C++
1098 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"
|
|
#include "localization/localize.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
|
|
}
|
|
|
|
// 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)
|
|
cfwrite_int(p->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_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 __attribute__((__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. %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, 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 && !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;
|
|
}
|
|
if (valid_language) {
|
|
strncpy(valid_language, p->language, sizeof(p->language));
|
|
}
|
|
|
|
mprintf(("PLR => Verifying complete!\n"));
|
|
|
|
// cleanup and return
|
|
plr_close();
|
|
|
|
return true;
|
|
}
|
|
|