fix #K3472 - stale perm_invent when engraving
Engraving with a weapon which has known enchantment or with a magic
marker which has known charge count that decremented the amount did
so without updating the persistent inventory display. Report was
for curses but applied to every interface that can show perm_invent.
This includes some reformatting (mostly
if {
}
else {
}
to
if {
} else {
}
multiple times; also add some new braces after 'if' or 'else' where
one half already had those and the other didn't). And removal of
some unnecessary 'register' designators.
Plus fix up one sanity check which complained if number of charges
being used was more than a marker had, but then let the engraving
continue and decrement the count by that large amount. If that
impossible situation ever occurred, it would result in a marker
with negative charges.
This commit is contained in:
@@ -556,6 +556,8 @@ shopkeepers can remove pits and webs
|
|||||||
perm_invent: when buying shop goods using itemized purchasing while persistent
|
perm_invent: when buying shop goods using itemized purchasing while persistent
|
||||||
inventory window was enabled, the prices of unpaid items went away as
|
inventory window was enabled, the prices of unpaid items went away as
|
||||||
soon as any item was bought (actual item-by-item purchase worked ok)
|
soon as any item was bought (actual item-by-item purchase worked ok)
|
||||||
|
perm_invent: making an engraving which reduced known enchantment of a weapon
|
||||||
|
or known charge count of a marker didn't update persistent inventory
|
||||||
change getloc fastmove keys in number_pad mode from hardcoded HJKL to the
|
change getloc fastmove keys in number_pad mode from hardcoded HJKL to the
|
||||||
run/rush movement keys (meta+number)
|
run/rush movement keys (meta+number)
|
||||||
allow using rush/run prefix key in getloc to fastmove the cursor
|
allow using rush/run prefix key in getloc to fastmove the cursor
|
||||||
|
|||||||
111
src/engrave.c
111
src/engrave.c
@@ -79,18 +79,21 @@ static const struct {
|
|||||||
|
|
||||||
/* degrade some of the characters in a string */
|
/* degrade some of the characters in a string */
|
||||||
void
|
void
|
||||||
wipeout_text(char *engr, int cnt,
|
wipeout_text(
|
||||||
unsigned seed) /* for semi-controlled randomization */
|
char *engr, /* engraving text */
|
||||||
|
int cnt, /* number of chars to degrade */
|
||||||
|
unsigned seed) /* for semi-controlled randomization */
|
||||||
{
|
{
|
||||||
char *s;
|
char *s;
|
||||||
int i, j, nxt, use_rubout, lth = (int) strlen(engr);
|
int i, j, nxt, use_rubout;
|
||||||
|
unsigned lth = (unsigned) strlen(engr);
|
||||||
|
|
||||||
if (lth && cnt > 0) {
|
if (lth && cnt > 0) {
|
||||||
while (cnt--) {
|
while (cnt--) {
|
||||||
/* pick next character */
|
/* pick next character */
|
||||||
if (!seed) {
|
if (!seed) {
|
||||||
/* random */
|
/* random */
|
||||||
nxt = rn2(lth);
|
nxt = rn2((int) lth);
|
||||||
use_rubout = rn2(4);
|
use_rubout = rn2(4);
|
||||||
} else {
|
} else {
|
||||||
/* predictable; caller can reproduce the same sequence by
|
/* predictable; caller can reproduce the same sequence by
|
||||||
@@ -110,23 +113,25 @@ wipeout_text(char *engr, int cnt,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!use_rubout)
|
if (!use_rubout) {
|
||||||
i = SIZE(rubouts);
|
i = SIZE(rubouts);
|
||||||
else
|
} else {
|
||||||
for (i = 0; i < SIZE(rubouts); i++)
|
for (i = 0; i < SIZE(rubouts); i++)
|
||||||
if (*s == rubouts[i].wipefrom) {
|
if (*s == rubouts[i].wipefrom) {
|
||||||
|
unsigned ln = (unsigned) strlen(rubouts[i].wipeto);
|
||||||
/*
|
/*
|
||||||
* Pick one of the substitutes at random.
|
* Pick one of the substitutes at random.
|
||||||
*/
|
*/
|
||||||
if (!seed)
|
if (!seed) {
|
||||||
j = rn2(strlen(rubouts[i].wipeto));
|
j = rn2((int) ln);
|
||||||
else {
|
} else {
|
||||||
seed *= 31, seed %= (BUFSZ - 1);
|
seed *= 31, seed %= (BUFSZ - 1);
|
||||||
j = seed % (strlen(rubouts[i].wipeto));
|
j = seed % ln;
|
||||||
}
|
}
|
||||||
*s = rubouts[i].wipeto[j];
|
*s = rubouts[i].wipeto[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* didn't pick rubout; use '?' for unreadable character */
|
/* didn't pick rubout; use '?' for unreadable character */
|
||||||
if (i == SIZE(rubouts))
|
if (i == SIZE(rubouts))
|
||||||
@@ -182,9 +187,9 @@ cant_reach_floor(int x, int y, boolean up, boolean check_pit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
surface(register int x, register int y)
|
surface(int x, int y)
|
||||||
{
|
{
|
||||||
register struct rm *lev = &levl[x][y];
|
struct rm *lev = &levl[x][y];
|
||||||
|
|
||||||
if (x == u.ux && y == u.uy && u.uswallow && is_animal(u.ustuck->data))
|
if (x == u.ux && y == u.uy && u.uswallow && is_animal(u.ustuck->data))
|
||||||
return "maw";
|
return "maw";
|
||||||
@@ -213,9 +218,9 @@ surface(register int x, register int y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
ceiling(register int x, register int y)
|
ceiling(int x, int y)
|
||||||
{
|
{
|
||||||
register struct rm *lev = &levl[x][y];
|
struct rm *lev = &levl[x][y];
|
||||||
const char *what;
|
const char *what;
|
||||||
|
|
||||||
/* other room types will no longer exist when we're interested --
|
/* other room types will no longer exist when we're interested --
|
||||||
@@ -308,7 +313,7 @@ wipe_engr_at(xchar x, xchar y, xchar cnt, boolean magical)
|
|||||||
void
|
void
|
||||||
read_engr_at(int x, int y)
|
read_engr_at(int x, int y)
|
||||||
{
|
{
|
||||||
register struct engr *ep = engr_at(x, y);
|
struct engr *ep = engr_at(x, y);
|
||||||
int sensed = 0;
|
int sensed = 0;
|
||||||
|
|
||||||
/* Sensing an engraving does not require sight,
|
/* Sensing an engraving does not require sight,
|
||||||
@@ -407,7 +412,7 @@ make_engr_at(int x, int y, const char *s, long e_time, xchar e_type)
|
|||||||
void
|
void
|
||||||
del_engr_at(int x, int y)
|
del_engr_at(int x, int y)
|
||||||
{
|
{
|
||||||
register struct engr *ep = engr_at(x, y);
|
struct engr *ep = engr_at(x, y);
|
||||||
|
|
||||||
if (ep)
|
if (ep)
|
||||||
del_engr(ep);
|
del_engr(ep);
|
||||||
@@ -565,8 +570,9 @@ doengrave(void)
|
|||||||
if (otmp == &cg.zeroobj) {
|
if (otmp == &cg.zeroobj) {
|
||||||
Strcat(strcpy(fbuf, "your "), body_part(FINGERTIP));
|
Strcat(strcpy(fbuf, "your "), body_part(FINGERTIP));
|
||||||
writer = fbuf;
|
writer = fbuf;
|
||||||
} else
|
} else {
|
||||||
writer = yname(otmp);
|
writer = yname(otmp);
|
||||||
|
}
|
||||||
|
|
||||||
/* There's no reason you should be able to write with a wand
|
/* There's no reason you should be able to write with a wand
|
||||||
* while both your hands are tied up.
|
* while both your hands are tied up.
|
||||||
@@ -805,10 +811,11 @@ doengrave(void)
|
|||||||
if (!Blind) {
|
if (!Blind) {
|
||||||
Strcpy(post_engr_text, "Lightning arcs from the wand.");
|
Strcpy(post_engr_text, "Lightning arcs from the wand.");
|
||||||
doblind = TRUE;
|
doblind = TRUE;
|
||||||
} else
|
} else {
|
||||||
Strcpy(post_engr_text, !Deaf
|
Strcpy(post_engr_text, !Deaf
|
||||||
? "You hear crackling!" /* Deaf-aware */
|
? "You hear crackling!" /* Deaf-aware */
|
||||||
: "Your hair stands up!");
|
: "Your hair stands up!");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* type = MARK wands */
|
/* type = MARK wands */
|
||||||
@@ -855,7 +862,7 @@ doengrave(void)
|
|||||||
case TOWEL:
|
case TOWEL:
|
||||||
/* Can't really engrave with a towel */
|
/* Can't really engrave with a towel */
|
||||||
ptext = FALSE;
|
ptext = FALSE;
|
||||||
if (oep)
|
if (oep) {
|
||||||
if (oep->engr_type == DUST
|
if (oep->engr_type == DUST
|
||||||
|| oep->engr_type == ENGR_BLOOD
|
|| oep->engr_type == ENGR_BLOOD
|
||||||
|| oep->engr_type == MARK) {
|
|| oep->engr_type == MARK) {
|
||||||
@@ -867,11 +874,13 @@ doengrave(void)
|
|||||||
pline("%s %s.", Yobjnam2(otmp, "get"),
|
pline("%s %s.", Yobjnam2(otmp, "get"),
|
||||||
is_ice(u.ux, u.uy) ? "frosty" : "dusty");
|
is_ice(u.ux, u.uy) ? "frosty" : "dusty");
|
||||||
dengr = TRUE;
|
dengr = TRUE;
|
||||||
} else
|
} else {
|
||||||
pline("%s can't wipe out this engraving.", Yname2(otmp));
|
pline("%s can't wipe out this engraving.", Yname2(otmp));
|
||||||
else
|
}
|
||||||
|
} else {
|
||||||
pline("%s %s.", Yobjnam2(otmp, "get"),
|
pline("%s %s.", Yobjnam2(otmp, "get"),
|
||||||
is_ice(u.ux, u.uy) ? "frosty" : "dusty");
|
is_ice(u.ux, u.uy) ? "frosty" : "dusty");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -949,7 +958,7 @@ doengrave(void)
|
|||||||
* possible) by now.
|
* possible) by now.
|
||||||
*/
|
*/
|
||||||
if (oep) {
|
if (oep) {
|
||||||
register char c = 'n';
|
char c = 'n';
|
||||||
|
|
||||||
/* Give player the choice to add to engraving. */
|
/* Give player the choice to add to engraving. */
|
||||||
if (type == HEADSTONE) {
|
if (type == HEADSTONE) {
|
||||||
@@ -979,10 +988,10 @@ doengrave(void)
|
|||||||
: "written");
|
: "written");
|
||||||
del_engr(oep);
|
del_engr(oep);
|
||||||
oep = (struct engr *) 0;
|
oep = (struct engr *) 0;
|
||||||
} else
|
} else {
|
||||||
/* Don't delete engr until after we *know* we're engraving
|
/* defer deletion until after we *know* we're engraving */
|
||||||
*/
|
|
||||||
eow = TRUE;
|
eow = TRUE;
|
||||||
|
}
|
||||||
} else if (type == DUST || type == MARK || type == ENGR_BLOOD) {
|
} else if (type == DUST || type == MARK || type == ENGR_BLOOD) {
|
||||||
You("cannot wipe out the message that is %s the %s here.",
|
You("cannot wipe out the message that is %s the %s here.",
|
||||||
oep->engr_type == BURN
|
oep->engr_type == BURN
|
||||||
@@ -1111,12 +1120,12 @@ static int
|
|||||||
engrave(void)
|
engrave(void)
|
||||||
{
|
{
|
||||||
struct engr *oep;
|
struct engr *oep;
|
||||||
char buf[BUFSZ]; /* holds the post-this-action engr text, including anything
|
char buf[BUFSZ]; /* holds the post-this-action engr text, including
|
||||||
* already there */
|
* anything already there */
|
||||||
const char *finishverb; /* "You finish [foo]." */
|
const char *finishverb; /* "You finish [foo]." */
|
||||||
struct obj * stylus; /* shorthand for g.context.engraving.stylus */
|
struct obj * stylus; /* shorthand for g.context.engraving.stylus */
|
||||||
boolean firsttime = (g.context.engraving.actionct == 0);
|
boolean firsttime = (g.context.engraving.actionct == 0);
|
||||||
int rate = 10; /* # characters we are capable of engraving in this action */
|
int rate = 10; /* # characters that can be engraved in this action */
|
||||||
boolean truncate = FALSE;
|
boolean truncate = FALSE;
|
||||||
|
|
||||||
boolean carving = (g.context.engraving.type == ENGRAVE
|
boolean carving = (g.context.engraving.type == ENGRAVE
|
||||||
@@ -1135,8 +1144,7 @@ engrave(void)
|
|||||||
* Not safe to dereference stylus until after this. */
|
* Not safe to dereference stylus until after this. */
|
||||||
if (g.context.engraving.stylus == &cg.zeroobj) { /* bare finger */
|
if (g.context.engraving.stylus == &cg.zeroobj) { /* bare finger */
|
||||||
stylus = (struct obj *) 0;
|
stylus = (struct obj *) 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (stylus = g.invent; stylus; stylus = stylus->nobj) {
|
for (stylus = g.invent; stylus; stylus = stylus->nobj) {
|
||||||
if (stylus == g.context.engraving.stylus) {
|
if (stylus == g.context.engraving.stylus) {
|
||||||
break;
|
break;
|
||||||
@@ -1158,8 +1166,7 @@ engrave(void)
|
|||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
if (dulling_wep && !is_blade(stylus)) {
|
if (dulling_wep && !is_blade(stylus)) {
|
||||||
impossible("carving with non-bladed weapon");
|
impossible("carving with non-bladed weapon");
|
||||||
}
|
} else if (g.context.engraving.type == MARK && !marker) {
|
||||||
else if (g.context.engraving.type == MARK && !marker) {
|
|
||||||
impossible("making graffiti with non-marker stylus");
|
impossible("making graffiti with non-marker stylus");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1169,8 +1176,7 @@ engrave(void)
|
|||||||
|| stylus->oclass == GEM_CLASS)) {
|
|| stylus->oclass == GEM_CLASS)) {
|
||||||
/* slow engraving methods */
|
/* slow engraving methods */
|
||||||
rate = 1;
|
rate = 1;
|
||||||
}
|
} else if (marker) {
|
||||||
else if (marker) {
|
|
||||||
/* one charge / 2 letters */
|
/* one charge / 2 letters */
|
||||||
rate = min(rate, stylus->spe * 2);
|
rate = min(rate, stylus->spe * 2);
|
||||||
}
|
}
|
||||||
@@ -1208,19 +1214,21 @@ engrave(void)
|
|||||||
impossible("<= -3 weapon valid for engraving");
|
impossible("<= -3 weapon valid for engraving");
|
||||||
}
|
}
|
||||||
truncate = TRUE;
|
truncate = TRUE;
|
||||||
}
|
} else if (*endc) {
|
||||||
else if (*endc) {
|
|
||||||
stylus->spe -= 1;
|
stylus->spe -= 1;
|
||||||
|
update_inventory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (marker) {
|
||||||
else if (marker) {
|
|
||||||
int ink_cost = max(rate / 2, 1); /* Prevent infinite graffiti */
|
int ink_cost = max(rate / 2, 1); /* Prevent infinite graffiti */
|
||||||
|
|
||||||
if (stylus->spe < ink_cost) {
|
if (stylus->spe < ink_cost) {
|
||||||
impossible("dry marker valid for graffiti");
|
impossible("overly dry marker valid for graffiti?");
|
||||||
|
ink_cost = stylus->spe;
|
||||||
truncate = TRUE;
|
truncate = TRUE;
|
||||||
}
|
}
|
||||||
stylus->spe -= ink_cost;
|
stylus->spe -= ink_cost;
|
||||||
|
update_inventory();
|
||||||
if (stylus->spe == 0) {
|
if (stylus->spe == 0) {
|
||||||
/* can't engrave any further; truncate the string */
|
/* can't engrave any further; truncate the string */
|
||||||
Your("marker dries out.");
|
Your("marker dries out.");
|
||||||
@@ -1241,7 +1249,7 @@ engrave(void)
|
|||||||
break;
|
break;
|
||||||
case BURN:
|
case BURN:
|
||||||
finishverb = is_ice(u.ux, u.uy) ? "melting your message into the ice"
|
finishverb = is_ice(u.ux, u.uy) ? "melting your message into the ice"
|
||||||
: "burning your message into the floor";
|
: "burning your message into the floor";
|
||||||
break;
|
break;
|
||||||
case MARK:
|
case MARK:
|
||||||
finishverb = "defacing the dungeon";
|
finishverb = "defacing the dungeon";
|
||||||
@@ -1252,12 +1260,12 @@ engrave(void)
|
|||||||
|
|
||||||
/* actions that happen at the end of every engraving action go here */
|
/* actions that happen at the end of every engraving action go here */
|
||||||
|
|
||||||
Strcpy(buf, "");
|
buf[0] = '\0';
|
||||||
oep = engr_at(u.ux, u.uy);
|
oep = engr_at(u.ux, u.uy);
|
||||||
if (oep) /* add to existing engraving */
|
if (oep) /* add to existing engraving */
|
||||||
Strcpy(buf, oep->engr_txt);
|
Strcpy(buf, oep->engr_txt);
|
||||||
|
|
||||||
space_left = sizeof buf - (int) strlen(buf) - 1;
|
space_left = (int) (sizeof buf - strlen(buf) - 1U);
|
||||||
if (endc - g.context.engraving.nextc > space_left) {
|
if (endc - g.context.engraving.nextc > space_left) {
|
||||||
You("run out of room to write.");
|
You("run out of room to write.");
|
||||||
endc = g.context.engraving.nextc + space_left;
|
endc = g.context.engraving.nextc + space_left;
|
||||||
@@ -1269,8 +1277,7 @@ engrave(void)
|
|||||||
if (truncate && *endc != '\0') {
|
if (truncate && *endc != '\0') {
|
||||||
*endc = '\0';
|
*endc = '\0';
|
||||||
You("are only able to write \"%s\".", g.context.engraving.text);
|
You("are only able to write \"%s\".", g.context.engraving.text);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* input was not truncated; stylus may still have worn out on the last
|
/* input was not truncated; stylus may still have worn out on the last
|
||||||
* character, though */
|
* character, though */
|
||||||
truncate = FALSE;
|
truncate = FALSE;
|
||||||
@@ -1283,16 +1290,14 @@ engrave(void)
|
|||||||
if (*endc) {
|
if (*endc) {
|
||||||
g.context.engraving.nextc = endc;
|
g.context.engraving.nextc = endc;
|
||||||
return 1; /* not yet finished this turn */
|
return 1; /* not yet finished this turn */
|
||||||
}
|
} else { /* finished engraving */
|
||||||
else { /* finished engraving */
|
|
||||||
/* actions that happen after the engraving is finished go here */
|
/* actions that happen after the engraving is finished go here */
|
||||||
|
|
||||||
if (truncate) {
|
if (truncate) {
|
||||||
/* Now that "You are only able to write 'foo'" also prints at the
|
/* Now that "You are only able to write 'foo'" also prints at the
|
||||||
* end of engraving, this might be redundant. */
|
* end of engraving, this might be redundant. */
|
||||||
You("cannot write any more.");
|
You("cannot write any more.");
|
||||||
}
|
} else if (!firsttime) {
|
||||||
else if (!firsttime) {
|
|
||||||
/* only print this if engraving took multiple actions */
|
/* only print this if engraving took multiple actions */
|
||||||
You("finish %s.", finishverb);
|
You("finish %s.", finishverb);
|
||||||
}
|
}
|
||||||
@@ -1325,8 +1330,10 @@ save_engravings(NHFILE *nhfp)
|
|||||||
ep2 = ep->nxt_engr;
|
ep2 = ep->nxt_engr;
|
||||||
if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(nhfp)) {
|
if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(nhfp)) {
|
||||||
if (nhfp->structlevel) {
|
if (nhfp->structlevel) {
|
||||||
bwrite(nhfp->fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
|
bwrite(nhfp->fd, (genericptr_t)&(ep->engr_lth),
|
||||||
bwrite(nhfp->fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
|
sizeof ep->engr_lth);
|
||||||
|
bwrite(nhfp->fd, (genericptr_t)ep,
|
||||||
|
sizeof (struct engr) + ep->engr_lth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (release_data(nhfp))
|
if (release_data(nhfp))
|
||||||
@@ -1386,12 +1393,12 @@ engr_stats(const char *hdrfmt, char *hdrbuf, long *count, long *size)
|
|||||||
RESTORE_WARNING_FORMAT_NONLITERAL
|
RESTORE_WARNING_FORMAT_NONLITERAL
|
||||||
|
|
||||||
void
|
void
|
||||||
del_engr(register struct engr *ep)
|
del_engr(struct engr *ep)
|
||||||
{
|
{
|
||||||
if (ep == head_engr) {
|
if (ep == head_engr) {
|
||||||
head_engr = ep->nxt_engr;
|
head_engr = ep->nxt_engr;
|
||||||
} else {
|
} else {
|
||||||
register struct engr *ept;
|
struct engr *ept;
|
||||||
|
|
||||||
for (ept = head_engr; ept; ept = ept->nxt_engr)
|
for (ept = head_engr; ept; ept = ept->nxt_engr)
|
||||||
if (ept->nxt_engr == ep) {
|
if (ept->nxt_engr == ep) {
|
||||||
|
|||||||
Reference in New Issue
Block a user