summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/AppHdr.h39
-rw-r--r--crawl-ref/source/acr.cc2
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/externs.h54
-rw-r--r--crawl-ref/source/fight.cc9
-rw-r--r--crawl-ref/source/hiscores.cc1208
-rw-r--r--crawl-ref/source/initfile.cc6
-rw-r--r--crawl-ref/source/misc.cc11
-rw-r--r--crawl-ref/source/misc.h1
-rw-r--r--crawl-ref/source/mon-data.h2
-rw-r--r--crawl-ref/source/monstuff.cc21
-rw-r--r--crawl-ref/source/mstuff2.cc2
-rw-r--r--crawl-ref/source/player.cc38
-rw-r--r--crawl-ref/source/player.h3
-rw-r--r--crawl-ref/source/skills2.cc9
-rw-r--r--crawl-ref/source/skills2.h2
-rw-r--r--crawl-ref/source/tags.cc15
-rw-r--r--crawl-ref/source/tags.h2
-rw-r--r--crawl-ref/source/travel.h14
-rw-r--r--crawl-ref/source/version.h5
20 files changed, 826 insertions, 621 deletions
diff --git a/crawl-ref/source/AppHdr.h b/crawl-ref/source/AppHdr.h
index f68fdd97c7..45849093a7 100644
--- a/crawl-ref/source/AppHdr.h
+++ b/crawl-ref/source/AppHdr.h
@@ -84,20 +84,6 @@
//
// #define DGAMELAUNCH
- // DGL_CLEAR_SCREEN specifies the escape sequence to use to clear
- // the screen (used only when DGAMELAUNCH is defined). We make no
- // attempt to discover an appropriate escape sequence for the
- // term, assuming that dgamelaunch admins can adjust this as
- // needed.
- //
- // Why this is necessary: dgamelaunch's ttyplay initialises
- // playback by jumping to the last screen clear and playing back
- // from there. For that to work, ttyplay must be able to recognise
- // the clear screen sequence, and ncurses clear()+refresh()
- // doesn't do the trick.
- //
- #define DGL_CLEAR_SCREEN "\033[2J"
-
#define MULTIUSER
#define USE_UNIX_SIGNALS
@@ -199,6 +185,31 @@
#error Missing platform #define or unsupported compiler.
#endif
+// =========================================================================
+// Defines for dgamelaunch-specific things.
+// =========================================================================
+
+#ifdef DGAMELAUNCH
+ // DGL_CLEAR_SCREEN specifies the escape sequence to use to clear
+ // the screen (used only when DGAMELAUNCH is defined). We make no
+ // attempt to discover an appropriate escape sequence for the
+ // term, assuming that dgamelaunch admins can adjust this as
+ // needed.
+ //
+ // Why this is necessary: dgamelaunch's ttyplay initialises
+ // playback by jumping to the last screen clear and playing back
+ // from there. For that to work, ttyplay must be able to recognise
+ // the clear screen sequence, and ncurses clear()+refresh()
+ // doesn't do the trick.
+ //
+ #define DGL_CLEAR_SCREEN "\033[2J"
+
+ // If defined, the hiscores code dumps preformatted verbose and terse
+ // death message strings in the logfile for the convenience of logfile
+ // parsers.
+ #define DGL_EXTENDED_LOGFILES
+
+#endif
// =========================================================================
// Debugging Defines
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index ed5b69385e..022a3ba037 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -210,7 +210,7 @@ int main( int argc, char *argv[] )
// now parse the args again, looking for everything else.
parse_args( argc, argv, false );
- if (Options.sc_entries != 0)
+ if (Options.sc_entries != 0 || !SysEnv.scorefile.empty())
{
hiscores_print_all( Options.sc_entries, Options.sc_format );
exit(0);
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 1655e98edc..9495c20fb1 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1684,7 +1684,9 @@ enum level_area_type // you.level_type
LEVEL_DUNGEON, // 0
LEVEL_LABYRINTH,
LEVEL_ABYSS,
- LEVEL_PANDEMONIUM
+ LEVEL_PANDEMONIUM,
+
+ NUM_LEVEL_AREA_TYPES
};
enum load_mode_type
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f3c2f261b0..c5d6b6f3f4 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -19,8 +19,8 @@
#include <vector>
#include <list>
#include <string>
-
#include <map>
+#include <memory>
#include <time.h>
@@ -721,6 +721,7 @@ public:
size_type body_size(int psize = PSIZE_TORSO, bool base = false) const;
int damage_type(int attk = -1);
int damage_brand(int attk = -1);
+ bool has_usable_claws() const;
item_def *weapon(int which_attack = -1);
item_def *shield();
@@ -1350,19 +1351,19 @@ public:
char version;
char release;
long points;
- char name[kNameLen];
+ std::string name;
long uid; // for multiuser systems
char race;
char cls;
- char race_class_name[5]; // overrides race & cls if non-null
+ 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...
- char death_source_name[40]; // overrides death_source
- char auxkilldata[ITEMNAME_SIZE]; // weapon wielded, spell cast, etc
+ 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
@@ -1388,7 +1389,10 @@ 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();
@@ -1398,29 +1402,63 @@ public:
DDV_TERSE,
DDV_ONELINE,
DDV_NORMAL,
- DDV_VERBOSE
+ 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;
};
extern const struct coord_def Compass[8];
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index defd36c88f..835bdee2d8 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -693,7 +693,6 @@ bool melee_attack::player_aux_unarmed()
}
unarmed_attack = "punch";
-
/* applied twice */
aux_damage = 5 + you.skills[SK_UNARMED_COMBAT] / 3;
@@ -702,6 +701,12 @@ bool melee_attack::player_aux_unarmed()
unarmed_attack = "slash";
aux_damage += 6;
}
+ else if (you.has_usable_claws())
+ {
+ unarmed_attack = "claw";
+ aux_damage += roll_dice(1, 3);
+ }
+
break;
/* To add more, add to while part of loop below as well */
@@ -1218,7 +1223,7 @@ int melee_attack::player_weapon_type_modify(int damage)
break;
case -1: // unarmed
- if (you.species == SP_TROLL || you.mutation[MUT_CLAWS])
+ if (you.damage_type() == DVORP_CLAWING)
{
if (damage < HIT_MED)
attack_verb = "claw";
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index 0c2f343896..2aa17937c2 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -35,6 +35,7 @@
#include "AppHdr.h"
#include "externs.h"
+#include "branch.h"
#include "hiscores.h"
#include "itemname.h"
#include "itemprop.h"
@@ -47,10 +48,13 @@
#include "shopping.h"
#include "stuff.h"
#include "tags.h"
+#include "version.h"
#include "view.h"
#include "skills2.h"
+#define SCORE_VERSION "0.1"
+
#ifdef MULTIUSER
// includes to get passwd file access:
#include <pwd.h>
@@ -68,21 +72,11 @@ static FILE *hs_open(const char *mode, const std::string &filename);
static void hs_close(FILE *handle, const char *mode,
const std::string &filename);
static bool hs_read(FILE *scores, scorefile_entry &dest);
-static void hs_parse_numeric(char *inbuf, scorefile_entry &dest);
-static void hs_parse_string(char *inbuf, scorefile_entry &dest);
static void hs_write(FILE *scores, scorefile_entry &entry);
-static void hs_nextstring(char *&inbuf, char *dest, size_t bufsize);
-static int hs_nextint(char *&inbuf);
-static long hs_nextlong(char *&inbuf);
-
-// functions dealing with old scorefile entries
-static void hs_parse_generic_1(char *&inbuf, char *outbuf, size_t outsz,
- const char *stopvalues);
-static void hs_parse_generic_2(char *&inbuf, char *outbuf, size_t outsz,
- const char *continuevalues);
-static void hs_stripblanks(char *buf);
-static void hs_search_death(char *inbuf, struct scorefile_entry &se);
-static void hs_search_where(char *inbuf, struct scorefile_entry &se);
+static void hs_nextstring(const char *&inbuf, char *dest, size_t bufsize);
+static int hs_nextint(const char *&inbuf);
+static long hs_nextlong(const char *&inbuf);
+static time_t parse_time(const std::string &st);
// file locking stuff
#ifdef USE_FILE_LOCKING
@@ -245,7 +239,10 @@ void hiscores_print_all(int display_count, int format)
if (!hs_read(scores, se))
break;
- hiscores_print_entry(se, entry, format, printf);
+ if (format == -1)
+ printf("%s\n", se.raw_string().c_str());
+ else
+ hiscores_print_entry(se, entry, format, printf);
}
hs_close( scores, "r", score_file_name() );
@@ -493,42 +490,31 @@ void hs_close( FILE *handle, const char *mode, const std::string &scores )
bool hs_read( FILE *scores, scorefile_entry &dest )
{
- char inbuf[600];
- int c = EOF;
+ char inbuf[1300];
+ if (!scores || feof(scores))
+ return (false);
memset(inbuf, 0, sizeof inbuf);
dest.reset();
- // get a character..
- if (scores != NULL)
- c = fgetc(scores);
-
- // check for NULL scores file or EOF
- if (scores == NULL || c == EOF)
- return false;
+ if (!fgets(inbuf, sizeof inbuf, scores))
+ return (false);
- // get a line - this is tricky. "Lines" come in three flavors:
- // 1) old-style lines which were 80 character blocks
- // 2) 4.0 pr1 through pr7 versions which were newline terminated
- // 3) 4.0 pr8 and onwards which are 'current' ASCII format, and
- // may exceed 80 characters!
-
- // put 'c' in first spot
- inbuf[0] = c;
-
- if (fgets(&inbuf[1], (c==':') ? (sizeof(inbuf) - 2) : 81, scores) == NULL)
- return false;
-
- // check type; lines starting with a colon are new-style scores.
- if (c == ':')
- hs_parse_numeric(inbuf, dest);
- else
- hs_parse_string(inbuf, dest);
+ return (dest.parse(inbuf));
+}
- return true;
+static std::string hs_nextstring(const char *&inbuf, size_t destsize = 800)
+{
+ char *buf = new char[destsize];
+ if (!buf)
+ return ("");
+ hs_nextstring(inbuf, buf, destsize);
+ const std::string res = buf;
+ delete [] buf;
+ return (res);
}
-static void hs_nextstring(char *&inbuf, char *dest, size_t destsize)
+static void hs_nextstring(const char *&inbuf, char *dest, size_t destsize)
{
ASSERT(destsize > 0);
@@ -554,7 +540,7 @@ static void hs_nextstring(char *&inbuf, char *dest, size_t destsize)
*p = 0;
}
-static int hs_nextint(char *&inbuf)
+static int hs_nextint(const char *&inbuf)
{
char num[20];
hs_nextstring(inbuf, num, sizeof num);
@@ -562,7 +548,7 @@ static int hs_nextint(char *&inbuf)
return (num[0] == 0 ? 0 : atoi(num));
}
-static long hs_nextlong(char *&inbuf)
+static long hs_nextlong(const char *&inbuf)
{
char num[20];
hs_nextstring(inbuf, num, sizeof num);
@@ -575,134 +561,39 @@ static int val_char( char digit )
return (digit - '0');
}
-static time_t hs_nextdate(char *&inbuf)
+static time_t hs_nextdate(const char *&inbuf)
{
char buff[20];
- struct tm date;
-
hs_nextstring(inbuf, buff, sizeof buff);
- if (strlen( buff ) < 15)
- return (static_cast<time_t>(0));
-
- date.tm_year = val_char( buff[0] ) * 1000 + val_char( buff[1] ) * 100
- + val_char( buff[2] ) * 10 + val_char( buff[3] ) - 1900;
-
- date.tm_mon = val_char( buff[4] ) * 10 + val_char( buff[5] );
- date.tm_mday = val_char( buff[6] ) * 10 + val_char( buff[7] );
- date.tm_hour = val_char( buff[8] ) * 10 + val_char( buff[9] );
- date.tm_min = val_char( buff[10] ) * 10 + val_char( buff[11] );
- date.tm_sec = val_char( buff[12] ) * 10 + val_char( buff[13] );
- date.tm_isdst = (buff[14] == 'D');
-
- return (mktime( &date ));
+ return parse_time(buff);
}
-static void hs_parse_numeric(char *inbuf, struct scorefile_entry &se)
+static time_t parse_time(const std::string &st)
{
- se.version = hs_nextint(inbuf);
- se.release = hs_nextint(inbuf);
-
- // this would be a good point to check for version numbers and branch
- // appropriately
-
- // acceptable versions are 0 (converted from old hiscore format) and 4
- if (se.version != 0 && se.version != 4)
- return;
-
- se.points = hs_nextlong(inbuf);
-
- hs_nextstring(inbuf, se.name, sizeof se.name);
-
- se.uid = hs_nextlong(inbuf);
- se.race = hs_nextint(inbuf);
- se.cls = hs_nextint(inbuf);
-
- hs_nextstring(inbuf, se.race_class_name, sizeof se.race_class_name);
-
- se.lvl = hs_nextint(inbuf);
- se.best_skill = hs_nextint(inbuf);
- se.best_skill_lvl = hs_nextint(inbuf);
- se.death_type = hs_nextint(inbuf);
- se.death_source = hs_nextint(inbuf);
- se.mon_num = hs_nextint(inbuf);
-
- hs_nextstring(inbuf, se.death_source_name, sizeof se.death_source_name);
-
- // To try and keep the scorefile backwards compatible,
- // we'll branch on version > 4.0 to read the auxkilldata
- // text field.
- if (se.version == 4 && se.release >= 1)
- hs_nextstring( inbuf, se.auxkilldata, sizeof se.auxkilldata );
- else
- se.auxkilldata[0] = 0;
-
- se.dlvl = hs_nextint(inbuf);
- se.level_type = hs_nextint(inbuf);
- se.branch = hs_nextint(inbuf);
-
- // Trying to fix some bugs that have been around since at
- // least pr19, if not longer. From now on, dlvl should
- // be calculated on death and need no further modification.
- if (se.version < 4 || se.release < 2)
- {
- if (se.level_type == LEVEL_DUNGEON)
- {
- if (se.branch == BRANCH_MAIN_DUNGEON)
- se.dlvl += 1;
- else if (se.branch < BRANCH_ORCISH_MINES) // ie the hells
- se.dlvl -= 1;
- }
- }
+ struct tm date;
- se.final_hp = hs_nextint(inbuf);
- if (se.version == 4 && se.release >= 2)
- {
- se.final_max_hp = hs_nextint(inbuf);
- se.final_max_max_hp = hs_nextint(inbuf);
- se.damage = hs_nextint(inbuf);
- se.str = hs_nextint(inbuf);
- se.intel = hs_nextint(inbuf);
- se.dex = hs_nextint(inbuf);
- se.god = hs_nextint(inbuf);
- se.piety = hs_nextint(inbuf);
- se.penance = hs_nextint(inbuf);
- }
- else
- {
- se.final_max_hp = -1;
- se.final_max_max_hp = -1;
- se.damage = -1;
- se.str = -1;
- se.intel = -1;
- se.dex = -1;
- se.god = -1;
- se.piety = -1;
- se.penance = -1;
- }
+ if (st.length() < 15)
+ return (static_cast<time_t>(0));
- se.wiz_mode = hs_nextint(inbuf);
+ date.tm_year = val_char( st[0] ) * 1000 + val_char( st[1] ) * 100
+ + val_char( st[2] ) * 10 + val_char( st[3] ) - 1900;
- se.birth_time = hs_nextdate(inbuf);
- se.death_time = hs_nextdate(inbuf);
+ date.tm_mon = val_char( st[4] ) * 10 + val_char( st[5] );
+ date.tm_mday = val_char( st[6] ) * 10 + val_char( st[7] );
+ date.tm_hour = val_char( st[8] ) * 10 + val_char( st[9] );
+ date.tm_min = val_char( st[10] ) * 10 + val_char( st[11] );
+ date.tm_sec = val_char( st[12] ) * 10 + val_char( st[13] );
+ date.tm_isdst = (st[14] == 'D');
- if (se.version == 4 && se.release >= 2)
- {
- se.real_time = hs_nextint(inbuf);
- se.num_turns = hs_nextint(inbuf);
- }
- else
- {
- se.real_time = -1;
- se.num_turns = -1;
- }
-
- se.num_diff_runes = hs_nextint(inbuf);
- se.num_runes = hs_nextint(inbuf);
+ return (mktime( &date ));
}
static void hs_write( FILE *scores, scorefile_entry &se )
{
+ fprintf(scores, "%s\n", se.raw_string().c_str());
+
+ /*
char buff[80]; // should be more than enough for date stamps
se.version = 4;
@@ -730,380 +621,577 @@ static void hs_write( FILE *scores, scorefile_entry &se )
fprintf( scores, ":%ld:%ld:%d:%d:\n",
se.real_time, se.num_turns, se.num_diff_runes, se.num_runes );
-}
-// -------------------------------------------------------------------------
-// functions dealing with old-style scorefile entries.
-// -------------------------------------------------------------------------
+ */
+}
-static void hs_parse_string(char *inbuf, struct scorefile_entry &se)
+static const char *kill_method_names[] =
+{
+ "mon", "pois", "cloud", "beam", "deaths_door", "lava", "water",
+ "stupidity", "weakness", "clumsiness", "trap", "leaving", "winning",
+ "quitting", "draining", "starvation", "freezing", "burning", "wild_magic",
+ "xom", "statue", "rotting", "targetting", "spore", "tso_smiting",
+ "petrification", "unknown", "something", "falling_down_stairs", "acid",
+ "curare", "melting", "bleeding",
+};
+
+const char *kill_method_name(kill_method_type kmt)
{
- /* old entries are of the following format (Brent introduced some
- spacing at one point, we have to take this into account):
+ ASSERT(NUM_KILLBY ==
+ (int) sizeof(kill_method_names) / sizeof(*kill_method_names));
- // Actually, I believe it might have been Brian who added the spaces,
- // I was quite happy with the condensed version, given the 80 column
- // restriction. -- bwr
+ if (kmt == NUM_KILLBY)
+ return ("");
-6263 BoBo - DSD10 Wiz, killed by an acid blob on L1 of the Slime Pits.
-5877 Aldus-DGM10, killed by a lethal dose of poison on L10.
-5419 Yarf - Koa10, killed by a warg on L1 of the Mines.
+ return kill_method_names[kmt];
+}
- 1. All numerics up to the first non-numeric are the score
- 2. All non '-' characters are the name. Strip spaces.
- 3. All alphabetics up to the first numeric are race/class
- 4. All numerics up to the comma are the clevel
- 5. From the comma, search for known fixed substrings and
- translate to death_type. Leave death source = 0 for old
- scores, and just copy in the monster name.
- 6. Look for the branch type (again, substring search for
- fixed strings) and level.
+kill_method_type str_to_kill_method(const std::string &s)
+{
+ ASSERT(NUM_KILLBY ==
+ (int) sizeof(kill_method_names) / sizeof(*kill_method_names));
+
+ for (int i = 0; i < NUM_KILLBY; ++i)
+ {
+ if (s == kill_method_names[i])
+ return static_cast<kill_method_type>(i);
+ }
- Very ugly and time consuming.
+ return (NUM_KILLBY);
+}
- */
+//////////////////////////////////////////////////////////////////////////
+// scorefile_entry
- char scratch[80];
- const int inlen = strlen(inbuf);
- char *start = inbuf;
+scorefile_entry::scorefile_entry(int dam, int dsource, int dtype,
+ const char *aux, bool death_cause_only)
+{
+ reset();
- // 1. get score
- hs_parse_generic_2(inbuf, scratch, sizeof scratch, "0123456789");
+ init_death_cause(dam, dsource, dtype, aux);
+ if (!death_cause_only)
+ init();
+}
- se.version = 0; // version # of converted score
- se.release = 0;
- se.points = atoi(scratch);
+scorefile_entry::scorefile_entry()
+{
+ // Completely uninitialized, caveat user.
+ reset();
+}
- // 2. get name
- hs_parse_generic_1(inbuf, scratch, sizeof scratch, "-");
- hs_stripblanks(scratch);
- strncpy(se.name, scratch, sizeof se.name);
- se.name[ sizeof(se.name) - 1 ] = 0;
+scorefile_entry::scorefile_entry(const scorefile_entry &se)
+{
+ init_from(se);
+}
- // 3. get race, class
- // skip '-'
- if (++inbuf - start >= inlen)
- return;
+scorefile_entry &scorefile_entry::operator = (const scorefile_entry &se)
+{
+ init_from(se);
+ return (*this);
+}
- hs_parse_generic_1(inbuf, scratch, sizeof scratch, "0123456789");
- hs_stripblanks(scratch);
- strncpy(se.race_class_name, scratch, sizeof se.race_class_name);
- se.race_class_name[ sizeof(se.race_class_name) - 1 ] = 0;
- se.race = 0;
- se.cls = 0;
-
- // 4. get clevel
- hs_parse_generic_2(inbuf, scratch, sizeof scratch, "0123456789");
- se.lvl = atoi(scratch);
-
- // 4a. get wizard mode
- hs_parse_generic_1(inbuf, scratch, sizeof scratch, ",");
- if (strstr(scratch, "Wiz") != NULL)
- se.wiz_mode = 1;
+void scorefile_entry::init_from(const scorefile_entry &se)
+{
+ version = se.version;
+ release = se.release;
+ points = se.points;
+ name = se.name;
+ uid = se.uid;
+ race = se.race;
+ cls = se.cls;
+ race_class_name = se.race_class_name;
+ lvl = se.lvl;
+ best_skill = se.best_skill;
+ best_skill_lvl = se.best_skill_lvl;
+ death_type = se.death_type;
+ death_source = se.death_source;
+ mon_num = se.mon_num;
+ death_source_name = se.death_source_name;
+ auxkilldata = se.auxkilldata;
+ dlvl = se.dlvl;
+ level_type = se.level_type;
+ branch = se.branch;
+ final_hp = se.final_hp;
+ final_max_hp = se.final_max_hp;
+ final_max_max_hp = se.final_max_max_hp;
+ damage = se.damage;
+ str = se.str;
+ intel = se.intel;
+ dex = se.dex;
+ god = se.god;
+ piety = se.piety;
+ penance = se.penance;
+ wiz_mode = se.wiz_mode;
+ birth_time = se.birth_time;
+ death_time = se.death_time;
+ real_time = se.real_time;
+ num_turns = se.num_turns;
+ num_diff_runes = se.num_diff_runes;
+ num_runes = se.num_runes;
+}
+
+bool scorefile_entry::parse(const std::string &line)
+{
+ // Scorefile formats down the ages:
+ //
+ // 1) old-style lines which were 80 character blocks
+ // 2) 4.0 pr1 through pr7 versions which were newline terminated
+ // 3) 4.0 pr8 and onwards which are colon-separated fields (and
+ // start with a colon), and may exceed 80 characters!
+ // 4) 0.2 and onwards, which are xlogfile format - no leading
+ // colon, fields separated by colons, each field specified as
+ // key=value. Colons are not allowed in key names, must be escaped to
+ // | in values. Literal | must be escaped as || in values.
+ //
+ // 0.2 only reads entries of type (3) and (4), and only writes entries of
+ // type (4).
+
+ // Leading colon implies 4.0 style line:
+ if (line[0] == ':')
+ return (parse_obsolete_scoreline(line));
else
- se.wiz_mode = 0;
+ return (parse_scoreline(line));
+}
- // Skip comma
- if (++inbuf - start >= inlen)
- return;
+// 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, "\\", "\\\\"),
+ "|", "\\|" ),
+ ":", "|" );
+}
- // 5. get death type
- hs_search_death(inbuf, se);
-
- // 6. get branch, level
- hs_search_where(inbuf, se);
-
- // set things that can't be picked out of old scorefile entries
- se.uid = 0;
- se.best_skill = 0;
- se.best_skill_lvl = 0;
- se.final_hp = 0;
- se.final_max_hp = -1;
- se.final_max_max_hp = -1;
- se.damage = -1;
- se.str = -1;
- se.intel = -1;
- se.dex = -1;
- se.god = -1;
- se.piety = -1;
- se.penance = -1;
- se.birth_time = 0;
- se.death_time = 0;
- se.real_time = -1;
- se.num_turns = -1;
- se.num_runes = 0;
- se.num_diff_runes = 0;
- se.auxkilldata[0] = 0;
-}
-
-static void hs_parse_generic_1(char *&inbuf, char *outbuf, size_t outsz, const char *stopvalues)
-{
- ASSERT(outsz > 0);
-
- char *p = outbuf;
-
- if (!*inbuf)
+// 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)
{
- *p = 0;
- return;
+ 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);
+}
- while (strchr(stopvalues, *inbuf) == NULL
- && *inbuf != 0
- && (p - outbuf) < (int) outsz - 1)
- *p++ = *inbuf++;
+std::string scorefile_entry::raw_string() const
+{
+ set_score_fields();
+
+ if (!fields.get())
+ return ("");
+
+ std::string line;
+ for (int i = 0, size = fields->size(); i < size; ++i)
+ {
+ const std::pair<std::string, std::string> &f = (*fields)[i];
- while (strchr(stopvalues, *inbuf) == NULL
- && *inbuf != 0)
- inbuf++;
+ // Don't write empty fields.
+ if (f.second.empty())
+ continue;
+
+ if (!line.empty())
+ line += ":";
- *p = 0;
+ line += f.first;
+ line += "=";
+ line += xlog_escape(f.second);
+ }
+
+ return (line);
}
-static void hs_parse_generic_2(
- char *&inbuf, char *outbuf, size_t outsz, const char *continuevalues)
+bool scorefile_entry::parse_scoreline(const std::string &line)
{
- ASSERT(outsz > 0);
-
- char *p = outbuf;
-
- if (!*inbuf)
+ std::vector<std::string> rawfields = split_string(":", line);
+ fields.reset(new hs_fields);
+ for (int i = 0, size = rawfields.size(); i < size; ++i)
{
- *p = 0;
- return;
+ 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)) ) );
}
- while (strchr(continuevalues, *inbuf) != NULL
- && *inbuf
- && (p - outbuf) < (int) outsz - 1)
- *p++ = *inbuf++;
+ init_with_fields();
+
+ return (true);
+}
- while (strchr(continuevalues, *inbuf) != NULL
- && *inbuf)
- inbuf++;
+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 ) );
+}
- *p = 0;
+void scorefile_entry::add_auxkill_field() const
+{
+ const char *what =
+ death_type == KILLED_BY_MONSTER? "kweap" :
+ death_type == KILLED_BY_BEAM? "kbeam" :
+ "kaux";
+
+ add_field(what, "%s", auxkilldata.c_str());
}
-static void hs_stripblanks(char *buf)
+void scorefile_entry::read_auxkill_field()
{
- char *p = buf;
- char *q = buf;
+ const char *what =
+ death_type == KILLED_BY_MONSTER? "kweap" :
+ death_type == KILLED_BY_BEAM? "kbeam" :
+ "kaux";
- // strip leading
- while(*p == ' ')
- p++;
+ auxkilldata = str_field(what);
+}
- while(*p != 0 && p != q)
- *q++ = *p++;
+std::string scorefile_entry::str_field(const std::string &s) const
+{
+ hs_map::const_iterator i = fieldmap->find(s);
+ if (i == fieldmap->end())
+ return ("");
- *q-- = 0;
- // strip trailing
- while (q >= buf && *q == ' ')
- *q-- = 0;
+ return i->second;
}
-static void hs_search_death(char *inbuf, struct scorefile_entry &se)
+int scorefile_entry::int_field(const std::string &s) const
{
- // assume killed by monster
- se.death_type = KILLED_BY_MONSTER;
+ std::string field = str_field(s);
+ return atoi(field.c_str());
+}
- // sigh..
- if (strstr(inbuf, "killed by a lethal dose of poison") != NULL)
- se.death_type = KILLED_BY_POISON;
- else if (strstr(inbuf, "killed by a cloud") != NULL)
- se.death_type = KILLED_BY_CLOUD;
- else if (strstr(inbuf, "killed from afar by") != NULL)
- se.death_type = KILLED_BY_BEAM;
- else if (strstr(inbuf, "took a swim in molten lava") != NULL)
- se.death_type = KILLED_BY_LAVA;
- else if (strstr(inbuf, "asphyxiated"))
- se.death_type = KILLED_BY_CURARE;
- else if (strstr(inbuf, "soaked and fell apart") != NULL)
- {
- se.death_type = KILLED_BY_WATER;
- se.race = SP_MUMMY;
- }
- else if (strstr(inbuf, "drowned") != NULL)
- se.death_type = KILLED_BY_WATER;
- else if (strstr(inbuf, "died of stupidity") != NULL)
- se.death_type = KILLED_BY_STUPIDITY;
- else if (strstr(inbuf, "too weak to continue adventuring") != NULL)
- se.death_type = KILLED_BY_WEAKNESS;
- else if (strstr(inbuf, "slipped on a banana peel") != NULL)
- se.death_type = KILLED_BY_CLUMSINESS;
- else if (strstr(inbuf, "killed by a trap") != NULL)
- se.death_type = KILLED_BY_TRAP;
- else if (strstr(inbuf, "got out of the dungeon alive") != NULL)
- se.death_type = KILLED_BY_LEAVING;
- else if (strstr(inbuf, "escaped with the Orb") != NULL)
- se.death_type = KILLED_BY_WINNING;
- else if (strstr(inbuf, "quit") != NULL)
- se.death_type = KILLED_BY_QUITTING;
- else if (strstr(inbuf, "was drained of all life") != NULL)
- se.death_type = KILLED_BY_DRAINING;
- else if (strstr(inbuf, "starved to death") != NULL)
- se.death_type = KILLED_BY_STARVATION;
- else if (strstr(inbuf, "froze to death") != NULL)
- se.death_type = KILLED_BY_FREEZING;
- else if (strstr(inbuf, "burnt to a crisp") != NULL)
- se.death_type = KILLED_BY_BURNING;
- else if (strstr(inbuf, "killed by wild magic") != NULL)
- se.death_type = KILLED_BY_WILD_MAGIC;
- else if (strstr(inbuf, "killed by Xom") != NULL)
- se.death_type = KILLED_BY_XOM;
- else if (strstr(inbuf, "killed by a statue") != NULL)
- se.death_type = KILLED_BY_STATUE;
- else if (strstr(inbuf, "rotted away") != NULL)
- se.death_type = KILLED_BY_ROTTING;
- else if (strstr(inbuf, "killed by bad target") != NULL)
- se.death_type = KILLED_BY_TARGETTING;
- else if (strstr(inbuf, "killed by an exploding spore") != NULL)
- se.death_type = KILLED_BY_SPORE;
- else if (strstr(inbuf, "smote by The Shining One") != NULL)
- se.death_type = KILLED_BY_TSO_SMITING;
- else if (strstr(inbuf, "turned to stone") != NULL)
- se.death_type = KILLED_BY_PETRIFICATION;
- else if (strstr(inbuf, "melted into a puddle") != NULL)
- se.death_type = KILLED_BY_MELTING;
- else if (strstr(inbuf, "bled to death") != NULL)
- se.death_type = KILLED_BY_BLEEDING;
-
- // whew!
-
- // now, if we're still KILLED_BY_MONSTER, make sure that there is
- // a "killed by" somewhere, or else we're setting it to UNKNOWN.
- if (se.death_type == KILLED_BY_MONSTER)
+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)
{
- if (strstr(inbuf, "killed by") == NULL)
- se.death_type = KILLED_BY_SOMETHING;
+ const std::pair<std::string, std::string> f = (*fields)[i];
+
+ (*fieldmap)[f.first] = f.second;
}
+}
- // set some fields
- se.death_source = 0;
- se.mon_num = 0;
- *se.death_source_name = 0;
+static const char *short_branch_name(int branch)
+{
+ if (branch >= 0 && branch < NUM_BRANCHES)
+ return branches[branch].abbrevname;
+ return ("");
+}
- // now try to pull the monster out.
- // [dshaligram] Holy brain damage, Batman.
- if (se.death_type == KILLED_BY_MONSTER || se.death_type == KILLED_BY_BEAM)
+static int str_to_branch(const std::string &branch)
+{
+ for (int i = 0; i < NUM_BRANCHES; ++i)
{
- char *p = strstr(inbuf, " by ");
- if (p)
- {
- p += 4;
- char *q = strstr(inbuf, " on ");
- if (q == NULL)
- q = strstr(inbuf, " in ");
-
- if (q && q > p)
- {
- char *d = se.death_source_name;
- const int maxread = sizeof(se.death_source_name) - 1;
+ if (branches[i].abbrevname && branches[i].abbrevname == branch)
+ return (i);
+ }
+ return (BRANCH_MAIN_DUNGEON);
+}
- while (p < q && (d - se.death_source_name) < maxread)
- *d++ = *p++;
+static const char *level_type_names[] =
+{
+ "D", "Lab", "Abyss", "Pan"
+};
- *d = 0;
- }
- }
- }
+static const char *level_area_type_name(int level_type)
+{
+ if (level_type >= 0 && level_type < NUM_LEVEL_AREA_TYPES)
+ return level_type_names[level_type];
+ return ("");
}
-static void hs_search_where(char *inbuf, struct scorefile_entry &se)
+static int str_to_level_area_type(const std::string &s)
{
- char scratch[6];
+ for (int i = 0; i < NUM_LEVEL_AREA_TYPES; ++i)
+ if (s == level_type_names[i])
+ return (i);
+ return (LEVEL_DUNGEON);
+}
- se.level_type = LEVEL_DUNGEON;
- se.branch = BRANCH_MAIN_DUNGEON;
- se.dlvl = 0;
+static int str_to_god(const std::string &god)
+{
+ if (god.empty())
+ return GOD_NO_GOD;
+
+ for (int i = GOD_NO_GOD; i < NUM_GODS; ++i)
+ {
+ if (god_name(i) == god)
+ return (i);
+ }
+ return (GOD_NO_GOD);
+}
- // early out
- if (se.death_type == KILLED_BY_LEAVING
- || se.death_type == KILLED_BY_WINNING)
- return;
+void scorefile_entry::init_with_fields()
+{
+ map_fields();
+ points = long_field("sc");
+ name = str_field("name");
+ uid = int_field("uid");
+
+ race = str_to_species(str_field("race"));
+ cls = get_class_index_by_name(str_field("cls").c_str());
+
+ lvl = int_field("xl");
+
+ 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");
+
+ 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 = 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");
+}
- // here we go again.
- if (strstr(inbuf, "in the Abyss") != NULL)
- se.level_type = LEVEL_ABYSS;
- else if (strstr(inbuf, "in Pandemonium") != NULL)
- se.level_type = LEVEL_PANDEMONIUM;
- else if (strstr(inbuf, "in a labyrinth") != NULL)
- se.level_type = LEVEL_LABYRINTH;
+void scorefile_entry::set_score_fields() const
+{
+ fields.reset(new hs_fields());
- // early out for special level types
- if (se.level_type != LEVEL_DUNGEON)
+ if (!fields.get())
return;
- // check for vestibule
- if (strstr(inbuf, "in the Vestibule") != NULL)
- {
- se.branch = BRANCH_VESTIBULE_OF_HELL;
- return;
- }
+ 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,
+ race, str, dex, god ) );
+ add_field("ktyp", ::kill_method_name(kill_method_type(death_type)));
+ add_field("killer", death_source_desc());
+
+ add_auxkill_field();
+
+ add_field("place", "%s",
+ place_name(get_packed_place(branch, dlvl, level_type),
+ false, true).c_str());
+ add_field("br", "%s", short_branch_name(branch));
+ add_field("lvl", "%d", dlvl);
+ 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);
+
+ // Don't write No God to save some space.
+ if (god != -1)
+ add_field("god", "%s", god == GOD_NO_GOD? "" : god_name(god));
+ if (piety > 0)
+ add_field("piety", "%d", piety);
+ if (penance > 0)
+ add_field("pen", "%d", penance);
+ if (wiz_mode)
+ add_field("wiz", "%d", wiz_mode);
+
+ 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);
+
+ if (num_diff_runes)
+ add_field("urune", "%d", num_diff_runes);
+
+ if (num_runes)
+ add_field("nrune", "%d", num_runes);
+
+#ifdef DGL_EXTENDED_LOGFILES
+ const std::string short_msg = short_kill_message();
+ add_field("tmsg", "%s", short_msg.c_str());
+ const std::string long_msg = long_kill_message();
+ if (long_msg != short_msg)
+ add_field("vmsg", "%s", long_msg.c_str());
+#endif
+}
- // from here, we have branch and level.
- char *p = strstr(inbuf, "on L");
- if (p != NULL)
+std::string scorefile_entry::make_oneline(const std::string &ml) const
+{
+ std::vector<std::string> lines = split_string(EOL, ml);
+ for (int i = 0, size = lines.size(); i < size; ++i)
{
- p += 4;
- hs_parse_generic_2(p, scratch, sizeof scratch, "0123456789");
- se.dlvl = atoi( scratch );
+ std::string &s = lines[i];
+ if (s.find("...") == 0)
+ {
+ s = s.substr(3);
+ trim_string(s);
+ }
}
+ return comma_separated_line(lines.begin(), lines.end(), " ", " ");
+}
- // get branch.
- if (strstr(inbuf, "of Dis") != NULL)
- se.branch = BRANCH_DIS;
- else if (strstr(inbuf, "of Gehenna") != NULL)
- se.branch = BRANCH_GEHENNA;
- else if (strstr(inbuf, "of Cocytus") != NULL)
- se.branch = BRANCH_COCYTUS;
- else if (strstr(inbuf, "of Tartarus") != NULL)
- se.branch = BRANCH_TARTARUS;
- else if (strstr(inbuf, "of the Mines") != NULL)
- se.branch = BRANCH_ORCISH_MINES;
- else if (strstr(inbuf, "of the Hive") != NULL)
- se.branch = BRANCH_HIVE;
- else if (strstr(inbuf, "of the Lair") != NULL)
- se.branch = BRANCH_LAIR;
- else if (strstr(inbuf, "of the Slime Pits") != NULL)
- se.branch = BRANCH_SLIME_PITS;
- else if (strstr(inbuf, "of the Vaults") != NULL)
- se.branch = BRANCH_VAULTS;
- else if (strstr(inbuf, "of the Crypt") != NULL)
- se.branch = BRANCH_CRYPT;
- else if (strstr(inbuf, "of the Hall") != NULL)
- se.branch = BRANCH_HALL_OF_BLADES;
- else if (strstr(inbuf, "of Zot's Hall") != NULL)
- se.branch = BRANCH_HALL_OF_ZOT;
- else if (strstr(inbuf, "of the Temple") != NULL)
- se.branch = BRANCH_ECUMENICAL_TEMPLE;
- else if (strstr(inbuf, "of the Snake Pit") != NULL)
- se.branch = BRANCH_SNAKE_PIT;
- else if (strstr(inbuf, "of the Elf Hall") != NULL)
- se.branch = BRANCH_ELVEN_HALLS;
- else if (strstr(inbuf, "of the Tomb") != NULL)
- se.branch = BRANCH_TOMB;
- else if (strstr(inbuf, "of the Swamp") != NULL)
- se.branch = BRANCH_SWAMP;
+std::string scorefile_entry::long_kill_message() const
+{
+ std::string msg = death_description(DDV_LOGVERBOSE);
+ msg = make_oneline(msg);
+ msg[0] = tolower(msg[0]);
+ trim_string(msg);
+ return (msg);
}
-//////////////////////////////////////////////////////////////////////////
-// scorefile_entry
+std::string scorefile_entry::short_kill_message() const
+{
+ std::string msg = death_description(DDV_ONELINE);
+ msg = make_oneline(msg);
+ msg[0] = tolower(msg[0]);
+ trim_string(msg);
+ return (msg);
+}
-scorefile_entry::scorefile_entry(int dam, int dsource, int dtype,
- const char *aux, bool death_cause_only)
+// Maps a 0.1.x branch id to a 0.2 branch id. Ugh. Fortunately we need this
+// only to read old logfiles/scorefiles.
+int scorefile_entry::kludge_branch(int branch_01) const
{
- reset();
+ static int branch_map[] = {
+ BRANCH_MAIN_DUNGEON, BRANCH_DIS, BRANCH_GEHENNA,
+ BRANCH_VESTIBULE_OF_HELL, BRANCH_COCYTUS, BRANCH_TARTARUS,
+ BRANCH_INFERNO, BRANCH_THE_PIT, BRANCH_MAIN_DUNGEON,
+ BRANCH_MAIN_DUNGEON, BRANCH_ORCISH_MINES, BRANCH_HIVE,
+ BRANCH_LAIR, BRANCH_SLIME_PITS, BRANCH_VAULTS, BRANCH_CRYPT,
+ BRANCH_HALL_OF_BLADES, BRANCH_HALL_OF_ZOT, BRANCH_ECUMENICAL_TEMPLE,
+ BRANCH_SNAKE_PIT, BRANCH_ELVEN_HALLS, BRANCH_TOMB, BRANCH_SWAMP,
+ BRANCH_CAVERNS
+ };
- init_death_cause(dam, dsource, dtype, aux);
- if (!death_cause_only)
- init();
+ if (branch_01 < 0
+ || branch_01 > (int) (sizeof(branch_map) / sizeof(*branch_map)))
+ {
+ return (BRANCH_MAIN_DUNGEON);
+ }
+ return branch_map[branch_01];
}
-scorefile_entry::scorefile_entry()
+// [ds] This is the 4.0 b26 logfile parser. Old-style logs are now deprecated;
+// support for reading them may be discontinued in the next version.
+bool scorefile_entry::parse_obsolete_scoreline(const std::string &line)
{
- // Completely uninitialized, caveat user.
- reset();
+ const char *inbuf = line.c_str();
+
+ version = hs_nextint(inbuf);
+ release = hs_nextint(inbuf);
+
+ // this would be a good point to check for version numbers and branch
+ // appropriately
+
+ // acceptable versions are 0 (converted from old hiscore format) and 4
+ if (version != 4 || release < 2)
+ return (false);
+
+ points = hs_nextlong(inbuf);
+
+ name = hs_nextstring(inbuf);
+
+ uid = hs_nextlong(inbuf);
+ race = hs_nextint(inbuf);
+ cls = hs_nextint(inbuf);
+
+ race_class_name = hs_nextstring(inbuf, 6);
+
+ lvl = hs_nextint(inbuf);
+ best_skill = hs_nextint(inbuf);
+ best_skill_lvl = hs_nextint(inbuf);
+ death_type = hs_nextint(inbuf);
+ death_source = hs_nextint(inbuf);
+ mon_num = hs_nextint(inbuf);
+
+ death_source_name = hs_nextstring(inbuf);
+
+ // To try and keep the scorefile backwards compatible,
+ // we'll branch on version > 4.0 to read the auxkilldata
+ // text field.
+ if (version == 4 && release >= 1)
+ auxkilldata = hs_nextstring( inbuf, ITEMNAME_SIZE );
+ else
+ auxkilldata[0] = 0;
+
+ dlvl = hs_nextint(inbuf);
+ level_type = hs_nextint(inbuf);
+ branch = kludge_branch( hs_nextint(inbuf) );
+
+ final_hp = hs_nextint(inbuf);
+ final_max_hp = hs_nextint(inbuf);
+ final_max_max_hp = hs_nextint(inbuf);
+ damage = hs_nextint(inbuf);
+ str = hs_nextint(inbuf);
+ intel = hs_nextint(inbuf);
+ dex = hs_nextint(inbuf);
+ god = hs_nextint(inbuf);
+ piety = hs_nextint(inbuf);
+ penance = hs_nextint(inbuf);
+
+ wiz_mode = hs_nextint(inbuf);
+
+ birth_time = hs_nextdate(inbuf);
+ death_time = hs_nextdate(inbuf);
+
+ real_time = hs_nextint(inbuf);
+ num_turns = hs_nextint(inbuf);
+
+ num_diff_runes = hs_nextint(inbuf);
+ num_runes = hs_nextint(inbuf);
+
+ return (true);
}
void scorefile_entry::init_death_cause(int dam, int dsrc,
@@ -1116,15 +1204,12 @@ void scorefile_entry::init_death_cause(int dam, int dsrc,
// Set the default aux data value...
// If aux is passed in (ie for a trap), we'll default to that.
if (aux == NULL)
- auxkilldata[0] = 0;
+ auxkilldata.clear();
else
- {
- strncpy( auxkilldata, aux, ITEMNAME_SIZE );
- auxkilldata[ ITEMNAME_SIZE - 1 ] = 0;
- }
+ auxkilldata = aux;
// for death by monster
- if ((death_type == KILLED_BY_MONSTER || death_type == KILLED_BY_BEAM)
+ if ((death_type == KILLED_BY_MONSTER || death_type == KILLED_BY_BEAM)
&& death_source >= 0 && death_source < MAX_MONSTERS)
{
const monsters *monster = &menv[death_source];
@@ -1167,21 +1252,13 @@ void scorefile_entry::init_death_cause(int dam, int dsrc,
// Setting this is redundant for dancing weapons, however
// we do care about the above indentification. -- bwr
if (monster->type != MONS_DANCING_WEAPON)
- {
- it_name( monster->inv[MSLOT_WEAPON],
- DESC_NOCAP_A,
- info );
- strncpy( auxkilldata, info, ITEMNAME_SIZE );
- auxkilldata[ ITEMNAME_SIZE - 1 ] = 0;
- }
+ auxkilldata = it_name( monster->inv[MSLOT_WEAPON],
+ DESC_NOCAP_A );
}
-
- strcpy( info,
- monam( monster->number, monster->type, true, DESC_NOCAP_A,
- monster->inv[MSLOT_WEAPON] ) );
- strncpy( death_source_name, info, 40 );
- death_source_name[39] = 0;
+ death_source_name =
+ monam( monster->number, monster->type, true, DESC_NOCAP_A,
+ monster->inv[MSLOT_WEAPON] );
}
}
else
@@ -1244,8 +1321,7 @@ void scorefile_entry::init()
version = 4;
release = 2;
- strncpy( name, you.your_name, sizeof name );
- name[ sizeof(name) - 1 ] = 0;
+ name = you.your_name;
#ifdef MULTIUSER
uid = (int) getuid();
@@ -1416,9 +1492,9 @@ const char *scorefile_entry::death_source_desc() const
if (death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
return ("");
- return (*death_source_name?
- death_source_name
- : monam( mon_num, death_source, true, DESC_PLAIN ) );
+ return (!death_source_name.empty()?
+ death_source_name.c_str()
+ : monam( mon_num, death_source, true, DESC_NOCAP_A ) );
}
std::string scorefile_entry::damage_string(bool terse) const
@@ -1438,26 +1514,15 @@ std::string scorefile_entry::strip_article_a(const std::string &s) const
return (s);
}
-std::string scorefile_entry::terse_missile_cause() const
+std::string scorefile_entry::terse_missile_name() const
{
- std::string cause;
- std::string aux = auxkilldata;
-
- std::string monster_prefix = " by ";
- // We're looking for Shot with a%s %s by %s/ Hit by a%s %s thrown by %s
- std::string::size_type by = aux.rfind(monster_prefix);
- if (by == std::string::npos)
- return ("???");
-
- std::string mcause = aux.substr(by + monster_prefix.length());
- mcause = strip_article_a(mcause);
-
- std::string missile;
const std::string pre_post[][2] = {
{ "Shot with a", " by " },
{ "Hit by a", " thrown by " }
};
-
+ const std::string &aux = auxkilldata;
+ std::string missile;
+
for (unsigned i = 0; i < sizeof(pre_post) / sizeof(*pre_post); ++i)
{
if (aux.find(pre_post[i][0]) != 0)
@@ -1475,6 +1540,24 @@ std::string scorefile_entry::terse_missile_cause() const
if (missile.find("n ") == 0)
missile = missile.substr(2);
}
+ return (missile);
+}
+
+std::string scorefile_entry::terse_missile_cause() const
+{
+ std::string cause;
+ const std::string &aux = auxkilldata;
+
+ std::string monster_prefix = " by ";
+ // We're looking for Shot with a%s %s by %s/ Hit by a%s %s thrown by %s
+ std::string::size_type by = aux.rfind(monster_prefix);
+ if (by == std::string::npos)
+ return ("???");
+
+ std::string mcause = aux.substr(by + monster_prefix.length());
+ mcause = strip_article_a(mcause);
+
+ std::string missile = terse_missile_name();
if (missile.length())
mcause += "/" + missile;
@@ -1497,7 +1580,7 @@ std::string scorefile_entry::terse_wild_magic() const
std::string scorefile_entry::terse_trap() const
{
- std::string trap = *auxkilldata? std::string(auxkilldata) + " trap"
+ std::string trap = !auxkilldata.empty()? auxkilldata + " trap"
: "trap";
if (trap.find("n ") == 0)
trap = trap.substr(2);
@@ -1508,29 +1591,27 @@ std::string scorefile_entry::terse_trap() const
std::string scorefile_entry::single_cdesc() const
{
- char scratch[INFO_SIZE];
- char buf[INFO_SIZE];
+ std::string char_desc;
- if (!*race_class_name)
+ if (race_class_name.empty())
{
- snprintf( scratch, sizeof(scratch), "%s%s",
- get_species_abbrev( race ), get_class_abbrev( cls ) );
+ char_desc =
+ make_stringf("%s%s",
+ get_species_abbrev( race ),
+ get_class_abbrev( cls ) );
}
else
{
- strncpy( scratch, race_class_name, sizeof scratch );
- scratch[ sizeof(scratch) - 1 ] = 0;
+ char_desc = race_class_name;
}
std::string scname = name;
if (scname.length() > 10)
scname = scname.substr(0, 10);
- snprintf( buf, sizeof buf,
+ return make_stringf(
"%8ld %-10s %s-%02d%s", points, scname.c_str(),
- scratch, lvl, (wiz_mode == 1) ? "W" : "" );
-
- return (buf);
+ char_desc.c_str(), lvl, (wiz_mode == 1) ? "W" : "" );
}
std::string
@@ -1554,14 +1635,14 @@ scorefile_entry::character_description(death_desc_verbosity verbosity) const
INFO_SIZE );
snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s (level %d",
- points, name, scratch, lvl );
+ points, name.c_str(), scratch, lvl );
desc = buf;
}
else
{
snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s %s (level %d",
- points, name, species_name(race, lvl),
+ points, name.c_str(), species_name(race, lvl),
get_class_name(cls), lvl );
desc = buf;
}
@@ -1690,9 +1771,10 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
bool needs_called_by_monster_line = false;
bool needs_damage = false;
- bool terse = verbosity == DDV_TERSE;
- bool verbose = verbosity == DDV_VERBOSE;
- bool oneline = verbosity == DDV_ONELINE;
+ const bool terse = verbosity == DDV_TERSE;
+ const bool semiverbose = verbosity == DDV_LOGVERBOSE;
+ const bool verbose = verbosity == DDV_VERBOSE || semiverbose;
+ const bool oneline = verbosity == DDV_ONELINE;
char scratch[INFO_SIZE];
@@ -1733,20 +1815,29 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
{
snprintf( scratch, sizeof(scratch), "%scloud of %s",
terse? "" : "Engulfed by a ",
- auxkilldata );
+ auxkilldata.c_str() );
desc += scratch;
}
needs_damage = true;
break;
case KILLED_BY_BEAM:
- if (oneline)
+ if (oneline || semiverbose)
{
// keeping this short to leave room for the deep elf spellcasters:
snprintf( scratch, sizeof(scratch), "%s by ",
- range_type_verb( auxkilldata ) );
+ range_type_verb( auxkilldata.c_str() ) );
desc += scratch;
desc += death_source_desc();
+
+ if (semiverbose)
+ {
+ std::string beam = terse_missile_name();
+ if (beam.empty())
+ beam = terse_beam_cause();
+ if (!beam.empty())
+ desc += make_stringf(" (%s)", beam.c_str());
+ }
}
else if (isupper( auxkilldata[0] )) // already made (ie shot arrows)
{
@@ -1755,24 +1846,27 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
desc += terse? terse_missile_cause() : auxkilldata;
needs_damage = true;
}
- else if (verbose && strncmp( auxkilldata, "by ", 3 ) == 0)
+ else if (verbose && auxkilldata.find("by ") == 0)
{
// "by" is used for priest attacks where the effect is indirect
// in verbose format we have another line for the monster
needs_called_by_monster_line = true;
- snprintf( scratch, sizeof(scratch), "Killed %s", auxkilldata );
+ snprintf( scratch, sizeof(scratch), "Killed %s",
+ auxkilldata.c_str() );
desc += scratch;
}
else
{
// Note: This is also used for the "by" cases in non-verbose
// mode since listing the monster is more imporatant.
- if (!terse)
+ if (semiverbose)
+ desc += "Killed by ";
+ else if (!terse)
desc += "Killed from afar by ";
desc += death_source_desc();
- if (*auxkilldata)
+ if (!auxkilldata.empty())
needs_beam_cause_line = true;
needs_damage = true;
@@ -1822,8 +1916,9 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
desc += terse_trap();
else
{
- snprintf( scratch, sizeof(scratch), "Killed by triggering a%s trap",
- (*auxkilldata) ? auxkilldata : "" );
+ snprintf( scratch, sizeof(scratch),
+ "Killed by triggering a%s trap",
+ auxkilldata.c_str() );
desc += scratch;
}
needs_damage = true;
@@ -1870,7 +1965,7 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
break;
case KILLED_BY_WILD_MAGIC:
- if (!*auxkilldata)
+ if (auxkilldata.empty())
desc += terse? "wild magic" : "Killed by wild magic";
else
{
@@ -1880,8 +1975,8 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
{
// A lot of sources for this case... some have "by" already.
snprintf( scratch, sizeof(scratch), "Killed %s%s",
- (strncmp( auxkilldata, "by ", 3 ) != 0) ? "by " : "",
- auxkilldata );
+ (auxkilldata.find("by ") != 0) ? "by " : "",
+ auxkilldata.c_str() );
desc += scratch;
}
}
@@ -1925,7 +2020,7 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
/* case 26 */
case KILLED_BY_SOMETHING:
- if (auxkilldata)
+ if (!auxkilldata.empty())
desc += auxkilldata;
else
desc += terse? "died" : "Died";
@@ -1965,7 +2060,7 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
// TODO: Eventually, get rid of "..." for cases where the text fits.
if (terse)
{
- if (death_type == KILLED_BY_MONSTER && *auxkilldata)
+ if (death_type == KILLED_BY_MONSTER && !auxkilldata.empty())
{
desc += "/";
desc += strip_article_a(auxkilldata);
@@ -1983,7 +2078,7 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
{
bool done_damage = false; // paranoia
- if (needs_damage && damage > 0)
+ if (!semiverbose && needs_damage && damage > 0)
{
desc += " " + damage_string();
needs_damage = false;
@@ -2001,14 +2096,15 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
num_runes, (num_runes > 1) ? "s" : "" );
desc += scratch;
- if (num_diff_runes > 1)
+ if (!semiverbose && num_diff_runes > 1)
{
snprintf( scratch, INFO_SIZE, " (of %d types)",
num_diff_runes );
desc += scratch;
}
- if (death_time > 0
+ if (!semiverbose
+ && death_time > 0
&& !hiscore_same_day( birth_time, death_time ))
{
desc += " on ";
@@ -2025,30 +2121,40 @@ scorefile_entry::death_description(death_desc_verbosity verbosity) const
if (death_type == KILLED_BY_MONSTER && auxkilldata[0])
{
- snprintf(scratch, INFO_SIZE, "... wielding %s", auxkilldata);
- desc += scratch;
- needs_damage = true;
+ if (!semiverbose)
+ {
+ snprintf(scratch, INFO_SIZE, "... wielding %s",
+ auxkilldata.c_str());
+ desc += scratch;
+ needs_damage = true;
+ }
}
else if (needs_beam_cause_line)
{
- desc += (is_vowel( auxkilldata[0] )) ? "... with an "
- : "... with a ";
- desc += auxkilldata;
- needs_damage = true;
+ if (!semiverbose)
+ {
+ desc += (is_vowel( auxkilldata[0] )) ? "... with an "
+ : "... with a ";
+ desc += auxkilldata;
+ needs_damage = true;
+ }
}
else if (needs_called_by_monster_line)
{
- snprintf( scratch, sizeof(scratch), "... called down by %s",
- death_source_name );
+ snprintf( scratch, sizeof(scratch), "... invoked by %s",
+ death_source_name.c_str() );
desc += scratch;
needs_damage = true;
}
- if (needs_damage && !done_damage && damage > 0)
- desc += " " + damage_string();
+ if (!semiverbose)
+ {
+ if (needs_damage && !done_damage && damage > 0)
+ desc += " " + damage_string();
- if (needs_damage)
- desc += hiscore_newline_string();
+ if (needs_damage)
+ desc += hiscore_newline_string();
+ }
}
}
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index f73c7bd1d5..01764ac3ba 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -290,7 +290,7 @@ static char str_to_race( const std::string &str )
return ((index != -1) ? index_to_letter( index - 1 ) : 0);
}
-static char str_to_class( const std::string &str )
+static int str_to_class( const std::string &str )
{
int index = -1;
@@ -702,7 +702,7 @@ void game_options::reset_options()
// These are only used internally, and only from the commandline:
// XXX: These need a better place.
sc_entries = 0;
- sc_format = SCORE_REGULAR;
+ sc_format = -1;
friend_brand = CHATTR_NORMAL;
heap_brand = CHATTR_NORMAL;
@@ -2406,6 +2406,8 @@ bool parse_args( int argc, char **argv, bool rc_only )
Options.sc_format = SCORE_TERSE;
else if (o == CLO_VSCORES)
Options.sc_format = SCORE_VERBOSE;
+ else if (o == CLO_SCORES)
+ Options.sc_format = SCORE_REGULAR;
}
break;
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 2aa2d363cb..94542fff02 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1574,7 +1574,8 @@ bool fall_into_a_pool( int entry_x, int entry_y, bool allow_shift,
{
// back out the way we came in, if possible
if (grid_distance( you.x_pos, you.y_pos, entry_x, entry_y ) == 1
- && (entry_x != empty[0] || entry_y != empty[1]))
+ && (entry_x != empty[0] || entry_y != empty[1])
+ && mgrd[entry_x][entry_y] == NON_MONSTER)
{
escape = true;
empty[0] = entry_x;
@@ -1991,13 +1992,13 @@ unsigned short get_packed_place()
bool single_level_branch( int branch )
{
return
- branch == BRANCH_VESTIBULE_OF_HELL ||
- branch == BRANCH_HALL_OF_BLADES ||
- branch == BRANCH_ECUMENICAL_TEMPLE;
+ branch >= 0 && branch < NUM_BRANCHES
+ && branches[branch].depth == 1;
}
std::string place_name( unsigned short place, bool long_name,
- bool include_number ) {
+ bool include_number )
+{
unsigned char branch = (unsigned char) ((place >> 8) & 0xFF);
int lev = place & 0xFF;
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 20efd35732..b4fbfeb902 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -172,7 +172,6 @@ std::string short_place_name(unsigned short place);
std::string short_place_name(level_id id);
std::string place_name( unsigned short place, bool long_name = false,
bool include_number = true );
-std::string branch_name( int branch, bool terse );
// Prepositional form of branch level name. For example, "in the
// Abyss" or "on level 3 of the Main Dungeon".
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 714d38abf0..c52a17913c 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -3395,7 +3395,7 @@
M_NO_SKELETON | M_SEE_INVIS,
MR_RES_POISON | MR_RES_ASPHYX,
0, 5, MONS_JELLY, MONS_OOZE, MH_NATURAL, -6,
- { {AT_HIT, AF_ACID, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { {AT_HIT, AF_PLAIN, 5}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
{ 3, 3, 5, 0 },
1, 3, 8, 7, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT, I_PLANT,
MONUSE_NOTHING, SIZE_LITTLE
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index b0f932e8f5..c5882d783a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -1167,18 +1167,23 @@ static bool habitat_okay( struct monsters *monster, int targ )
// swap pets to their death, we can let that go). -- bwr
bool swap_places(struct monsters *monster)
{
- bool swap;
-
int loc_x = you.x_pos;
int loc_y = you.y_pos;
const int mgrid = grd[monster->x][monster->y];
- swap = habitat_okay( monster, grd[loc_x][loc_y] )
- && !is_grid_dangerous(mgrid);
+ const bool mon_dest_okay = habitat_okay( monster, grd[loc_x][loc_y] );
+ const bool you_dest_okay =
+ !is_grid_dangerous(mgrid)
+ || yesno("Do you really want to step there?", false, 'n');
+
+ if (!you_dest_okay)
+ return (false);
+
+ bool swap = mon_dest_okay;
// chose an appropiate habitat square at random around the target.
- if (!swap && !is_grid_dangerous(mgrid))
+ if (!swap)
{
int num_found = 0;
int temp_x, temp_y;
@@ -4534,9 +4539,8 @@ void mons_check_pool(monsters *mons, int killer)
return;
const int grid = grd(mons->pos());
- const int native_habitat = monster_habitat(mons->type);
if ((grid == DNGN_LAVA || grid == DNGN_DEEP_WATER)
- && grid != native_habitat)
+ && !monster_habitable_grid(mons, grid))
{
const bool message = mons_near(mons);
@@ -4549,8 +4553,7 @@ void mons_check_pool(monsters *mons, int killer)
// Even fire resistant monsters perish in lava, but undead can survive
// deep water.
- if (!monster_habitable_grid(mons, grid)
- && (grid == DNGN_LAVA || mons->holiness() != MH_UNDEAD))
+ if (grid == DNGN_LAVA || mons->holiness() != MH_UNDEAD)
{
if (message)
{
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 93ac6f69f8..ec44e6c55b 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -1424,7 +1424,7 @@ bolt mons_spells( int spell_cast, int power )
beam.type = SYM_MISSILE;
beam.thrower = KILL_MON;
beam.flavour = BEAM_POISON_ARROW;
- beam.hit = 14 + power / 25;
+ beam.hit = 12 + power / 25;
beam.range = beam.rangeMax = 8;
break;
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 983b8403f1..bb4cb683dc 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -327,7 +327,7 @@ bool is_grid_dangerous(int grid)
{
return (!player_is_levitating()
&& (grid == DNGN_LAVA
- || grid == DNGN_DEEP_WATER && !player_can_swim()));
+ || (grid == DNGN_DEEP_WATER && !player_can_swim())));
}
bool player_in_mappable_area( void )
@@ -3247,6 +3247,27 @@ void redraw_skill(const char your_name[kNameLen], const char class_name[80])
cprintf( "%s", print_it );
} // end redraw_skill()
+// Does a case-sensitive lookup of the species name supplied.
+int str_to_species(const std::string &species)
+{
+ if (species.empty())
+ return SP_HUMAN;
+
+ for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
+ {
+ if (species == species_name(i, 10))
+ return (i);
+ }
+
+ for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
+ {
+ if (species == species_name(i, 1))
+ return (i);
+ }
+
+ return (SP_HUMAN);
+}
+
// Note that this function only has the one static buffer, so if you
// want to use the results, you'll want to make a copy.
char *species_name( int speci, int level, bool genus, bool adj, bool cap )
@@ -4770,11 +4791,7 @@ int player::damage_type(int)
{
return (DVORP_SLICING);
}
- else if (equip[EQ_GLOVES] == -1 &&
- (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
- || mutation[MUT_CLAWS]
- || species == SP_TROLL
- || species == SP_GHOUL))
+ else if (has_usable_claws())
{
return (DVORP_CLAWING);
}
@@ -5162,3 +5179,12 @@ void player::slow_down(int str)
{
::slow_player( str );
}
+
+bool player::has_usable_claws() const
+{
+ return (equip[EQ_GLOVES] == -1 &&
+ (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON
+ || mutation[MUT_CLAWS]
+ || species == SP_TROLL
+ || species == SP_GHOUL));
+}
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index 8cd5c23ff3..4dd31f58f2 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -79,7 +79,7 @@ bool wearing_amulet(char which_am, bool calc_unid = true);
* called from: acr - chardump - describe - newgame - view
* *********************************************************************** */
char *species_name( int speci, int level, bool genus = false, bool adj = false, bool cap = true );
-
+int str_to_species(const std::string &species);
/* ***********************************************************************
* called from: beam
@@ -439,7 +439,6 @@ int get_class_index_by_name( const char *name );
const char *get_class_abbrev( int which_job );
const char *get_class_name( int which_job );
-
// last updated 19apr2001 {gdl}
/* ***********************************************************************
* called from:
diff --git a/crawl-ref/source/skills2.cc b/crawl-ref/source/skills2.cc
index 0bbc35dace..b325b3a64a 100644
--- a/crawl-ref/source/skills2.cc
+++ b/crawl-ref/source/skills2.cc
@@ -1994,6 +1994,15 @@ const char *skill_name(int which_skill)
return (skills[which_skill][0]);
} // end skill_name()
+int str_to_skill(const std::string &skill)
+{
+ for (int i = 0; i < NUM_SKILLS; ++i)
+ {
+ if (skills[i][0] && skill == skills[i][0])
+ return (i);
+ }
+ return (SK_FIGHTING);
+}
const char *skill_title( unsigned char best_skill, unsigned char skill_lev,
int species, int str, int dex, int god )
diff --git a/crawl-ref/source/skills2.h b/crawl-ref/source/skills2.h
index 73658f31af..31d0cc8690 100644
--- a/crawl-ref/source/skills2.h
+++ b/crawl-ref/source/skills2.h
@@ -24,7 +24,7 @@
* called from: chardump - it_use3 - itemname - skills
* *********************************************************************** */
const char *skill_name(int which_skill);
-
+int str_to_skill(const std::string &skill);
// last_updated 24may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 6655fec60b..a95aad09d4 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -350,22 +350,25 @@ bool unmarshallBoolean(struct tagHeader &th)
}
// Saving the date as a string so we're not reliant on a particular epoch.
-void make_date_string( time_t in_date, char buff[20] )
+std::string make_date_string( time_t in_date )
{
+ char buff[20];
+
if (in_date <= 0)
{
buff[0] = 0;
- return;
+ return (buff);
}
-
struct tm *date = localtime( &in_date );
- snprintf( buff, 20,
+ snprintf( buff, sizeof buff,
"%4d%02d%02d%02d%02d%02d%s",
date->tm_year + 1900, date->tm_mon, date->tm_mday,
date->tm_hour, date->tm_min, date->tm_sec,
((date->tm_isdst > 0) ? "D" : "S") );
+
+ return (buff);
}
static int get_val_from_string( const char *ptr, int len )
@@ -613,7 +616,6 @@ void tag_set_expected(char tags[], int fileType)
// --------------------------- player tags (foo.sav) -------------------- //
static void tag_construct_you(struct tagHeader &th)
{
- char buff[20]; // used for date string
int i,j;
marshallString(th, you.your_name, 30);
@@ -776,8 +778,7 @@ static void tag_construct_you(struct tagHeader &th)
marshallByte(th, you.wizard);
// time of game start
- make_date_string( you.birth_time, buff );
- marshallString(th, buff, 20);
+ marshallString(th, make_date_string( you.birth_time ).c_str(), 20);
// real_time == -1 means game was started before this feature
if (you.real_time != -1)
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 6b1701699e..553cdaee6d 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -52,7 +52,7 @@ float unmarshallFloat(struct tagHeader &th);
bool unmarshallBoolean(struct tagHeader &th);
void unmarshallString(struct tagHeader &th, char *data, int maxSize);
-void make_date_string( time_t in_date, char buff[20] );
+std::string make_date_string( time_t in_date );
time_t parse_date_string( char[20] );
// last updated 22jan2001 {gdl}
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index 28d980baef..c8bca8e0c6 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -143,6 +143,13 @@ public:
int level_type;
public:
+ // Returns the level_id of the current level.
+ static level_id current();
+
+ // Returns the level_id of the level that the stair/portal/whatever at
+ // 'pos' on the current level leads to.
+ static level_id get_next_level_id(const coord_def &pos);
+
level_id() : branch(0), depth(-1), level_type(LEVEL_DUNGEON) { }
level_id(int br, int dep, int ltype = LEVEL_DUNGEON)
: branch(br), depth(dep), level_type(ltype)
@@ -160,13 +167,6 @@ public:
return (branch != -1 && depth != -1) || level_type != LEVEL_DUNGEON;
}
- // Returns the level_id of the current level.
- static level_id current();
-
- // Returns the level_id of the level that the stair/portal/whatever at
- // 'pos' on the current level leads to.
- static level_id get_next_level_id(const coord_def &pos);
-
bool operator == ( const level_id &id ) const
{
return branch == id.branch && depth == id.depth
diff --git a/crawl-ref/source/version.h b/crawl-ref/source/version.h
index f523ff50d8..6677b4304f 100644
--- a/crawl-ref/source/version.h
+++ b/crawl-ref/source/version.h
@@ -37,11 +37,14 @@
#define CRAWL "Dungeon Crawl Stone Soup"
+#define VER_NUM "0.2"
+#define VER_QUAL "-svn"
+
// last updated 07august2001 {mv}
/* ***********************************************************************
* called from: chardump - command - newgame
* *********************************************************************** */
-#define VERSION "0.2-svn (crawl-ref)"
+#define VERSION VER_NUM VER_QUAL " (crawl-ref)"
// last updated 20feb2001 {GDL}
/* ***********************************************************************