Extended achievement and conduct fields for xlogfile

Introducing two new xlogfile fields "achieveX" and "conductX" which encode
achievements and conducts as a series of comma-separated strings which are
more easily parseable and also somewhat interpretable independent from knowing
the source code.

Example for a player that died shortly after picking up the luckstone from the
gnomisch mines:
achieveX=entered_the_gnomish_mines,entered_mine_town,entered_a_shop,entered_a_temple,obtained_the_luckstone_from_the_mines
conductX=polyless,polyselfless,wishless,artiwishless,genocideless
This commit is contained in:
Patric Mueller
2020-04-24 20:59:14 +02:00
parent e63fed627c
commit 0e4ff07cef
2 changed files with 130 additions and 3 deletions

View File

@@ -303,6 +303,7 @@ item-using monsters will zap wand of undead turning at corpse-wielding hero
when the corpse is harmful
boiling a pool or fountain now creates a temporary cloud of steam
random themed rooms in the dungeons of doom
extended achievement and conduct fields for xlogfile
Platform- and/or Interface-Specific New Features

View File

@@ -11,10 +11,10 @@
#include "patchlevel.h"
#endif
/* If UPDATE_RECORD_IN_PLACE is defined, we don't want to rewrite the
* whole file, because that entails creating a new version which
/* If UPDATE_RECORD_IN_PLACE is defined, we don't want to rewrite the
* whole file, because that entails creating a new version which
* requires that the old one be deletable. UPDATE_RECORD_IN_PLACE
* had to be defined more centrally in 3.7 to ensure that the
* had to be defined more centrally in 3.7 to ensure that the
* final_fpos field gets included in struct instance_globals aka 'g'.
*/
@@ -71,6 +71,9 @@ static void FDECL(writexlentry, (FILE *, struct toptenentry *, int));
static long NDECL(encodexlogflags);
static long NDECL(encodeconduct);
static long FDECL(encodeachieve, (BOOLEAN_P));
static void FDECL(add_achieveX, (char *, const char *, BOOLEAN_P));
static char *NDECL(encode_extended_achievements);
static char *NDECL(encode_extended_conducts);
#endif
static void FDECL(free_ttlist, (struct toptenentry *));
static int FDECL(classmon, (char *, BOOLEAN_P));
@@ -367,6 +370,8 @@ int how;
Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP,
encodeconduct(), XLOG_SEP, g.moves, XLOG_SEP,
encodeachieve(FALSE));
Fprintf(rfile, "%cachieveX=%s", XLOG_SEP, encode_extended_achievements());
Fprintf(rfile, "%cconductX=%s", XLOG_SEP, encode_extended_conducts());
Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP,
(long) urealtime.realtime, XLOG_SEP,
(long) ubirthday, XLOG_SEP, (long) urealtime.finish_time);
@@ -450,6 +455,127 @@ boolean secondlong; /* False: handle achievements 1..31, True: 32..62 */
return r;
}
/* add the achievement or conduct comma-separated to string */
static void
add_achieveX(buf, achievement, condition)
char *buf;
const char *achievement;
boolean condition;
{
if (condition) {
if (buf[0] != '\0') {
Strcat(buf, ",");
}
Strcat(buf, achievement);
}
}
static char *
encode_extended_achievements()
{
static char buf[N_ACH*40];
const char *achievement = NULL;
int i;
buf[0] = '\0';
for (i = 0; u.uachieved[i]; i++) {
switch (u.uachieved[i]) {
case ACH_UWIN:
achievement = "ascended";
break;
case ACH_ASTR:
achievement = "entered_astral_plane";
break;
case ACH_ENDG:
achievement = "entered_elemental_planes";
break;
case ACH_AMUL:
achievement = "obtained_the_amulet_of_yendor";
break;
case ACH_INVK:
achievement = "performed_the_invocation_ritual";
break;
case ACH_BOOK:
achievement = "obtained_the_book_of_the_dead";
break;
case ACH_BELL:
achievement = "obtained_the_bell_of_opening";
break;
case ACH_CNDL:
achievement = "obtained_the_candelabrum_of_invocation";
break;
case ACH_HELL:
achievement = "entered_gehennom";
break;
case ACH_MEDU:
achievement = "defeated_medusa";
break;
case ACH_MINE_PRIZE:
achievement = "obtained_the_luckstone_from_the_mines";
break;
case ACH_SOKO_PRIZE:
achievement = "obtained_the_sokoban_prize";
break;
case ACH_ORCL:
achievement = "consulted_the_oracle";
break;
case ACH_NOVL:
achievement = "read_a_discworld_novel";
break;
case ACH_MINE:
achievement = "entered_the_gnomish_mines";
break;
case ACH_TOWN:
achievement = "entered_mine_town";
break;
case ACH_SHOP:
achievement = "entered_a_shop";
break;
case ACH_TMPL:
achievement = "entered_a_temple";
break;
case ACH_SOKO:
achievement = "entered_sokoban";
break;
case ACH_BGRM:
achievement = "entered_bigroom";
break;
default:
continue;
}
add_achieveX(buf, achievement, TRUE);
}
return buf;
}
static char *
encode_extended_conducts()
{
static char buf[BUFSZ];
const char *achievement = NULL;
int i;
buf[0] = '\0';
add_achieveX(buf, "foodless", !u.uconduct.food);
add_achieveX(buf, "vegan", !u.uconduct.unvegan);
add_achieveX(buf, "vegetarian", !u.uconduct.unvegetarian);
add_achieveX(buf, "atheist", !u.uconduct.gnostic);
add_achieveX(buf, "weaponless", !u.uconduct.weaphit);
add_achieveX(buf, "pacifist", !u.uconduct.killer);
add_achieveX(buf, "illiterate", !u.uconduct.literate);
add_achieveX(buf, "polyless", !u.uconduct.polypiles);
add_achieveX(buf, "polyselfless", !u.uconduct.polyselfs);
add_achieveX(buf, "wishless", !u.uconduct.wishes);
add_achieveX(buf, "artiwishless", !u.uconduct.wisharti);
add_achieveX(buf, "genocideless", !num_genocides());
add_achieveX(buf, "blind", u.uroleplay.blind);
add_achieveX(buf, "nudist", u.uroleplay.nudist);
return buf;
}
#endif /* XLOGFILE */
static void