Remove saving grace
This feature was no longer fulfilling its intended purpose: the issue is that when players are aware of it, instead of creating interesting stories, it becomes a resource the player can rely on. Alternative mitigation for some "unfair" early-game deaths has been added (such as the warning shot for early-game attack wands and the ability of iron shoes to protect against certain early traps), and the warning shot in particular can create interesting gameplay moments and stories of its own, especially when saving grace is *not* present (discovering that a monster has a wand of fire and can oneshot you is an interesting emergency situation, but less scary if you know that its first attempt to oneshot you will fail). The feature was also proving quite hard to code correctly, because there are numerous cases that it "obviously" shouldn't affect (most notably beheading due to Vorpal Blade, but also things like purple worm digestion) which would need to be special-cased, and because there are grey areas like wand zap bounces (which might or might not be an intentional attempt by the player to hit themself with the bounce) and damage from traps. Removing it saves the need to work out, for every new damage source, whether and when saving grace should interact with it. Breaks save compatibility.
This commit is contained in:
@@ -2219,9 +2219,6 @@ uncursed genocide while hallucinating deliberately mis-reports hero's role as
|
||||
target but was also inappropriately showing it to livelog/#chronicle
|
||||
livelog/#chronicle for bribing a demon lord reported random monster and
|
||||
currency if hero was hallucinating
|
||||
livelog/#chronicle for saving-grace: if saving-grace prevents hero's death,
|
||||
report it [at present, it uses the livelog classification for breaking
|
||||
a conduct]
|
||||
naming a type of item, unnaming it (with name of <space>), naming it again
|
||||
(new name or re-use of old one), then unnaming it again would issue
|
||||
impossible: "named object not in disco"
|
||||
@@ -2904,11 +2901,6 @@ pyrolisk eggs explode when broken
|
||||
pauper-option to start the character with no possessions
|
||||
wand of secret door detection, spell of detect unseen, and wizard mode ^E now
|
||||
flash the cursor at each location where detection finds something
|
||||
saving-grace: once per game if receiving a killing blow from full or nearly
|
||||
full HP, survive with 1 HP
|
||||
enlightenment/attribute disclosure for saving-grace: include a line for have
|
||||
or haven't been saved (game in progress) or did or didn't get saved
|
||||
(game over) via saving-grace
|
||||
'selectsaved' lists "name-role-race-gend-algn" instead of just "name" in the
|
||||
menu of save files available to be restored
|
||||
'selectsaved' prefixes "name-role-race-gend-algn" with "- " for normal play,
|
||||
|
||||
@@ -840,9 +840,6 @@ struct instance_globals_r {
|
||||
|
||||
struct instance_globals_s {
|
||||
|
||||
/* allmain.c */
|
||||
boolean saving_grace_turn; /* saving grace was triggered this turn */
|
||||
|
||||
/* artifact.c */
|
||||
int spec_dbon_applies; /* coordinate effects from spec_dbon() with
|
||||
messages in artifact_hit() */
|
||||
@@ -974,9 +971,6 @@ struct instance_globals_t {
|
||||
|
||||
struct instance_globals_u {
|
||||
|
||||
/* allmain.c */
|
||||
int uhp_at_start_of_monster_turn;
|
||||
|
||||
/* botl.c */
|
||||
boolean update_all;
|
||||
|
||||
|
||||
@@ -1236,7 +1236,6 @@ extern int monster_nearby(void);
|
||||
extern void end_running(boolean);
|
||||
extern void nomul(int);
|
||||
extern void unmul(const char *);
|
||||
extern int saving_grace(int);
|
||||
extern void showdamage(int);
|
||||
extern void losehp(int, const char *, schar) ;
|
||||
extern int weight_cap(void);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 142
|
||||
#define EDITLEVEL 143
|
||||
|
||||
/*
|
||||
* Development status possibilities.
|
||||
|
||||
@@ -428,7 +428,6 @@ struct you {
|
||||
Bitfield(uinvulnerable, 1); /* you're invulnerable (praying) */
|
||||
Bitfield(uburied, 1); /* you're buried */
|
||||
Bitfield(uedibility, 1); /* blessed food detect; sense unsafe food */
|
||||
Bitfield(usaving_grace, 1); /* prevents death once */
|
||||
Bitfield(uhandedness, 1); /* There is no advantage for either handedness.
|
||||
The distinction is only for flavor variation
|
||||
and for use in messages. */
|
||||
|
||||
@@ -208,7 +208,6 @@ moveloop_core(void)
|
||||
encumber_msg();
|
||||
|
||||
svc.context.mon_moving = TRUE;
|
||||
gu.uhp_at_start_of_monster_turn = u.uhp;
|
||||
do {
|
||||
monscanmove = movemon();
|
||||
if (u.umovement >= NORMAL_SPEED)
|
||||
@@ -277,8 +276,6 @@ moveloop_core(void)
|
||||
if (u.ublesscnt)
|
||||
u.ublesscnt--;
|
||||
|
||||
gs.saving_grace_turn = FALSE;
|
||||
|
||||
/* One possible result of prayer is healing. Whether or
|
||||
* not you get healed depends on your current hit points.
|
||||
* If you are allowed to regenerate during the prayer,
|
||||
@@ -430,8 +427,6 @@ moveloop_core(void)
|
||||
else if (!u.umoved)
|
||||
(void) pooleffects(FALSE);
|
||||
|
||||
gs.saving_grace_turn = FALSE;
|
||||
|
||||
/* vision while buried or underwater is updated here */
|
||||
if (Underwater)
|
||||
under_water(0);
|
||||
|
||||
@@ -675,8 +675,6 @@ static const struct instance_globals_r g_init_r = {
|
||||
};
|
||||
|
||||
static const struct instance_globals_s g_init_s = {
|
||||
/* allmain.c */
|
||||
FALSE, /* saving_grace_turn */
|
||||
/* artifact.c */
|
||||
0, /* spec_dbon_applies */
|
||||
/* decl.c */
|
||||
@@ -767,8 +765,6 @@ static const struct instance_globals_t g_init_t = {
|
||||
};
|
||||
|
||||
static const struct instance_globals_u g_init_u = {
|
||||
/* allmain.c */
|
||||
0, /* uhp_at_start_of_monster_turn */
|
||||
/* botl.c */
|
||||
FALSE, /* update_all */
|
||||
/* decl.c */
|
||||
|
||||
-55
@@ -4242,60 +4242,6 @@ maybe_wail(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* once per game, if receiving a killing blow from above 90% HP,
|
||||
allow the hero to survive with 1 HP */
|
||||
int
|
||||
saving_grace(int dmg)
|
||||
{
|
||||
if (dmg < 0) {
|
||||
impossible("saving_grace check for negative damage? (%d)", dmg);
|
||||
return 0;
|
||||
}
|
||||
#if 0 /* saving grace _does_ protect hero during own actions */
|
||||
if (!svc.context.mon_moving) {
|
||||
/* saving grace doesn't protect you from your own actions */
|
||||
return dmg;
|
||||
}
|
||||
#endif
|
||||
if (dmg < u.uhp || u.uhp <= 0) {
|
||||
/* no need for saving grace */
|
||||
return dmg;
|
||||
}
|
||||
|
||||
if (gs.saving_grace_turn) {
|
||||
/* saving grace already triggered and prevents HP reducing below 1
|
||||
this turn (specifically: until the next player action or turn
|
||||
boundary), don't print further messages or livelog entries */
|
||||
return u.uhp - 1;
|
||||
}
|
||||
|
||||
if (!u.usaving_grace &&
|
||||
(gu.uhp_at_start_of_monster_turn * 100 / u.uhpmax) >= 90) {
|
||||
/* saving_grace doesn't have it's own livelog classification;
|
||||
we might invent one, or perhaps use LL_LIFESAVE, but surviving
|
||||
certain death (or preserving worn amulet of life saving) via
|
||||
saving-grace feels like breaking a conduct; not sure how best
|
||||
to phrase this though; classifying it as a spoiler will hide it
|
||||
from #chronicle during play but show it to livelog observers */
|
||||
livelog_printf(LL_CONDUCT | LL_SPOILER, "%s (%d damage, %d/%d HP)",
|
||||
"survived one-shot death via saving-grace",
|
||||
/* include damage that happened earlier this turn */
|
||||
gu.uhp_at_start_of_monster_turn - u.uhp + dmg,
|
||||
gu.uhp_at_start_of_monster_turn, u.uhpmax);
|
||||
|
||||
/* note: this could reduce dmg to 0 if u.uhpmax==1 */
|
||||
dmg = u.uhp - 1;
|
||||
u.usaving_grace = 1; /* used up */
|
||||
gs.saving_grace_turn = TRUE;
|
||||
end_running(TRUE);
|
||||
if (u.usleep)
|
||||
unmul("Suddenly you wake up!");
|
||||
if (is_fainted())
|
||||
reset_faint();
|
||||
}
|
||||
return dmg;
|
||||
}
|
||||
|
||||
/* show a message how much damage you received */
|
||||
void
|
||||
showdamage(int dmg)
|
||||
@@ -4330,7 +4276,6 @@ losehp(int n, const char *knam, schar k_format)
|
||||
return;
|
||||
}
|
||||
|
||||
n = saving_grace(n);
|
||||
u.uhp -= n;
|
||||
showdamage(n);
|
||||
if (u.uhp > u.uhpmax)
|
||||
|
||||
@@ -1974,21 +1974,6 @@ attributes_enlightenment(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* saving-grace: show during final disclosure, hide during normal play */
|
||||
if (final || wizard || discover) {
|
||||
static const char *verbchoices[2][2] = {
|
||||
{ "might avoid", "have avoided" },
|
||||
{ "could have avoided", "avoided" },
|
||||
};
|
||||
/* u.usaving_grace will always be 0 or 1; final is 0 (game in
|
||||
progress), 1 (game over, survived), or 2 (game over, died) */
|
||||
const char *verb = verbchoices[!!final][u.usaving_grace];
|
||||
|
||||
/* 'verb' has already been set for present or past but enl_msg()
|
||||
needs it twice, one for in progress, the other for game over */
|
||||
enl_msg(You_, verb, verb, " a one-shot death via saving-grace", "");
|
||||
}
|
||||
|
||||
{
|
||||
const char *p;
|
||||
|
||||
|
||||
@@ -1916,7 +1916,6 @@ mdamageu(struct monst *mtmp, int n)
|
||||
if (u.mh < 1)
|
||||
rehumanize();
|
||||
} else {
|
||||
n = saving_grace(n);
|
||||
u.uhp -= n;
|
||||
showdamage(n);
|
||||
/* caller might have reduced uhpmax before calling mdamageu() */
|
||||
|
||||
Reference in New Issue
Block a user