Merge branch 'copperwater-pr460' into NetHack-3.7
This commit is contained in:
@@ -858,6 +858,7 @@ add cross-compile to WASM (github #385, #403, #412)
|
||||
differentiating gendered monster tiles from NullCGT (#430)
|
||||
check bones data directly for deja vu messages (#374)
|
||||
unify code for extracting an object from a monster's inventory (#455)
|
||||
make engraving an occupation (#460)
|
||||
|
||||
|
||||
Code Cleanup and Reorganization
|
||||
|
||||
@@ -65,6 +65,16 @@ struct victual_info {
|
||||
Bitfield(doreset, 1); /* stop eating at end of turn */
|
||||
};
|
||||
|
||||
struct engrave_info {
|
||||
char text[BUFSZ]; /* actual text being engraved - doengrave() handles all
|
||||
the possible mutations of this */
|
||||
char *nextc; /* next character(s) in text[] to engrave */
|
||||
struct obj *stylus; /* object doing the writing */
|
||||
xchar type; /* type of engraving (DUST, MARK, etc) */
|
||||
coord pos; /* location the engraving is being placed on */
|
||||
int actionct; /* nth turn spent engraving */
|
||||
};
|
||||
|
||||
struct warntype_info {
|
||||
unsigned long obj; /* object warn_of_mon monster type M2 */
|
||||
unsigned long polyd; /* warn_of_mon monster type M2 due to poly */
|
||||
@@ -142,6 +152,7 @@ struct context_info {
|
||||
boolean enhance_tip; /* player is informed about #enhance */
|
||||
struct dig_info digging;
|
||||
struct victual_info victual;
|
||||
struct engrave_info engraving;
|
||||
struct tin_info tin;
|
||||
struct book_info spbook;
|
||||
struct takeoff_info takeoff;
|
||||
|
||||
293
src/engrave.c
293
src/engrave.c
@@ -6,6 +6,7 @@
|
||||
#include "hack.h"
|
||||
|
||||
static int stylus_ok(struct obj *);
|
||||
static int engrave(void);
|
||||
static const char *blengr(void);
|
||||
|
||||
char *
|
||||
@@ -493,7 +494,6 @@ doengrave(void)
|
||||
const char *eloc; /* Where the engraving is (ie dust/floor/...) */
|
||||
char *sp; /* Place holder for space count of engr text */
|
||||
int len; /* # of nonspace chars of new engraving text */
|
||||
int maxelen; /* Max allowable length of engraving text */
|
||||
struct engr *oep = engr_at(u.ux, u.uy);
|
||||
/* The current engraving */
|
||||
struct obj *otmp; /* Object selected with which to engrave */
|
||||
@@ -505,7 +505,6 @@ doengrave(void)
|
||||
buf[0] = (char) 0;
|
||||
ebuf[0] = (char) 0;
|
||||
post_engr_text[0] = (char) 0;
|
||||
maxelen = BUFSZ - 1;
|
||||
if (oep)
|
||||
oetype = oep->engr_type;
|
||||
if (is_demon(g.youmonst.data) || is_vampire(g.youmonst.data))
|
||||
@@ -1069,95 +1068,14 @@ doengrave(void)
|
||||
oep = (struct engr *) 0;
|
||||
}
|
||||
|
||||
/* Figure out how long it took to engrave, and if player has
|
||||
* engraved too much.
|
||||
*/
|
||||
switch (type) {
|
||||
default:
|
||||
g.multi = -(len / 10);
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You finish your weird engraving.";
|
||||
break;
|
||||
case DUST:
|
||||
g.multi = -(len / 10);
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You finish writing in the dust.";
|
||||
break;
|
||||
case HEADSTONE:
|
||||
case ENGRAVE:
|
||||
g.multi = -(len / 10);
|
||||
if (otmp->oclass == WEAPON_CLASS
|
||||
&& (otmp->otyp != ATHAME || otmp->cursed)) {
|
||||
g.multi = -len;
|
||||
maxelen = ((otmp->spe + 3) * 2) + 1;
|
||||
/* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
|
||||
* Note: this does not allow a +0 anything (except an athame)
|
||||
* to engrave "Elbereth" all at once.
|
||||
* However, you can engrave "Elb", then "ere", then "th".
|
||||
*/
|
||||
pline("%s dull.", Yobjnam2(otmp, "get"));
|
||||
costly_alteration(otmp, COST_DEGRD);
|
||||
if (len > maxelen) {
|
||||
g.multi = -maxelen;
|
||||
otmp->spe = -3;
|
||||
} else if (len > 1)
|
||||
otmp->spe -= len >> 1;
|
||||
else
|
||||
otmp->spe -= 1; /* Prevent infinite engraving */
|
||||
} else if (otmp->oclass == RING_CLASS || otmp->oclass == GEM_CLASS) {
|
||||
g.multi = -len;
|
||||
}
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You finish engraving.";
|
||||
break;
|
||||
case BURN:
|
||||
g.multi = -(len / 10);
|
||||
if (g.multi)
|
||||
g.nomovemsg = is_ice(u.ux, u.uy)
|
||||
? "You finish melting your message into the ice."
|
||||
: "You finish burning your message into the floor.";
|
||||
break;
|
||||
case MARK:
|
||||
g.multi = -(len / 10);
|
||||
if (otmp->otyp == MAGIC_MARKER) {
|
||||
maxelen = otmp->spe * 2; /* one charge / 2 letters */
|
||||
if (len > maxelen) {
|
||||
Your("marker dries out.");
|
||||
otmp->spe = 0;
|
||||
g.multi = -(maxelen / 10);
|
||||
} else if (len > 1)
|
||||
otmp->spe -= len >> 1;
|
||||
else
|
||||
otmp->spe -= 1; /* Prevent infinite graffiti */
|
||||
}
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You finish defacing the dungeon.";
|
||||
break;
|
||||
case ENGR_BLOOD:
|
||||
g.multi = -(len / 10);
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You finish scrawling.";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Chop engraving down to size if necessary */
|
||||
if (len > maxelen) {
|
||||
for (sp = ebuf; maxelen && *sp; sp++)
|
||||
if (!(*sp == ' '))
|
||||
maxelen--;
|
||||
if (!maxelen && *sp) {
|
||||
*sp = '\0';
|
||||
if (g.multi)
|
||||
g.nomovemsg = "You cannot write any more.";
|
||||
You("are only able to write \"%s\".", ebuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (oep) /* add to existing engraving */
|
||||
Strcpy(buf, oep->engr_txt);
|
||||
(void) strncat(buf, ebuf, BUFSZ - (int) strlen(buf) - 1);
|
||||
/* Put the engraving onto the map */
|
||||
make_engr_at(u.ux, u.uy, buf, g.moves - g.multi, type);
|
||||
Strcpy(g.context.engraving.text, ebuf);
|
||||
g.context.engraving.nextc = g.context.engraving.text;
|
||||
g.context.engraving.stylus = otmp;
|
||||
g.context.engraving.type = type;
|
||||
g.context.engraving.pos.x = u.ux;
|
||||
g.context.engraving.pos.y = u.uy;
|
||||
g.context.engraving.actionct = 0;
|
||||
set_occupation(engrave, "engraving", 0);
|
||||
|
||||
if (post_engr_text[0])
|
||||
pline("%s", post_engr_text);
|
||||
@@ -1167,7 +1085,198 @@ doengrave(void)
|
||||
if (!Blind)
|
||||
Your1(vision_clears);
|
||||
}
|
||||
return 1;
|
||||
|
||||
/* Engraving will always take at least one action via being run as an
|
||||
* occupation, so do not count this setup as taking time. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* occupation callback for engraving some text */
|
||||
static int
|
||||
engrave(void)
|
||||
{
|
||||
struct engr *oep;
|
||||
char buf[BUFSZ]; /* holds the post-this-action engr text, including anything
|
||||
* already there */
|
||||
const char *finishverb; /* "You finish [foo]." */
|
||||
struct obj * stylus; /* shorthand for g.context.engraving.stylus */
|
||||
boolean firsttime = (g.context.engraving.actionct == 0);
|
||||
int rate = 10; /* # characters we are capable of engraving in this action */
|
||||
boolean truncate = FALSE;
|
||||
|
||||
boolean carving = (g.context.engraving.type == ENGRAVE
|
||||
|| g.context.engraving.type == HEADSTONE);
|
||||
boolean dulling_wep, marker;
|
||||
char *endc; /* points at character 1 beyond the last character to engrave
|
||||
this action */
|
||||
int i;
|
||||
|
||||
if (g.context.engraving.pos.x != u.ux
|
||||
|| g.context.engraving.pos.y != u.uy) { /* teleported? */
|
||||
pline("You are unable to continue engraving.");
|
||||
return 0;
|
||||
}
|
||||
/* Stylus might have been taken out of inventory and destroyed somehow.
|
||||
* Not safe to dereference stylus until after this. */
|
||||
if (g.context.engraving.stylus == &cg.zeroobj) { /* bare finger */
|
||||
stylus = (struct obj *) 0;
|
||||
}
|
||||
else {
|
||||
for (stylus = g.invent; stylus; stylus = stylus->nobj) {
|
||||
if (stylus == g.context.engraving.stylus) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!stylus) {
|
||||
pline("You are unable to continue engraving.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dulling_wep = (stylus && stylus->oclass == WEAPON_CLASS
|
||||
&& (stylus->otyp != ATHAME || stylus->cursed));
|
||||
marker = (stylus && stylus->otyp == MAGIC_MARKER);
|
||||
|
||||
g.context.engraving.actionct++;
|
||||
|
||||
/* sanity checks */
|
||||
if (dulling_wep && !carving) {
|
||||
impossible("using weapon for non-carve engraving");
|
||||
}
|
||||
else if (g.context.engraving.type == MARK && !marker) {
|
||||
impossible("making graffiti with non-marker stylus");
|
||||
}
|
||||
|
||||
/* Step 1: Compute rate. */
|
||||
if (carving && stylus
|
||||
&& (dulling_wep || stylus->oclass == RING_CLASS
|
||||
|| stylus->oclass == GEM_CLASS)) {
|
||||
/* slow engraving methods */
|
||||
rate = 1;
|
||||
}
|
||||
else if (marker) {
|
||||
/* one charge / 2 letters */
|
||||
rate = min(rate, stylus->spe * 2);
|
||||
}
|
||||
|
||||
/* Step 2: Compute last character that can be engraved this action. */
|
||||
i = rate;
|
||||
for (endc = g.context.engraving.nextc; *endc && i > 0; endc++) {
|
||||
if (*endc != ' ') {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 3: affect stylus from engraving - it might wear out. */
|
||||
if (dulling_wep) {
|
||||
/* Dull the weapon at a rate of -1 enchantment per 2 characters,
|
||||
* rounding down.
|
||||
* The number of characters obtainable given starting enchantment:
|
||||
* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
|
||||
* Note: this does not allow a +0 anything (except an athame) to
|
||||
* engrave "Elbereth" all at once.
|
||||
* However, you can engrave "Elb", then "ere", then "th", by taking
|
||||
* advantage of the rounding down. */
|
||||
if (firsttime) {
|
||||
pline("%s dull.", Yobjnam2(stylus, "get"));
|
||||
}
|
||||
if (g.context.engraving.actionct % 2 == 1) { /* 1st, 3rd, ... action */
|
||||
/* deduct a point on 1st, 3rd, 5th, ... turns, unless this is the
|
||||
* last character being engraved (a rather convoluted way to round
|
||||
* down).
|
||||
* Check for truncation *before* deducting a point - otherwise,
|
||||
* attempting to e.g. engrave 3 characters with a -2 weapon will
|
||||
* stop at the 1st. */
|
||||
if (stylus->spe <= -3) {
|
||||
if (firsttime) {
|
||||
impossible("<= -3 weapon valid for engraving");
|
||||
}
|
||||
truncate = TRUE;
|
||||
}
|
||||
else if (*endc) {
|
||||
stylus->spe -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (marker) {
|
||||
int ink_cost = max(rate / 2, 1); /* Prevent infinite graffiti */
|
||||
if (stylus->spe < ink_cost) {
|
||||
impossible("dry marker valid for graffiti");
|
||||
truncate = TRUE;
|
||||
}
|
||||
stylus->spe -= ink_cost;
|
||||
if (stylus->spe == 0) {
|
||||
/* can't engrave any further; truncate the string */
|
||||
Your("marker dries out.");
|
||||
truncate = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (g.context.engraving.type) {
|
||||
default:
|
||||
finishverb = "your weird engraving";
|
||||
break;
|
||||
case DUST:
|
||||
finishverb = "writing in the dust";
|
||||
break;
|
||||
case HEADSTONE:
|
||||
case ENGRAVE:
|
||||
finishverb = "engraving";
|
||||
break;
|
||||
case BURN:
|
||||
finishverb = is_ice(u.ux, u.uy) ? "melting your message into the ice"
|
||||
: "burning your message into the floor";
|
||||
break;
|
||||
case MARK:
|
||||
finishverb = "defacing the dungeon";
|
||||
break;
|
||||
case ENGR_BLOOD:
|
||||
finishverb = "scrawling";
|
||||
}
|
||||
|
||||
/* actions that happen at the end of every engraving action go here */
|
||||
|
||||
/* If the stylus did wear out mid-engraving, truncate the input so that we
|
||||
* can't go any further. */
|
||||
if (truncate && *endc != '\0') {
|
||||
*endc = '\0';
|
||||
You("are only able to write \"%s\".", g.context.engraving.text);
|
||||
}
|
||||
else {
|
||||
/* input was not truncated; stylus may still have worn out on the last
|
||||
* character, though */
|
||||
truncate = FALSE;
|
||||
}
|
||||
|
||||
Strcpy(buf, "");
|
||||
oep = engr_at(u.ux, u.uy);
|
||||
if (oep) /* add to existing engraving */
|
||||
Strcpy(buf, oep->engr_txt);
|
||||
(void) strncat(buf, g.context.engraving.nextc,
|
||||
endc - g.context.engraving.nextc);
|
||||
make_engr_at(u.ux, u.uy, buf, g.moves - g.multi, g.context.engraving.type);
|
||||
|
||||
if (*endc) {
|
||||
g.context.engraving.nextc = endc;
|
||||
return 1; /* not yet finished this turn */
|
||||
}
|
||||
else { /* finished engraving */
|
||||
/* actions that happen after the engraving is finished go here */
|
||||
|
||||
if (truncate) {
|
||||
/* Now that "You are only able to write 'foo'" also prints at the
|
||||
* end of engraving, this might be redundant. */
|
||||
You("cannot write any more.");
|
||||
}
|
||||
else if (!firsttime) {
|
||||
/* only print this if engraving took multiple actions */
|
||||
You("finish %s.", finishverb);
|
||||
}
|
||||
g.context.engraving.text[0] = '\0';
|
||||
g.context.engraving.nextc = (char *) 0;
|
||||
g.context.engraving.stylus = (struct obj *) 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* while loading bones, clean up text which might accidentally
|
||||
|
||||
Reference in New Issue
Block a user