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)
|
differentiating gendered monster tiles from NullCGT (#430)
|
||||||
check bones data directly for deja vu messages (#374)
|
check bones data directly for deja vu messages (#374)
|
||||||
unify code for extracting an object from a monster's inventory (#455)
|
unify code for extracting an object from a monster's inventory (#455)
|
||||||
|
make engraving an occupation (#460)
|
||||||
|
|
||||||
|
|
||||||
Code Cleanup and Reorganization
|
Code Cleanup and Reorganization
|
||||||
|
|||||||
@@ -65,6 +65,16 @@ struct victual_info {
|
|||||||
Bitfield(doreset, 1); /* stop eating at end of turn */
|
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 {
|
struct warntype_info {
|
||||||
unsigned long obj; /* object warn_of_mon monster type M2 */
|
unsigned long obj; /* object warn_of_mon monster type M2 */
|
||||||
unsigned long polyd; /* warn_of_mon monster type M2 due to poly */
|
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 */
|
boolean enhance_tip; /* player is informed about #enhance */
|
||||||
struct dig_info digging;
|
struct dig_info digging;
|
||||||
struct victual_info victual;
|
struct victual_info victual;
|
||||||
|
struct engrave_info engraving;
|
||||||
struct tin_info tin;
|
struct tin_info tin;
|
||||||
struct book_info spbook;
|
struct book_info spbook;
|
||||||
struct takeoff_info takeoff;
|
struct takeoff_info takeoff;
|
||||||
|
|||||||
293
src/engrave.c
293
src/engrave.c
@@ -6,6 +6,7 @@
|
|||||||
#include "hack.h"
|
#include "hack.h"
|
||||||
|
|
||||||
static int stylus_ok(struct obj *);
|
static int stylus_ok(struct obj *);
|
||||||
|
static int engrave(void);
|
||||||
static const char *blengr(void);
|
static const char *blengr(void);
|
||||||
|
|
||||||
char *
|
char *
|
||||||
@@ -493,7 +494,6 @@ doengrave(void)
|
|||||||
const char *eloc; /* Where the engraving is (ie dust/floor/...) */
|
const char *eloc; /* Where the engraving is (ie dust/floor/...) */
|
||||||
char *sp; /* Place holder for space count of engr text */
|
char *sp; /* Place holder for space count of engr text */
|
||||||
int len; /* # of nonspace chars of new engraving 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);
|
struct engr *oep = engr_at(u.ux, u.uy);
|
||||||
/* The current engraving */
|
/* The current engraving */
|
||||||
struct obj *otmp; /* Object selected with which to engrave */
|
struct obj *otmp; /* Object selected with which to engrave */
|
||||||
@@ -505,7 +505,6 @@ doengrave(void)
|
|||||||
buf[0] = (char) 0;
|
buf[0] = (char) 0;
|
||||||
ebuf[0] = (char) 0;
|
ebuf[0] = (char) 0;
|
||||||
post_engr_text[0] = (char) 0;
|
post_engr_text[0] = (char) 0;
|
||||||
maxelen = BUFSZ - 1;
|
|
||||||
if (oep)
|
if (oep)
|
||||||
oetype = oep->engr_type;
|
oetype = oep->engr_type;
|
||||||
if (is_demon(g.youmonst.data) || is_vampire(g.youmonst.data))
|
if (is_demon(g.youmonst.data) || is_vampire(g.youmonst.data))
|
||||||
@@ -1069,95 +1068,14 @@ doengrave(void)
|
|||||||
oep = (struct engr *) 0;
|
oep = (struct engr *) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out how long it took to engrave, and if player has
|
Strcpy(g.context.engraving.text, ebuf);
|
||||||
* engraved too much.
|
g.context.engraving.nextc = g.context.engraving.text;
|
||||||
*/
|
g.context.engraving.stylus = otmp;
|
||||||
switch (type) {
|
g.context.engraving.type = type;
|
||||||
default:
|
g.context.engraving.pos.x = u.ux;
|
||||||
g.multi = -(len / 10);
|
g.context.engraving.pos.y = u.uy;
|
||||||
if (g.multi)
|
g.context.engraving.actionct = 0;
|
||||||
g.nomovemsg = "You finish your weird engraving.";
|
set_occupation(engrave, "engraving", 0);
|
||||||
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);
|
|
||||||
|
|
||||||
if (post_engr_text[0])
|
if (post_engr_text[0])
|
||||||
pline("%s", post_engr_text);
|
pline("%s", post_engr_text);
|
||||||
@@ -1167,7 +1085,198 @@ doengrave(void)
|
|||||||
if (!Blind)
|
if (!Blind)
|
||||||
Your1(vision_clears);
|
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
|
/* while loading bones, clean up text which might accidentally
|
||||||
|
|||||||
Reference in New Issue
Block a user