summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/hiscores.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/hiscores.cc')
-rw-r--r--stone_soup/crawl-ref/source/hiscores.cc1846
1 files changed, 0 insertions, 1846 deletions
diff --git a/stone_soup/crawl-ref/source/hiscores.cc b/stone_soup/crawl-ref/source/hiscores.cc
deleted file mode 100644
index f3aba604d1..0000000000
--- a/stone_soup/crawl-ref/source/hiscores.cc
+++ /dev/null
@@ -1,1846 +0,0 @@
-/*
- * File: highscore.cc
- * Summary: deal with reading and writing of highscore file
- * Written by: Gordon Lipford
- *
- * Change History (most recent first):
- *
- * <1> 16feb2001 gdl Created
- */
-
-/*
- * ----------- MODIFYING THE PRINTED SCORE FORMAT ---------------------
- * Do this at your leisure. Change hiscores_format_single() as much
- * as you like.
- *
- *
- * ----------- IF YOU MODIFY THE INTERNAL SCOREFILE FORMAT ------------
- * .. as defined by the struct 'scorefile_entry' ..
- * You MUST change hs_copy(), hs_parse_numeric(), hs_parse_string(),
- * and hs_write(). It's also a really good idea to change the
- * version numbers assigned in ouch() so that Crawl can tell the
- * difference between your new entry and previous versions.
- *
- *
- *
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#include "AppHdr.h"
-#include "externs.h"
-
-#include "hiscores.h"
-#include "itemname.h"
-#include "mon-util.h"
-#include "player.h"
-#include "religion.h"
-#include "stuff.h"
-#include "tags.h"
-#include "view.h"
-
-#include "skills2.h"
-
-#ifdef MULTIUSER
- // includes to get passwd file access:
- #include <pwd.h>
- #include <sys/types.h>
-#endif
-
-// enough memory allocated to snarf in the scorefile entries
-static struct scorefile_entry hs_list[SCORE_FILE_ENTRIES];
-
-// hackish: scorefile position of newest entry. Will be highlit during
-// highscore printing (always -1 when run from command line).
-static int newest_entry = -1;
-
-static FILE *hs_open(const char *mode);
-static void hs_close(FILE *handle, const char *mode);
-static bool hs_read(FILE *scores, struct scorefile_entry &dest);
-static void hs_parse_numeric(char *inbuf, struct scorefile_entry &dest);
-static void hs_parse_string(char *inbuf, struct scorefile_entry &dest);
-static void hs_copy(struct scorefile_entry &dest, struct scorefile_entry &src);
-static void hs_write(FILE *scores, struct scorefile_entry &entry);
-static void hs_nextstring(char *&inbuf, char *dest);
-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, const char *stopvalues);
-static void hs_parse_generic_2(char *&inbuf, char *outbuf, 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);
-
-// file locking stuff
-#ifdef USE_FILE_LOCKING
-static bool lock_file_handle( FILE *handle, int type );
-static bool unlock_file_handle( FILE *handle );
-#endif // USE_FILE_LOCKING
-
-void hiscores_new_entry( struct scorefile_entry &ne )
-{
- FILE *scores;
- int i, total_entries;
- bool inserted = false;
-
- // open highscore file (reading) -- note that NULL is not fatal!
- scores = hs_open("r");
-
- // read highscore file, inserting new entry at appropriate point,
- for (i = 0; i < SCORE_FILE_ENTRIES; i++)
- {
- if (hs_read(scores, hs_list[i]) == false)
- break;
-
- // compare points..
- if (ne.points >= hs_list[i].points && inserted == false)
- {
- newest_entry = i; // for later printing
- inserted = true;
- // copy read entry to i+1th position
- // Fixed a nasty overflow bug here -- Sharp
- if (i+1 < SCORE_FILE_ENTRIES)
- {
- hs_copy(hs_list[i+1], hs_list[i]);
- hs_copy(hs_list[i], ne);
- i++;
- } else {
- // copy new entry to current position
- hs_copy(hs_list[i], ne);
- }
- }
- }
-
- // special case: lowest score, with room
- if (!inserted && i < SCORE_FILE_ENTRIES)
- {
- newest_entry = i;
- inserted = true;
- // copy new entry
- hs_copy(hs_list[i], ne);
- i++;
- }
-
- total_entries = i;
-
- // close so we can re-open for writing
- hs_close(scores,"r");
-
- // open highscore file (writing) -- NULL *is* fatal here.
- scores = hs_open("w");
- if (scores == NULL)
- {
- perror("Entry not added - failure opening score file for writing.");
- return;
- }
-
- // write scorefile entries.
- for (i = 0; i < total_entries; i++)
- {
- hs_write(scores, hs_list[i]);
- }
-
- // close scorefile.
- hs_close(scores, "w");
-}
-
-void hiscores_print_list( int display_count, int format )
-{
- FILE *scores;
- int i, total_entries;
- bool use_printf = (Options.sc_entries > 0);
-
- if (display_count <= 0)
- display_count = SCORE_FILE_ENTRIES;
-
- // open highscore file (reading)
- scores = hs_open("r");
- if (scores == NULL)
- {
- // will only happen from command line
- puts( "No high scores." );
- return;
- }
-
- // read highscore file
- for (i = 0; i < SCORE_FILE_ENTRIES; i++)
- {
- if (hs_read( scores, hs_list[i] ) == false)
- break;
- }
- total_entries = i;
-
- // close off
- hs_close( scores, "r" );
-
- if (!use_printf)
- textcolor(LIGHTGREY);
-
- int start = (newest_entry > 10) ? newest_entry - 10: 0;
-
- if (start + display_count > total_entries)
- start = total_entries - display_count;
-
- if (start < 0)
- start = 0;
-
- const int finish = start + display_count;
-
- for (i = start; i < finish && i < total_entries; i++)
- {
- // check for recently added entry
- if (i == newest_entry && !use_printf)
- textcolor(YELLOW);
-
- // print position (tracked implicitly by order score file)
- snprintf( info, INFO_SIZE, "%3d.", i + 1 );
- if (use_printf)
- printf(info);
- else
- cprintf(info);
-
- // format the entry
- if (format == SCORE_TERSE)
- {
- hiscores_format_single( info, hs_list[i] );
- // truncate if we want short format
- info[75] = '\0';
- }
- else
- {
- hiscores_format_single_long( info, hs_list[i],
- (format == SCORE_VERBOSE) );
- }
-
- // print entry
- strcat(info, EOL);
- if(use_printf)
- printf(info);
- else
- cprintf(info);
-
- if (i == newest_entry && !use_printf)
- textcolor(LIGHTGREY);
- }
-}
-
-// Trying to supply an appropriate verb for the attack type. -- bwr
-static const char *const range_type_verb( const char *const aux )
-{
- if (strncmp( aux, "Shot ", 5 ) == 0) // launched
- return ("shot");
- else if (aux[0] == '\0' // unknown
- || strncmp( aux, "Hit ", 4 ) == 0 // thrown
- || strncmp( aux, "volley ", 7 ) == 0) // manticore spikes
- {
- return ("hit from afar");
- }
-
- return ("blasted"); // spells, wands
-}
-
-void hiscores_format_single(char *buf, struct scorefile_entry &se)
-{
- char scratch[100];
-
- // Now that we have a long format, I'm starting to make this
- // more terse, in hopes that it will better fit. -- bwr
-
- // race_class_name overrides race & class
- if (se.race_class_name[0] == '\0')
- {
- snprintf( scratch, sizeof(scratch), "%s%s",
- get_species_abbrev( se.race ), get_class_abbrev( se.cls ) );
- }
- else
- {
- strcpy( scratch, se.race_class_name );
- }
-
- se.name[10]='\0';
- sprintf( buf, "%8ld %-10s %s-%02d%s", se.points, se.name,
- scratch, se.lvl, (se.wiz_mode == 1) ? "W" : "" );
-
- // get monster type & number, if applicable
- int mon_type = se.death_source;
- int mon_number = se.mon_num;
-
- // remember -- we have 36 characters (not including initial space):
- switch (se.death_type)
- {
- case KILLED_BY_MONSTER:
- strcat( buf, " slain by " );
-
- // if death_source_name is non-null, override lookup (names might have
- // changed!)
- if (se.death_source_name[0] != '\0')
- strcat( buf, se.death_source_name );
- else
- strcat( buf, monam( mon_number, mon_type, true, DESC_PLAIN ) );
-
- break;
-
- case KILLED_BY_POISON:
- //if (dam == -9999) strcat(buf, "an overload of ");
- strcat( buf, " succumbed to poison" );
- break;
-
- case KILLED_BY_CLOUD:
- if (se.auxkilldata[0] == '\0')
- strcat( buf, " engulfed by a cloud" );
- else
- {
- const int len = strlen( se.auxkilldata );
-
- // Squeeze out "a cloud of" if required. -- bwr
- snprintf( scratch, sizeof(scratch), " engulfed by %s%s",
- (len < 15) ? "a cloud of " : "",
- se.auxkilldata );
-
- strcat( buf, scratch );
- }
- break;
-
- case KILLED_BY_BEAM:
- // keeping this short to leave room for the deep elf spellcasters:
- snprintf( scratch, sizeof(scratch), " %s by ",
- range_type_verb( se.auxkilldata ) );
- strcat( buf, scratch );
-
- // if death_source_name is non-null, override this
- if (se.death_source_name[0] != '\0')
- strcat( buf, se.death_source_name );
- else
- strcat( buf, monam( mon_number, mon_type, true, DESC_PLAIN ) );
- break;
-
-/*
- case KILLED_BY_DEATHS_DOOR:
- // death's door running out - NOTE: This is no longer fatal
- strcat(buf, " ran out of time");
- break;
-*/
-
- case KILLED_BY_CURARE:
- strcat( buf, " asphyxiated");
- break;
-
- case KILLED_BY_LAVA:
- if (se.race == SP_MUMMY)
- strcat( buf, " turned to ash by lava" );
- else
- strcat( buf, " took a swim in lava" );
- break;
-
- case KILLED_BY_WATER:
- if (se.race == SP_MUMMY)
- strcat( buf, " soaked and fell apart" );
- else
- strcat( buf, " drowned" );
- break;
-
- // these three are probably only possible if you wear a ring
- // of >= +3 ability, get drained to 3, then take it off, or have a very
- // low abil and wear a -ve ring. or, as of 2.7x, mutations can cause this
- // Don't forget decks of cards (they have some nasty code for this) -- bwr
- case KILLED_BY_STUPIDITY:
- strcat( buf, " died of stupidity" );
- break;
-
- case KILLED_BY_WEAKNESS:
- strcat( buf, " became too weak to continue" );
- break;
-
- case KILLED_BY_CLUMSINESS:
- strcat( buf, " slipped on a banana peel" );
- break;
-
- case KILLED_BY_TRAP:
- snprintf( scratch, sizeof(scratch), " triggered a%s trap",
- (se.auxkilldata[0] != '\0') ? se.auxkilldata : "" );
- strcat( buf, scratch );
- break;
-
- case KILLED_BY_LEAVING:
- strcat( buf, " got out of the dungeon alive" );
- break;
-
- case KILLED_BY_WINNING:
- strcat( buf, " escaped with the Orb!" );
- break;
-
- case KILLED_BY_QUITTING:
- strcat( buf, " quit the game" );
- break;
-
- case KILLED_BY_DRAINING:
- strcat( buf, " drained of all life" );
- break;
-
- case KILLED_BY_STARVATION:
- strcat( buf, " starved to death" );
- break;
-
- case KILLED_BY_FREEZING:
- strcat( buf, " froze to death" );
- break;
-
- case KILLED_BY_BURNING: // only sticky flame
- strcat( buf, " burnt to a crisp" );
- break;
-
- case KILLED_BY_WILD_MAGIC:
- if (se.auxkilldata[0] == '\0')
- strcat( buf, " killed by wild magic" );
- else
- {
- const bool need_by = (strncmp( se.auxkilldata, "by ", 3 ) == 0);
- const int len = strlen( se.auxkilldata );
-
- // Squeeze out "killed" if we're getting a bit long. -- bwr
- snprintf( scratch, sizeof(scratch), " %s%s%s",
- (len + 3 * (need_by) < 30) ? "killed" : "",
- (need_by) ? "by " : "",
- se.auxkilldata );
-
- strcat( buf, scratch );
- }
- break;
-
- case KILLED_BY_XOM: // only used for old Xom kills
- strcat( buf, " killed for Xom's enjoyment" );
- break;
-
- case KILLED_BY_STATUE:
- strcat( buf, " killed by a statue" );
- break;
-
- case KILLED_BY_ROTTING:
- strcat( buf, " rotted away" );
- break;
-
- case KILLED_BY_TARGETTING:
- strcat( buf, " killed by bad targeting" );
- break;
-
- case KILLED_BY_SPORE:
- strcat( buf, " killed by an exploding spore" );
- break;
-
- case KILLED_BY_TSO_SMITING:
- strcat( buf, " smote by The Shining One" );
- break;
-
- case KILLED_BY_PETRIFICATION:
- strcat( buf, " turned to stone" );
- break;
-
- case KILLED_BY_MELTING:
- strcat( buf, " melted into a puddle" );
- break;
-
- case KILLED_BY_BLEEDING:
- strcat( buf, " bled to death" );
- break;
-
- case KILLED_BY_SOMETHING:
- strcat( buf, " died" );
- break;
-
- case KILLED_BY_FALLING_DOWN_STAIRS:
- strcat( buf, " fell down a flight of stairs" );
- break;
-
- case KILLED_BY_ACID:
- strcat( buf, " splashed by acid" );
- break;
-
- default:
- strcat( buf, " nibbled to death by software bugs" );
- break;
- } // end switch
-
- if (se.death_type != KILLED_BY_LEAVING && se.death_type != KILLED_BY_WINNING)
- {
- if (se.level_type == LEVEL_ABYSS)
- {
- strcat(buf, " (Abyss)");
- return;
- }
- else if (se.level_type == LEVEL_PANDEMONIUM)
- {
- strcat(buf, " (Pan)");
- return;
- }
- else if (se.level_type == LEVEL_LABYRINTH)
- {
- strcat(buf, " (Lab)");
- return;
- }
- else if (se.branch == BRANCH_VESTIBULE_OF_HELL)
- {
- strcat(buf, " (Hell)"); // Gate? Vest?
- return;
- }
- else if (se.branch == BRANCH_HALL_OF_BLADES)
- {
- strcat(buf, " (Blade)");
- return;
- }
- else if (se.branch == BRANCH_ECUMENICAL_TEMPLE)
- {
- strcat(buf, " (Temple)");
- return;
- }
-
- snprintf( scratch, sizeof(scratch), " (%s%d)",
- (se.branch == BRANCH_DIS) ? "Dis " :
- (se.branch == BRANCH_GEHENNA) ? "Geh " :
- (se.branch == BRANCH_COCYTUS) ? "Coc " :
- (se.branch == BRANCH_TARTARUS) ? "Tar " :
- (se.branch == BRANCH_ORCISH_MINES) ? "Orc " :
- (se.branch == BRANCH_HIVE) ? "Hive " :
- (se.branch == BRANCH_LAIR) ? "Lair " :
- (se.branch == BRANCH_SLIME_PITS) ? "Slime " :
- (se.branch == BRANCH_VAULTS) ? "Vault " :
- (se.branch == BRANCH_CRYPT) ? "Crypt " :
- (se.branch == BRANCH_HALL_OF_ZOT) ? "Zot " :
- (se.branch == BRANCH_SNAKE_PIT) ? "Snake " :
- (se.branch == BRANCH_ELVEN_HALLS) ? "Elf " :
- (se.branch == BRANCH_TOMB) ? "Tomb " :
- (se.branch == BRANCH_SWAMP) ? "Swamp " : "DLv ",
- se.dlvl );
-
- strcat( buf, scratch );
- } // endif - killed by winning
-
- return;
-}
-
-static bool hiscore_same_day( time_t t1, time_t t2 )
-{
- struct tm *d1 = localtime( &t1 );
- const int year = d1->tm_year;
- const int mon = d1->tm_mon;
- const int day = d1->tm_mday;
-
- struct tm *d2 = localtime( &t2 );
-
- return (d2->tm_mday == day && d2->tm_mon == mon && d2->tm_year == year);
-}
-
-static void hiscore_date_string( time_t time, char buff[INFO_SIZE] )
-{
- struct tm *date = localtime( &time );
-
- const char *mons[12] = { "Jan", "Feb", "Mar", "Apr", "May", "June",
- "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
-
- snprintf( buff, INFO_SIZE, "%s %d, %d", mons[date->tm_mon],
- date->tm_mday, date->tm_year + 1900 );
-}
-
-static void hiscore_newline( char *buf, int &line_count )
-{
- strncat( buf, EOL " ", HIGHSCORE_SIZE );
- line_count++;
-}
-
-int hiscores_format_single_long( char *buf, struct scorefile_entry &se,
- bool verbose )
-{
- char scratch[INFO_SIZE];
- int line_count = 1;
-
- // race_class_name could/used to override race & class
- // strcpy(scratch, se.race_class_name);
-
- // Please excuse the following bit of mess in the name of flavour ;)
- if (verbose)
- {
- strncpy( scratch, skill_title( se.best_skill, se.best_skill_lvl,
- se.race, se.str, se.dex, se.god ),
- INFO_SIZE );
-
- snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s (level %d",
- se.points, se.name, scratch, se.lvl );
-
- }
- else
- {
- snprintf( buf, HIGHSCORE_SIZE, "%8ld %s the %s %s (level %d",
- se.points, se.name, species_name(se.race, se.lvl),
- get_class_name(se.cls), se.lvl );
- }
-
- if (se.final_max_max_hp > 0) // as the other two may be negative
- {
- snprintf( scratch, INFO_SIZE, ", %d/%d", se.final_hp, se.final_max_hp );
- strncat( buf, scratch, HIGHSCORE_SIZE );
-
- if (se.final_max_hp < se.final_max_max_hp)
- {
- snprintf( scratch, INFO_SIZE, " (%d)", se.final_max_max_hp );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- }
-
- strncat( buf, " HPs", HIGHSCORE_SIZE );
- }
-
- strncat( buf, ((se.wiz_mode) ? ") *WIZ*" : ")"), HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
-
- if (verbose)
- {
- const char *const race = species_name( se.race, se.lvl );
-
- snprintf( scratch, INFO_SIZE, "Began as a%s %s %s",
- is_vowel(race[0]) ? "n" : "", race, get_class_name(se.cls) );
- strncat( buf, scratch, HIGHSCORE_SIZE );
-
- if (se.birth_time > 0)
- {
- strncat( buf, " on ", HIGHSCORE_SIZE );
- hiscore_date_string( se.birth_time, scratch );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- }
-
- strncat( buf, "." , HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
-
- if (se.race != SP_DEMIGOD && se.god != -1)
- {
- if (se.god == GOD_XOM)
- {
- snprintf( scratch, INFO_SIZE, "Was a %sPlaything of Xom.",
- (se.lvl >= 20) ? "Favourite " : "" );
-
- strncat( buf, scratch, HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
- }
- else if (se.god != GOD_NO_GOD)
- {
- // Not exactly the same as the religon screen, but
- // good enough to fill this slot for now.
- snprintf( scratch, INFO_SIZE, "Was %s of %s%s",
- (se.piety > 160) ? "the Champion" :
- (se.piety >= 120) ? "a High Priest" :
- (se.piety >= 100) ? "an Elder" :
- (se.piety >= 75) ? "a Priest" :
- (se.piety >= 50) ? "a Believer" :
- (se.piety >= 30) ? "a Follower"
- : "an Initiate",
- god_name( se.god ),
- (se.penance > 0) ? " (penitent)." : "." );
-
- strncat( buf, scratch, HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
- }
- }
- }
-
- // get monster type & number, if applicable
- int mon_type = se.death_source;
- int mon_number = se.mon_num;
-
- bool needs_beam_cause_line = false;
- bool needs_called_by_monster_line = false;
- bool needs_damage = false;
-
- switch (se.death_type)
- {
- case KILLED_BY_MONSTER:
- // GDL: here's an example of using final_hp. Verbiage could be better.
- // bwr: changed "blasted" since this is for melee
- snprintf( scratch, INFO_SIZE, "%s %s",
- (se.final_hp > -6) ? "Slain by" :
- (se.final_hp > -14) ? "Mangled by" :
- (se.final_hp > -22) ? "Demolished by"
- : "Annihilated by",
-
- (se.death_source_name[0] != '\0')
- ? se.death_source_name
- : monam( mon_number, mon_type, true, DESC_PLAIN ) );
-
- strncat( buf, scratch, HIGHSCORE_SIZE );
-
- // put the damage on the weapon line if there is one
- if (se.auxkilldata[0] == '\0')
- needs_damage = true;
- break;
-
- case KILLED_BY_POISON:
- //if (dam == -9999) strcat(buf, "an overload of ");
- strcat( buf, "Succumbed to poison" );
- break;
-
- case KILLED_BY_CLOUD:
- if (se.auxkilldata[0] == '\0')
- strcat( buf, "Engulfed by a cloud" );
- else
- {
- snprintf( scratch, sizeof(scratch), "Engulfed by a cloud of %s",
- se.auxkilldata );
- strcat( buf, scratch );
- }
- needs_damage = true;
- break;
-
- case KILLED_BY_BEAM:
- if (isupper( se.auxkilldata[0] )) // already made (ie shot arrows)
- {
- strcat( buf, se.auxkilldata );
- needs_damage = true;
- }
- else if (verbose && strncmp( se.auxkilldata, "by ", 3 ) == 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", se.auxkilldata );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- }
- else
- {
- // Note: This is also used for the "by" cases in non-verbose
- // mode since listing the monster is more imporatant.
- strcat( buf, "Killed from afar by " );
-
- // if death_source_name is non-null, override this
- if (se.death_source_name[0] != '\0')
- strcat(buf, se.death_source_name);
- else
- strcat(buf, monam( mon_number, mon_type, true, DESC_PLAIN ));
-
- if (se.auxkilldata[0] != '\0')
- needs_beam_cause_line = true;
- }
- break;
-
- case KILLED_BY_CURARE:
- strcat(buf, "Asphyxiated");
- break;
-
- case KILLED_BY_LAVA:
- if (se.race == SP_MUMMY)
- strcat( buf, "Turned to ash by lava" );
- else
- strcat( buf, "Took a swim in molten lava" );
- break;
-
- case KILLED_BY_WATER:
- if (se.race == SP_MUMMY)
- strcat( buf, "Soaked and fell apart" );
- else
- strcat( buf, "Drowned" );
- break;
-
- case KILLED_BY_STUPIDITY:
- strcat( buf, "Forgot to breathe" );
- break;
-
- case KILLED_BY_WEAKNESS:
- strcat( buf, "Collapsed under their own weight" );
- break;
-
- case KILLED_BY_CLUMSINESS:
- strcat( buf, "Slipped on a banana peel" );
- break;
-
- case KILLED_BY_TRAP:
- snprintf( scratch, sizeof(scratch), "Killed by triggering a%s trap",
- (se.auxkilldata[0] != '\0') ? se.auxkilldata : "" );
- strcat( buf, scratch );
- needs_damage = true;
- break;
-
- case KILLED_BY_LEAVING:
- if (se.num_runes > 0)
- strcat( buf, "Got out of the dungeon" );
- else
- strcat( buf, "Got out of the dungeon alive!" );
- break;
-
- case KILLED_BY_WINNING:
- strcat( buf, "Escaped with the Orb" );
- if (se.num_runes < 1)
- strcat( buf, "!" );
- break;
-
- case KILLED_BY_QUITTING:
- strcat( buf, "Quit the game" );
- break;
-
- case KILLED_BY_DRAINING:
- strcat( buf, "Was drained of all life" );
- break;
-
- case KILLED_BY_STARVATION:
- strcat( buf, "Starved to death" );
- break;
-
- case KILLED_BY_FREEZING: // refrigeration spell
- strcat( buf, "Froze to death" );
- needs_damage = true;
- break;
-
- case KILLED_BY_BURNING: // sticky flame
- strcat( buf, "Burnt to a crisp" );
- needs_damage = true;
- break;
-
- case KILLED_BY_WILD_MAGIC:
- if (se.auxkilldata[0] == '\0')
- strcat( buf, "Killed by wild magic" );
- else
- {
- // A lot of sources for this case... some have "by" already.
- snprintf( scratch, sizeof(scratch), "Killed %s%s",
- (strncmp( se.auxkilldata, "by ", 3 ) != 0) ? "by " : "",
- se.auxkilldata );
-
- strcat( buf, scratch );
- }
-
- needs_damage = true;
- break;
-
- case KILLED_BY_XOM: // only used for old Xom kills
- strcat( buf, "It was good that Xom killed them" );
- needs_damage = true;
- break;
-
- case KILLED_BY_STATUE:
- strcat( buf, "Killed by a statue" );
- needs_damage = true;
- break;
-
- case KILLED_BY_ROTTING:
- strcat( buf, "Rotted away" );
- break;
-
- case KILLED_BY_TARGETTING:
- strcat( buf, "Killed themselves with bad targeting" );
- needs_damage = true;
- break;
-
- case KILLED_BY_SPORE:
- strcat( buf, "Killed by an exploding spore" );
- needs_damage = true;
- break;
-
- case KILLED_BY_TSO_SMITING:
- strcat( buf, "Smote by The Shining One" );
- needs_damage = true;
- break;
-
- case KILLED_BY_PETRIFICATION:
- strcat( buf, "Turned to stone" );
- break;
-
- case KILLED_BY_MELTING:
- strcat( buf, " melted into a puddle" );
- break;
-
- case KILLED_BY_BLEEDING:
- strcat( buf, " bled to death" );
- break;
-
- case KILLED_BY_SOMETHING:
- strcat( buf, "Died" );
- break;
-
- case KILLED_BY_FALLING_DOWN_STAIRS:
- strcat( buf, "Fell down a flight of stairs" );
- needs_damage = true;
- break;
-
- case KILLED_BY_ACID:
- strcat( buf, "Splashed by acid" );
- needs_damage = true;
- break;
-
- default:
- strcat( buf, "Nibbled to death by software bugs" );
- break;
- } // end switch
-
- // TODO: Eventually, get rid of "..." for cases where the text fits.
- if (verbose)
- {
- bool done_damage = false; // paranoia
-
- if (needs_damage && se.damage > 0)
- {
- snprintf( scratch, INFO_SIZE, " (%d damage)", se.damage );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- needs_damage = false;
- done_damage = true;
- }
-
- if ((se.death_type == KILLED_BY_LEAVING
- || se.death_type == KILLED_BY_WINNING)
- && se.num_runes > 0)
- {
- hiscore_newline( buf, line_count );
-
- snprintf( scratch, INFO_SIZE, "... %s %d rune%s",
- (se.death_type == KILLED_BY_WINNING) ? "and" : "with",
- se.num_runes, (se.num_runes > 1) ? "s" : "" );
- strncat( buf, scratch, HIGHSCORE_SIZE );
-
- if (se.num_diff_runes > 1)
- {
- snprintf( scratch, INFO_SIZE, " (of %d types)",
- se.num_diff_runes );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- }
-
- if (se.death_time > 0
- && !hiscore_same_day( se.birth_time, se.death_time ))
- {
- strcat( buf, " on " );
- hiscore_date_string( se.death_time, scratch );
- strcat( buf, scratch );
- }
-
- strcat( buf, "!" );
- hiscore_newline( buf, line_count );
- }
- else if (se.death_type != KILLED_BY_QUITTING)
- {
- hiscore_newline( buf, line_count );
-
- if (se.death_type == KILLED_BY_MONSTER && se.auxkilldata[0])
- {
- snprintf(scratch, INFO_SIZE, "... wielding %s", se.auxkilldata);
- strncat(buf, scratch, HIGHSCORE_SIZE);
- needs_damage = true;
- }
- else if (needs_beam_cause_line)
- {
- strcat( buf, (is_vowel( se.auxkilldata[0] )) ? "... with an "
- : "... with a " );
- strcat( buf, se.auxkilldata );
- needs_damage = true;
- }
- else if (needs_called_by_monster_line)
- {
- snprintf( scratch, sizeof(scratch), "... called down by %s",
- se.death_source_name );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- needs_damage = true;
- }
-
- if (needs_damage && !done_damage)
- {
- if (se.damage > 0)
- {
- snprintf( scratch, INFO_SIZE, " (%d damage)", se.damage );
- strncat( buf, scratch, HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
- }
- }
- }
- }
-
- if (se.death_type == KILLED_BY_LEAVING
- || se.death_type == KILLED_BY_WINNING)
- {
- // TODO: strcat "after reaching level %d"; for LEAVING
- if (!verbose)
- {
- if (se.num_runes > 0)
- strcat( buf, "!" );
-
- hiscore_newline( buf, line_count );
- }
- }
- else
- {
- if (verbose && se.death_type != KILLED_BY_QUITTING)
- strcat( buf, "..." );
-
- if (se.level_type == LEVEL_ABYSS)
- strcat( buf, " in the Abyss" );
- else if (se.level_type == LEVEL_PANDEMONIUM)
- strcat( buf, " in Pandemonium" );
- else if (se.level_type == LEVEL_LABYRINTH)
- strcat( buf, " in a labyrinth" );
- else
- {
- switch (se.branch)
- {
- case BRANCH_ECUMENICAL_TEMPLE:
- strcat( buf, " in the Ecumenical Temple" );
- break;
- case BRANCH_HALL_OF_BLADES:
- strcat( buf, " in the Hall of Blades" );
- break;
- case BRANCH_VESTIBULE_OF_HELL:
- strcat( buf, " in the Vestibule" );
- break;
-
- case BRANCH_DIS:
- strcat( buf, " on Dis" );
- break;
- case BRANCH_GEHENNA:
- strcat( buf, " on Gehenna" );
- break;
- case BRANCH_COCYTUS:
- strcat( buf, " on Cocytus" );
- break;
- case BRANCH_TARTARUS:
- strcat( buf, " on Tartarus" );
- break;
- case BRANCH_ORCISH_MINES:
- strcat( buf, " on Orcish Mines" );
- break;
- case BRANCH_HIVE:
- strcat( buf, " on Hive" );
- break;
- case BRANCH_LAIR:
- strcat( buf, " on Lair" );
- break;
- case BRANCH_SLIME_PITS:
- strcat( buf, " on Slime Pits" );
- break;
- case BRANCH_VAULTS:
- strcat( buf, " on Vault" );
- break;
- case BRANCH_CRYPT:
- strcat( buf, " on Crypt" );
- break;
- case BRANCH_HALL_OF_ZOT:
- strcat( buf, " on Hall of Zot" );
- break;
- case BRANCH_SNAKE_PIT:
- strcat( buf, " on Snake Pit" );
- break;
- case BRANCH_ELVEN_HALLS:
- strcat( buf, " on Elven Halls" );
- break;
- case BRANCH_TOMB:
- strcat( buf, " on Tomb" );
- break;
- case BRANCH_SWAMP:
- strcat( buf, " on Swamp" );
- break;
- case BRANCH_MAIN_DUNGEON:
- strcat( buf, " on Dungeon" );
- break;
- }
-
- if (se.branch != BRANCH_VESTIBULE_OF_HELL
- && se.branch != BRANCH_ECUMENICAL_TEMPLE
- && se.branch != BRANCH_HALL_OF_BLADES)
- {
- snprintf( scratch, sizeof(scratch), " Level %d", se.dlvl );
- strcat( buf, scratch );
- }
- }
-
- if (verbose && se.death_time
- && !hiscore_same_day( se.birth_time, se.death_time ))
- {
- strcat( buf, " on " );
- hiscore_date_string( se.death_time, scratch );
- strcat( buf, scratch );
- }
-
- strcat( buf, "." );
- hiscore_newline( buf, line_count );
- } // endif - killed by winning
-
- if (verbose)
- {
- if (se.real_time > 0)
- {
- char username[80] = "The";
- char tmp[80];
-
-#ifdef MULTIUSER
- if (se.uid > 0)
- {
- struct passwd *pw_entry = getpwuid( se.uid );
- strncpy( username, pw_entry->pw_name, sizeof(username) );
- strncat( username, "'s", sizeof(username) );
- username[0] = toupper( username[0] );
- }
-#endif
-
- make_time_string( se.real_time, tmp, sizeof(tmp) );
-
- snprintf( scratch, INFO_SIZE, "%s game lasted %s (%ld turns).",
- username, tmp, se.num_turns );
-
- strncat( buf, scratch, HIGHSCORE_SIZE );
- hiscore_newline( buf, line_count );
- }
- }
-
- return (line_count);
-}
-
-// --------------------------------------------------------------------------
-// BEGIN private functions
-// --------------------------------------------------------------------------
-
-// first, some file locking stuff for multiuser crawl
-#ifdef USE_FILE_LOCKING
-
-static bool lock_file_handle( FILE *handle, int type )
-{
- struct flock lock;
- int status;
-
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- lock.l_type = type;
-
-#ifdef USE_BLOCKING_LOCK
-
- status = fcntl( fileno( handle ), F_SETLKW, &lock );
-
-#else
-
- for (int i = 0; i < 30; i++)
- {
- status = fcntl( fileno( handle ), F_SETLK, &lock );
-
- // success
- if (status == 0)
- break;
-
- // known failure
- if (status == -1 && (errno != EACCES && errno != EAGAIN))
- break;
-
- perror( "Problems locking file... retrying..." );
- delay( 1000 );
- }
-
-#endif
-
- return (status == 0);
-}
-
-static bool unlock_file_handle( FILE *handle )
-{
- struct flock lock;
- int status;
-
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- lock.l_type = F_UNLCK;
-
-#ifdef USE_BLOCKING_LOCK
-
- status = fcntl( fileno( handle ), F_SETLKW, &lock );
-
-#else
-
- for (int i = 0; i < 30; i++)
- {
- status = fcntl( fileno( handle ), F_SETLK, &lock );
-
- // success
- if (status == 0)
- break;
-
- // known failure
- if (status == -1 && (errno != EACCES && errno != EAGAIN))
- break;
-
- perror( "Problems unlocking file... retrying..." );
- delay( 1000 );
- }
-
-#endif
-
- return (status == 0);
-}
-
-#endif
-
-
-
-FILE *hs_open( const char *mode )
-{
-#ifdef SAVE_DIR_PATH
- FILE *handle = fopen(SAVE_DIR_PATH "scores", mode);
-#ifdef SHARED_FILES_CHMOD_PUBLIC
- chmod(SAVE_DIR_PATH "scores", SHARED_FILES_CHMOD_PUBLIC);
-#endif
-#else
- FILE *handle = fopen("scores", mode);
-#endif
-
-#ifdef USE_FILE_LOCKING
- int locktype = F_RDLCK;
- if (stricmp(mode, "w") == 0)
- locktype = F_WRLCK;
-
- if (handle && !lock_file_handle( handle, locktype ))
- {
- perror( "Could not lock scorefile... " );
- fclose( handle );
- handle = NULL;
- }
-#endif
- return handle;
-}
-
-void hs_close( FILE *handle, const char *mode )
-{
- UNUSED( mode );
-
- if (handle == NULL)
- return;
-
-#ifdef USE_FILE_LOCKING
- unlock_file_handle( handle );
-#endif
-
- // actually close
- fclose(handle);
-
-#ifdef SHARED_FILES_CHMOD_PUBLIC
- if (stricmp(mode, "w") == 0)
- {
- #ifdef SAVE_DIR_PATH
- chmod(SAVE_DIR_PATH "scores", SHARED_FILES_CHMOD_PUBLIC);
- #else
- chmod("scores", SHARED_FILES_CHMOD_PUBLIC);
- #endif
- }
-#endif
-}
-
-static void hs_init( struct scorefile_entry &dest )
-{
- // simple init
- dest.version = 0;
- dest.release = 0;
- dest.points = -1;
- dest.name[0] = '\0';
- dest.uid = 0;
- dest.race = 0;
- dest.cls = 0;
- dest.lvl = 0;
- dest.race_class_name[0] = '\0';
- dest.best_skill = 0;
- dest.best_skill_lvl = 0;
- dest.death_type = KILLED_BY_SOMETHING;
- dest.death_source = 0;
- dest.mon_num = 0;
- dest.death_source_name[0] = '\0';
- dest.auxkilldata[0] = '\0';
- dest.dlvl = 0;
- dest.level_type = 0;
- dest.branch = 0;
- dest.final_hp = -1;
- dest.final_max_hp = -1;
- dest.final_max_max_hp = -1;
- dest.str = -1;
- dest.intel = -1;
- dest.dex = -1;
- dest.damage = -1;
- dest.god = -1;
- dest.piety = -1;
- dest.penance = -1;
- dest.wiz_mode = 0;
- dest.birth_time = 0;
- dest.death_time = 0;
- dest.real_time = -1;
- dest.num_turns = -1;
- dest.num_diff_runes = 0;
- dest.num_runes = 0;
-}
-
-void hs_copy(struct scorefile_entry &dest, struct scorefile_entry &src)
-{
- // simple field copy -- assume src is well constructed.
-
- dest.version = src.version;
- dest.release = src.release;
- dest.points = src.points;
- strcpy(dest.name, src.name);
- dest.uid = src.uid;
- dest.race = src.race;
- dest.cls = src.cls;
- dest.lvl = src.lvl;
- strcpy(dest.race_class_name, src.race_class_name);
- dest.best_skill = src.best_skill;
- dest.best_skill_lvl = src.best_skill_lvl;
- dest.death_type = src.death_type;
- dest.death_source = src.death_source;
- dest.mon_num = src.mon_num;
- strcpy( dest.death_source_name, src.death_source_name );
- strcpy( dest.auxkilldata, src.auxkilldata );
- dest.dlvl = src.dlvl;
- dest.level_type = src.level_type;
- dest.branch = src.branch;
- dest.final_hp = src.final_hp;
- dest.final_max_hp = src.final_max_hp;
- dest.final_max_max_hp = src.final_max_max_hp;
- dest.str = src.str;
- dest.intel = src.intel;
- dest.dex = src.dex;
- dest.damage = src.damage;
- dest.god = src.god;
- dest.piety = src.piety;
- dest.penance = src.penance;
- dest.wiz_mode = src.wiz_mode;
- dest.birth_time = src.birth_time;
- dest.death_time = src.death_time;
- dest.real_time = src.real_time;
- dest.num_turns = src.num_turns;
- dest.num_diff_runes = src.num_diff_runes;
- dest.num_runes = src.num_runes;
-}
-
-bool hs_read( FILE *scores, struct scorefile_entry &dest )
-{
- char inbuf[200];
- int c = EOF;
-
- hs_init( dest );
-
- // get a character..
- if (scores != NULL)
- c = fgetc(scores);
-
- // check for NULL scores file or EOF
- if (scores == NULL || c == EOF)
- 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 true;
-}
-
-static void hs_nextstring(char *&inbuf, char *dest)
-{
- char *p = dest;
-
- if (*inbuf == '\0')
- {
- *p = '\0';
- return;
- }
-
- // assume we're on a ':'
- inbuf ++;
- while(*inbuf != ':' && *inbuf != '\0')
- *p++ = *inbuf++;
-
- *p = '\0';
-}
-
-static int hs_nextint(char *&inbuf)
-{
- char num[20];
- hs_nextstring(inbuf, num);
-
- return (num[0] == '\0' ? 0 : atoi(num));
-}
-
-static long hs_nextlong(char *&inbuf)
-{
- char num[20];
- hs_nextstring(inbuf, num);
-
- return (num[0] == '\0' ? 0 : atol(num));
-}
-
-static int val_char( char digit )
-{
- return (digit - '0');
-}
-
-static time_t hs_nextdate(char *&inbuf)
-{
- char buff[20];
- struct tm date;
-
- hs_nextstring( inbuf, 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 ));
-}
-
-static void hs_parse_numeric(char *inbuf, struct scorefile_entry &se)
-{
- 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);
-
- se.uid = hs_nextlong(inbuf);
- se.race = hs_nextint(inbuf);
- se.cls = hs_nextint(inbuf);
-
- hs_nextstring(inbuf, 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);
-
- // 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 );
- 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;
- }
- }
-
- 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;
- }
-
- se.wiz_mode = hs_nextint(inbuf);
-
- se.birth_time = hs_nextdate(inbuf);
- se.death_time = hs_nextdate(inbuf);
-
- 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);
-}
-
-static void hs_write( FILE *scores, struct scorefile_entry &se )
-{
- char buff[80]; // should be more than enough for date stamps
-
- se.version = 4;
- se.release = 2;
-
- fprintf( scores, ":%d:%d:%ld:%s:%ld:%d:%d:%s:%d:%d:%d",
- se.version, se.release, se.points, se.name,
- se.uid, se.race, se.cls, se.race_class_name, se.lvl,
- se.best_skill, se.best_skill_lvl );
-
- // XXX: need damage
- fprintf( scores, ":%d:%d:%d:%s:%s:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
- se.death_type, se.death_source, se.mon_num,
- se.death_source_name, se.auxkilldata,
- se.dlvl, se.level_type, se.branch,
- se.final_hp, se.final_max_hp, se.final_max_max_hp, se.damage,
- se.str, se.intel, se.dex,
- se.god, se.piety, se.penance, se.wiz_mode );
-
- make_date_string( se.birth_time, buff );
- fprintf( scores, ":%s", buff );
-
- make_date_string( se.death_time, buff );
- fprintf( scores, ":%s", buff );
-
- 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)
-{
- /* old entries are of the following format (Brent introduced some
- spacing at one point, we have to take this into account):
-
- // 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
-
-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.
-
- 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.
-
- Very ugly and time consuming.
-
- */
-
- char scratch[80];
-
- // 1. get score
- hs_parse_generic_2(inbuf, scratch, "0123456789");
-
- se.version = 0; // version # of converted score
- se.release = 0;
- se.points = atoi(scratch);
-
- // 2. get name
- hs_parse_generic_1(inbuf, scratch, "-");
- hs_stripblanks(scratch);
- strcpy(se.name, scratch);
-
- // 3. get race, class
- inbuf++; // skip '-'
- hs_parse_generic_1(inbuf, scratch, "0123456789");
- hs_stripblanks(scratch);
- strcpy(se.race_class_name, scratch);
- se.race = 0;
- se.cls = 0;
-
- // 4. get clevel
- hs_parse_generic_2(inbuf, scratch, "0123456789");
- se.lvl = atoi(scratch);
-
- // 4a. get wizard mode
- hs_parse_generic_1(inbuf, scratch, ",");
- if (strstr(scratch, "Wiz") != NULL)
- se.wiz_mode = 1;
- else
- se.wiz_mode = 0;
-
- // 5. get death type
- inbuf++; // skip comma
- 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, const char *stopvalues)
-{
- char *p = outbuf;
-
- while(strchr(stopvalues, *inbuf) == NULL && *inbuf != '\0')
- *p++ = *inbuf++;
-
- *p = '\0';
-}
-
-static void hs_parse_generic_2(char *&inbuf, char *outbuf, const char *continuevalues)
-{
- char *p = outbuf;
-
- while(strchr(continuevalues, *inbuf) != NULL && *inbuf != '\0')
- *p++ = *inbuf++;
-
- *p = '\0';
-}
-
-static void hs_stripblanks(char *buf)
-{
- char *p = buf;
- char *q = buf;
-
- // strip leading
- while(*p == ' ')
- p++;
- while(*p != '\0')
- *q++ = *p++;
-
- *q-- = '\0';
- // strip trailing
- while(*q == ' ')
- {
- *q = '\0';
- q--;
- }
-}
-
-static void hs_search_death(char *inbuf, struct scorefile_entry &se)
-{
- // assume killed by monster
- se.death_type = KILLED_BY_MONSTER;
-
- // 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)
- {
- if (strstr(inbuf, "killed by") == NULL)
- se.death_type = KILLED_BY_SOMETHING;
- }
-
- // set some fields
- se.death_source = 0;
- se.mon_num = 0;
- strcpy(se.death_source_name, "");
-
- // now try to pull the monster out.
- if (se.death_type == KILLED_BY_MONSTER || se.death_type == KILLED_BY_BEAM)
- {
- char *p = strstr(inbuf, " by ");
- p += 4;
- char *q = strstr(inbuf, " on ");
- if (q == NULL)
- q = strstr(inbuf, " in ");
- char *d = se.death_source_name;
- while(p != q)
- *d++ = *p++;
-
- *d = '\0';
- }
-}
-
-static void hs_search_where(char *inbuf, struct scorefile_entry &se)
-{
- char scratch[6];
-
- se.level_type = LEVEL_DUNGEON;
- se.branch = BRANCH_MAIN_DUNGEON;
- se.dlvl = 0;
-
- // early out
- if (se.death_type == KILLED_BY_LEAVING || se.death_type == KILLED_BY_WINNING)
- return;
-
- // 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;
-
- // early out for special level types
- if (se.level_type != LEVEL_DUNGEON)
- return;
-
- // check for vestible
- if (strstr(inbuf, "in the Vestibule") != NULL)
- {
- se.branch = BRANCH_VESTIBULE_OF_HELL;
- return;
- }
-
- // from here, we have branch and level.
- char *p = strstr(inbuf, "on L");
- if (p != NULL)
- {
- p += 4;
- hs_parse_generic_2(p, scratch, "0123456789");
- se.dlvl = atoi( scratch );
- }
-
- // 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;
-}