track eight more achievements

Record reaching experience level 3, 6, 10, 14, 18, 22, 26, and 30,
the levels where the character gets a new rank title, and report
those as achievements at end of game.  These achievements persist
even if enough levels to lose a rank are lost, and if lost ranks
are regained the original achievement is the one that gets tracked
and disclosed.
This commit is contained in:
PatR
2020-05-04 16:35:40 -07:00
parent 16562b2892
commit 116642ce1e
8 changed files with 117 additions and 28 deletions

View File

@@ -270,18 +270,37 @@ int
xlev_to_rank(xlev)
int xlev;
{
/*
* 1..2 => 0
* 3..5 => 1
* 6..9 => 2
* 10..13 => 3
* ...
* 26..29 => 7
* 30 => 8
* Conversion is precise but only partially reversible.
*/
return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8;
}
#if 0 /* not currently needed */
/* convert rank index (0..8) to experience level (1..30) */
int
rank_to_xlev(rank)
int rank;
{
return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30;
/*
* 0 => 1..2
* 1 => 3..5
* 2 => 6..9
* 3 => 10..13
* ...
* 7 => 26..29
* 8 => 30
* We return the low end of each range.
*/
return (rank < 1) ? 1 : (rank < 2) ? 3
: (rank < 8) ? ((rank * 4) - 2) : 30;
}
#endif
const char *
rank_of(lev, monnum, female)

View File

@@ -299,9 +299,12 @@ boolean incr; /* true iff via incremental experience growth */
/* increase level (unless already maxxed) */
if (u.ulevel < MAXULEV) {
int newrank, oldrank = xlev_to_rank(u.ulevel);
/* increase experience points to reflect new level */
if (incr) {
long tmp = newuexp(u.ulevel + 1);
if (u.uexp >= tmp)
u.uexp = tmp - 1;
} else {
@@ -314,6 +317,9 @@ boolean incr; /* true iff via incremental experience growth */
if (u.ulevelmax < u.ulevel)
u.ulevelmax = u.ulevel;
adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */
newrank = xlev_to_rank(u.ulevel);
if (newrank > oldrank)
record_achievement(achieve_rank(newrank));
}
g.context.botl = TRUE;
}

View File

@@ -1882,8 +1882,8 @@ static void
show_achievements(final)
int final; /* used "behind the curtain" by enl_foo() macros */
{
int i, achidx, acnt;
char title[BUFSZ];
int i, achidx, absidx, acnt;
char title[QBUFSZ], buf[QBUFSZ];
winid awin = WIN_ERR;
/* unfortunately we can't show the achievements (at least not all of
@@ -1922,8 +1922,9 @@ int final; /* used "behind the curtain" by enl_foo() macros */
}
for (i = 0; i < acnt; ++i) {
achidx = u.uachieved[i];
absidx = abs(achidx);
switch (achidx) {
switch (absidx) {
case ACH_BLND:
enl_msg(You_, "are exploring", "explored",
" without being able to see", "");
@@ -2013,10 +2014,19 @@ int final; /* used "behind the curtain" by enl_foo() macros */
/* the ultimate achievement... */
enlght_out(" You ascended!");
break;
/* rank 0 is the starting condition, not an achievement; 8 is Xp 30 */
case ACH_RNK1: case ACH_RNK2: case ACH_RNK3: case ACH_RNK4:
case ACH_RNK5: case ACH_RNK6: case ACH_RNK7: case ACH_RNK8:
Sprintf(buf, "attained the rank of %s",
rank_of(rank_to_xlev(absidx - (ACH_RNK1 - 1)),
Role_switch, (achidx < 0) ? TRUE : FALSE));
you_have_X(buf);
break;
default:
/* title[] has served its purpose, reuse it as a scratch buffer */
Sprintf(title, " [Unexpected achievement #%d.]", achidx);
enlght_out(title);
Sprintf(buf, " [Unexpected achievement #%d.]", achidx);
enlght_out(buf);
break;
} /* switch */
} /* for */
@@ -2030,12 +2040,15 @@ int final; /* used "behind the curtain" by enl_foo() macros */
/* record an achievement (add at end of list unless already present) */
void
record_achievement(achidx)
xchar achidx;
schar achidx;
{
int i;
int i, absidx;
/* valid achievements range from 1 to N_ACH-1 */
if (achidx < 1 || achidx >= N_ACH) {
absidx = abs(achidx);
/* valid achievements range from 1 to N_ACH-1; however, ranks can be
stored as the complement (ie, negative) to track gender */
if ((achidx < 1 && (absidx < ACH_RNK1 || absidx > ACH_RNK8))
|| achidx >= N_ACH) {
impossible("Achievement #%d is out of range.", achidx);
return;
}
@@ -2046,7 +2059,7 @@ xchar achidx;
an attempt to duplicate an achievement can happen if any of Bell,
Candelabrum, Book, or Amulet is dropped then picked up again */
for (i = 0; u.uachieved[i]; ++i)
if (u.uachieved[i] == achidx)
if (abs(u.uachieved[i]) == abs(achidx))
return; /* already recorded, don't duplicate it */
u.uachieved[i] = achidx;
return;
@@ -2055,12 +2068,12 @@ xchar achidx;
/* discard a recorded achievement; return True if removed, False otherwise */
boolean
remove_achievement(achidx)
xchar achidx;
schar achidx;
{
int i;
for (i = 0; u.uachieved[i]; ++i)
if (u.uachieved[i] == achidx)
if (abs(u.uachieved[i]) == abs(achidx))
break; /* stop when found */
if (!u.uachieved[i]) /* not found */
return FALSE;
@@ -2082,6 +2095,19 @@ count_achievements()
return acnt;
}
/* convert a rank index to an achievement number; encode it when female
in order to subsequently report gender-specific ranks accurately */
schar
achieve_rank(rank)
int rank; /* 1..8 */
{
schar achidx = (schar) ((rank - 1) + ACH_RNK1);
if (flags.female)
achidx = -achidx;
return achidx;
}
/*
* Vanquished monsters.
*/

View File

@@ -474,13 +474,16 @@ boolean condition;
static char *
encode_extended_achievements()
{
static char buf[N_ACH*40];
static char buf[N_ACH * 40];
char rnkbuf[40];
const char *achievement = NULL;
int i;
int i, achidx, absidx;
buf[0] = '\0';
for (i = 0; u.uachieved[i]; i++) {
switch (u.uachieved[i]) {
achidx = u.uachieved[i];
absidx = abs(achidx);
switch (absidx) {
case ACH_UWIN:
achievement = "ascended";
break;
@@ -517,7 +520,6 @@ encode_extended_achievements()
case ACH_SOKO_PRIZE:
achievement = "obtained_the_sokoban_prize";
break;
case ACH_ORCL:
achievement = "consulted_the_oracle";
break;
@@ -542,6 +544,15 @@ encode_extended_achievements()
case ACH_BGRM:
achievement = "entered_bigroom";
break;
/* rank 0 is the starting condition, not an achievement; 8 is Xp 30 */
case ACH_RNK1: case ACH_RNK2: case ACH_RNK3: case ACH_RNK4:
case ACH_RNK5: case ACH_RNK6: case ACH_RNK7: case ACH_RNK8:
Sprintf(rnkbuf, "attained_the_rank_of_%s",
rank_of(rank_to_xlev(absidx - (ACH_RNK1 - 1)),
Role_switch, (achidx < 0) ? TRUE : FALSE));
strNsubst(rnkbuf, " ", "_", 0); /* replace every ' ' with '_' */
achievement = lcase(rnkbuf);
break;
default:
continue;
}