with older xlogfiles.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1093 c06c8d41-db1a-0410-9941-cceddc491573
TAVHZJPVNJBZR7CUURAOYNDZPNVQ3AGHTXDEP5K4JGYETBLQJDRQC
GNJGG33CNP6IWUW4V2JKIFAC5N43TP5MX4PZOTXROBYZVXQEAJLAC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
LY3EVV7EUNULYH3WSDZDLZYPJM4LHLOJTT3WETKYIJTKUP7UQPZAC
RISMOCQM6BKK4XSIRKYLOBB2UPDYJNDAL6OGIIR5GGNZQAK5YSZAC
}
std::string replace_all(std::string s,
const std::string &find,
const std::string &repl)
{
std::string::size_type start = 0;
std::string::size_type found;
while ((found = s.find(find, start)) != std::string::npos)
{
s.replace( found, find.length(), repl );
start = found + repl.length();
}
return (s);
bool verbose = false );
bool verbose = false );
class xlog_fields
{
public:
xlog_fields();
xlog_fields(const std::string &line);
void init(const std::string &line);
std::string xlog_line() const;
void add_field(const std::string &key,
const char *format, ...);
std::string str_field(const std::string &) const;
int int_field(const std::string &) const;
long long_field(const std::string &) const;
private:
std::string xlog_unescape(const std::string &) const;
std::string xlog_escape(const std::string &) const;
void map_fields() const;
std::string::size_type next_separator(const std::string &s,
std::string::size_type start) const;
std::vector<std::string> split_fields(const std::string &s) const;
private:
typedef std::vector< std::pair<std::string, std::string> > xl_fields;
typedef std::map<std::string, std::string> xl_map;
xl_fields fields;
mutable xl_map fieldmap;
};
struct scorefile_entry
{
public:
char version;
char release;
long points;
std::string name;
long uid; // for multiuser systems
char race;
char cls;
std::string race_class_name; // overrides race & cls if non-empty.
char lvl; // player level.
char best_skill; // best skill #
char best_skill_lvl; // best skill level
int death_type;
int death_source; // 0 or monster TYPE
int mon_num; // sigh...
std::string death_source_name; // overrides death_source
std::string auxkilldata; // weapon wielded, spell cast, etc
char dlvl; // dungeon level (relative)
char level_type; // what kind of level died on..
char branch; // dungeon branch
int final_hp; // actual current HPs (probably <= 0)
int final_max_hp; // net HPs after rot
int final_max_max_hp; // gross HPs before rot
int damage; // damage of final attack
int str; // final str (useful for nickname)
int intel; // final int
int dex; // final dex (useful for nickname)
int god; // god
int piety; // piety
int penance; // penance
char wiz_mode; // character used wiz mode
time_t birth_time; // start time of character
time_t death_time; // end time of character
long real_time; // real playing time in seconds
long num_turns; // number of turns taken
int num_diff_runes; // number of rune types in inventory
int num_runes; // total number of runes in inventory
public:
scorefile_entry();
scorefile_entry(int damage, int death_source, int death_type,
const char *aux, bool death_cause_only = false);
scorefile_entry(const scorefile_entry &se);
scorefile_entry &operator = (const scorefile_entry &other);
void init_death_cause(int damage, int death_source, int death_type,
const char *aux);
void init();
void reset();
enum death_desc_verbosity {
DDV_TERSE,
DDV_ONELINE,
DDV_NORMAL,
DDV_VERBOSE,
DDV_LOGVERBOSE // Semi-verbose for logging purposes
};
std::string raw_string() const;
bool parse(const std::string &line);
std::string hiscore_line(death_desc_verbosity verbosity) const;
std::string character_description(death_desc_verbosity) const;
// Full description of death: Killed by an xyz wielding foo
std::string death_description(death_desc_verbosity) const;
std::string death_place(death_desc_verbosity) const;
std::string game_time(death_desc_verbosity) const;
private:
mutable std::auto_ptr<xlog_fields> fields;
private:
std::string single_cdesc() const;
std::string strip_article_a(const std::string &s) const;
std::string terse_missile_cause() const;
std::string terse_missile_name() const;
std::string terse_beam_cause() const;
std::string terse_wild_magic() const;
std::string terse_trap() const;
const char *damage_verb() const;
const char *death_source_desc() const;
std::string damage_string(bool terse = false) const;
bool parse_obsolete_scoreline(const std::string &line);
bool parse_scoreline(const std::string &line);
void init_with_fields();
void add_auxkill_field() const;
void set_score_fields() const;
std::string short_kill_message() const;
std::string long_kill_message() const;
std::string make_oneline(const std::string &s) const;
void init_from(const scorefile_entry &other);
int kludge_branch(int branch_01) const;
};
}
// xlogfile escape: s/\\/\\\\/g, s/|/\\|/g, s/:/|/g,
std::string scorefile_entry::xlog_escape(const std::string &s) const
{
return
replace_all_of(
replace_all_of(
replace_all_of(s, "\\", "\\\\"),
"|", "\\|" ),
":", "|" );
}
// xlogfile unescape: s/\\(.)/$1/g, s/|/:/g
std::string scorefile_entry::xlog_unescape(const std::string &s) const
{
std::string unesc = s;
bool escaped = false;
for (int i = 0, size = unesc.size(); i < size; ++i)
{
const char c = unesc[i];
if (escaped)
{
escaped = false;
continue;
}
if (c == '|')
unesc[i] = ':';
else if (c == '\\')
{
escaped = true;
unesc.erase(i--, 1);
size--;
}
}
return (unesc);
std::string line;
for (int i = 0, size = fields->size(); i < size; ++i)
{
const std::pair<std::string, std::string> &f = (*fields)[i];
// Don't write empty fields.
if (f.second.empty())
continue;
if (!line.empty())
line += ":";
std::vector<std::string> rawfields = split_string(":", line);
fields.reset(new hs_fields);
for (int i = 0, size = rawfields.size(); i < size; ++i)
{
const std::string field = rawfields[i];
std::string::size_type st = field.find('=');
if (st == std::string::npos)
continue;
fields->push_back(
std::pair<std::string, std::string>(
field.substr(0, st),
xlog_unescape(field.substr(st + 1)) ) );
}
fields.reset(new xlog_fields(line));
}
void scorefile_entry::add_field(const std::string &key,
const char *format,
...) const
{
char buf[400];
va_list args;
va_start(args, format);
vsnprintf(buf, sizeof buf, format, args);
va_end(args);
fields->push_back(
std::pair<std::string, std::string>( key, buf ) );
}
void scorefile_entry::add_auxkill_field() const
{
add_field("kaux", "%s", auxkilldata.c_str());
void scorefile_entry::read_auxkill_field()
{
auxkilldata = str_field("kaux");
}
std::string scorefile_entry::str_field(const std::string &s) const
{
hs_map::const_iterator i = fieldmap->find(s);
if (i == fieldmap->end())
return ("");
return i->second;
}
int scorefile_entry::int_field(const std::string &s) const
{
std::string field = str_field(s);
return atoi(field.c_str());
}
long scorefile_entry::long_field(const std::string &s) const
{
std::string field = str_field(s);
return atol(field.c_str());
}
void scorefile_entry::map_fields()
{
fieldmap.reset(new hs_map);
for (int i = 0, size = fields->size(); i < size; ++i)
{
const std::pair<std::string, std::string> f = (*fields)[i];
(*fieldmap)[f.first] = f.second;
}
}
best_skill = str_to_skill(str_field("sk"));
best_skill_lvl = int_field("sklev");
death_type = str_to_kill_method(str_field("ktyp"));
death_source_name = str_field("killer");
best_skill = str_to_skill(fields->str_field("sk"));
best_skill_lvl = fields->int_field("sklev");
death_type = str_to_kill_method(fields->str_field("ktyp"));
death_source_name = fields->str_field("killer");
auxkilldata = fields->str_field("kaux");
branch = str_to_branch(fields->str_field("br"));
dlvl = fields->int_field("lvl");
level_type = str_to_level_area_type(fields->str_field("ltyp"));
read_auxkill_field();
branch = str_to_branch(str_field("br"));
dlvl = int_field("lvl");
level_type = str_to_level_area_type(str_field("ltyp"));
final_hp = fields->int_field("hp");
final_max_hp = fields->int_field("mhp");
final_max_max_hp = fields->int_field("mmhp");
damage = fields->int_field("dam");
str = fields->int_field("str");
intel = fields->int_field("int");
dex = fields->int_field("dex");
final_hp = int_field("hp");
final_max_hp = int_field("mhp");
final_max_max_hp = int_field("mmhp");
damage = int_field("dam");
str = int_field("str");
intel = int_field("int");
dex = int_field("dex");
god = str_to_god(str_field("god"));
piety = int_field("piety");
penance = int_field("pen");
wiz_mode = int_field("wiz");
birth_time = parse_time(str_field("start"));
death_time = parse_time(str_field("end"));
real_time = long_field("dur");
num_turns = long_field("turn");
num_diff_runes = int_field("urune");
num_runes = int_field("nrune");
god = str_to_god(fields->str_field("god"));
piety = fields->int_field("piety");
penance = fields->int_field("pen");
wiz_mode = fields->int_field("wiz");
birth_time = parse_time(fields->str_field("start"));
death_time = parse_time(fields->str_field("end"));
real_time = fields->long_field("dur");
num_turns = fields->long_field("turn");
num_diff_runes = fields->int_field("urune");
num_runes = fields->int_field("nrune");
add_field("v", VER_NUM);
add_field("lv", SCORE_VERSION);
add_field("sc", "%ld", points);
add_field("name", "%s", name.c_str());
add_field("uid", "%d", uid);
add_field("race", "%s", species_name(race, lvl));
add_field("cls", "%s", get_class_name(cls));
add_field("xl", "%d", lvl);
add_field("sk", "%s", skill_name(best_skill));
add_field("sklev", "%d", best_skill_lvl);
add_field("title", "%s", skill_title( best_skill, best_skill_lvl,
fields->add_field("v", VER_NUM);
fields->add_field("lv", SCORE_VERSION);
fields->add_field("sc", "%ld", points);
fields->add_field("name", "%s", name.c_str());
fields->add_field("uid", "%d", uid);
fields->add_field("race", "%s", species_name(race, lvl));
fields->add_field("cls", "%s", get_class_name(cls));
fields->add_field("xl", "%d", lvl);
fields->add_field("sk", "%s", skill_name(best_skill));
fields->add_field("sklev", "%d", best_skill_lvl);
fields->add_field("title", "%s", skill_title( best_skill, best_skill_lvl,
add_field("br", "%s", short_branch_name(branch));
add_field("lvl", "%d", dlvl);
add_field("ltyp", "%s", level_area_type_name(level_type));
fields->add_field("br", "%s", short_branch_name(branch));
fields->add_field("lvl", "%d", dlvl);
fields->add_field("ltyp", "%s", level_area_type_name(level_type));
add_field("hp", "%d", final_hp);
add_field("mhp", "%d", final_max_hp);
add_field("mmhp", "%d", final_max_max_hp);
add_field("dam", "%d", damage);
add_field("str", "%d", str);
add_field("int", "%d", intel);
add_field("dex", "%d", dex);
fields->add_field("hp", "%d", final_hp);
fields->add_field("mhp", "%d", final_max_hp);
fields->add_field("mmhp", "%d", final_max_max_hp);
fields->add_field("dam", "%d", damage);
fields->add_field("str", "%d", str);
fields->add_field("int", "%d", intel);
fields->add_field("dex", "%d", dex);
add_field("start", "%s", make_date_string(birth_time).c_str());
add_field("end", "%s", make_date_string(death_time).c_str());
add_field("dur", "%ld", real_time);
add_field("turn", "%ld", num_turns);
fields->add_field("start", "%s", make_date_string(birth_time).c_str());
fields->add_field("end", "%s", make_date_string(death_time).c_str());
fields->add_field("dur", "%ld", real_time);
fields->add_field("turn", "%ld", num_turns);
}
//////////////////////////////////////////////////////////////////////////////
// xlog_fields
xlog_fields::xlog_fields() : fields(), fieldmap()
{
}
xlog_fields::xlog_fields(const std::string &line) : fields(), fieldmap()
{
init(line);
}
std::string::size_type
xlog_fields::next_separator(const std::string &s,
std::string::size_type start) const
{
std::string::size_type p = s.find(':', start);
if (p != std::string::npos && p < s.length() - 1 && s[p + 1] == ':')
return next_separator(s, p + 2);
return (p);
}
std::vector<std::string>
xlog_fields::split_fields(const std::string &s) const
{
std::string::size_type start = 0, end = 0;
std::vector<std::string> fs;
for ( ; (end = next_separator(s, start)) != std::string::npos;
start = end + 1 )
{
fs.push_back( s.substr(start, end - start) );
}
if (start < s.length())
fs.push_back( s.substr(start) );
return (fs);
}
void xlog_fields::init(const std::string &line)
{
std::vector<std::string> rawfields = split_fields(line);
for (int i = 0, size = rawfields.size(); i < size; ++i)
{
const std::string field = rawfields[i];
std::string::size_type st = field.find('=');
if (st == std::string::npos)
continue;
fields.push_back(
std::pair<std::string, std::string>(
field.substr(0, st),
xlog_unescape(field.substr(st + 1)) ) );
}
map_fields();
}
// xlogfile escape: s/:/::/g
std::string xlog_fields::xlog_escape(const std::string &s) const
{
return replace_all(s, ":", "::");
}
// xlogfile unescape: s/::/:/g
std::string xlog_fields::xlog_unescape(const std::string &s) const
{
return replace_all(s, "::", ":");
}
void xlog_fields::add_field(const std::string &key,
const char *format,
...)
{
char buf[500];
va_list args;
va_start(args, format);
vsnprintf(buf, sizeof buf, format, args);
va_end(args);
fields.push_back(
std::pair<std::string, std::string>( key, buf ) );
fieldmap[key] = buf;
std::string xlog_fields::str_field(const std::string &s) const
{
xl_map::const_iterator i = fieldmap.find(s);
if (i == fieldmap.end())
return ("");
return i->second;
}
int xlog_fields::int_field(const std::string &s) const
{
std::string field = str_field(s);
return atoi(field.c_str());
}
long xlog_fields::long_field(const std::string &s) const
{
std::string field = str_field(s);
return atol(field.c_str());
}
void xlog_fields::map_fields() const
{
fieldmap.clear();
for (int i = 0, size = fields.size(); i < size; ++i)
{
const std::pair<std::string, std::string> &f = fields[i];
fieldmap[f.first] = f.second;
}
}
std::string xlog_fields::xlog_line() const
{
std::string line;
for (int i = 0, size = fields.size(); i < size; ++i)
{
const std::pair<std::string, std::string> &f = fields[i];
// Don't write empty fields.
if (f.second.empty())
continue;
if (!line.empty())
line += ":";
line += f.first;
line += "=";
line += xlog_escape(f.second);
}
return (line);
}
};
struct scorefile_entry
{
public:
char version;
char release;
long points;
std::string name;
long uid; // for multiuser systems
char race;
char cls;
std::string race_class_name; // overrides race & cls if non-empty.
char lvl; // player level.
char best_skill; // best skill #
char best_skill_lvl; // best skill level
int death_type;
int death_source; // 0 or monster TYPE
int mon_num; // sigh...
std::string death_source_name; // overrides death_source
std::string auxkilldata; // weapon wielded, spell cast, etc
char dlvl; // dungeon level (relative)
char level_type; // what kind of level died on..
char branch; // dungeon branch
int final_hp; // actual current HPs (probably <= 0)
int final_max_hp; // net HPs after rot
int final_max_max_hp; // gross HPs before rot
int damage; // damage of final attack
int str; // final str (useful for nickname)
int intel; // final int
int dex; // final dex (useful for nickname)
int god; // god
int piety; // piety
int penance; // penance
char wiz_mode; // character used wiz mode
time_t birth_time; // start time of character
time_t death_time; // end time of character
long real_time; // real playing time in seconds
long num_turns; // number of turns taken
int num_diff_runes; // number of rune types in inventory
int num_runes; // total number of runes in inventory
public:
scorefile_entry();
scorefile_entry(int damage, int death_source, int death_type,
const char *aux, bool death_cause_only = false);
scorefile_entry(const scorefile_entry &se);
scorefile_entry &operator = (const scorefile_entry &other);
void init_death_cause(int damage, int death_source, int death_type,
const char *aux);
void init();
void reset();
enum death_desc_verbosity {
DDV_TERSE,
DDV_ONELINE,
DDV_NORMAL,
DDV_VERBOSE,
DDV_LOGVERBOSE // Semi-verbose for logging purposes
};
std::string raw_string() const;
bool parse(const std::string &line);
std::string hiscore_line(death_desc_verbosity verbosity) const;
std::string character_description(death_desc_verbosity) const;
// Full description of death: Killed by an xyz wielding foo
std::string death_description(death_desc_verbosity) const;
std::string death_place(death_desc_verbosity) const;
std::string game_time(death_desc_verbosity) const;
private:
typedef std::vector< std::pair<std::string, std::string> > hs_fields;
typedef std::map<std::string, std::string> hs_map;
mutable std::auto_ptr<hs_fields> fields;
mutable std::auto_ptr<hs_map> fieldmap;
private:
std::string single_cdesc() const;
std::string strip_article_a(const std::string &s) const;
std::string terse_missile_cause() const;
std::string terse_missile_name() const;
std::string terse_beam_cause() const;
std::string terse_wild_magic() const;
std::string terse_trap() const;
const char *damage_verb() const;
const char *death_source_desc() const;
std::string damage_string(bool terse = false) const;
bool parse_obsolete_scoreline(const std::string &line);
bool parse_scoreline(const std::string &line);
void init_with_fields();
void add_field(const std::string &key,
const char *format, ...) const;
void add_auxkill_field() const;
void set_score_fields() const;
std::string short_kill_message() const;
std::string long_kill_message() const;
std::string make_oneline(const std::string &s) const;
std::string str_field(const std::string &key) const;
int int_field(const std::string &key) const;
long long_field(const std::string &key) const;
std::string xlog_escape(const std::string &s) const;
std::string xlog_unescape(const std::string &s) const;
void read_auxkill_field();
void map_fields();
void init_from(const scorefile_entry &other);
int kludge_branch(int branch_01) const;