1 /* NetHack 3.6 engrave.c $NHDT-Date: 1456304550 2016/02/24 09:02:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.61 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
8 STATIC_VAR NEARDATA
struct engr
*head_engr
;
11 random_engraving(outbuf
)
16 /* a random engraving may come from the "rumors" file,
17 or from the "engrave" file (formerly in an array here) */
18 if (!rn2(4) || !(rumor
= getrumor(0, outbuf
, TRUE
)) || !*rumor
)
19 (void) get_rnd_text(ENGRAVEFILE
, outbuf
);
21 wipeout_text(outbuf
, (int) (strlen(outbuf
) / 4), 0);
25 /* Partial rubouts for engraving characters. -3. */
29 } rubouts
[] = { { 'A', "^" },
78 /* degrade some of the characters in a string */
80 wipeout_text(engr
, cnt
, seed
)
83 unsigned seed
; /* for semi-controlled randomization */
86 int i
, j
, nxt
, use_rubout
, lth
= (int) strlen(engr
);
90 /* pick next character */
96 /* predictable; caller can reproduce the same sequence by
97 supplying the same arguments later, or a pseudo-random
98 sequence by varying any of them */
100 seed
*= 31, seed
%= (BUFSZ
- 1);
101 use_rubout
= seed
& 3;
107 /* rub out unreadable & small punctuation marks */
108 if (index("?.,'`-|_", *s
)) {
116 for (i
= 0; i
< SIZE(rubouts
); i
++)
117 if (*s
== rubouts
[i
].wipefrom
) {
119 * Pick one of the substitutes at random.
122 j
= rn2(strlen(rubouts
[i
].wipeto
));
124 seed
*= 31, seed
%= (BUFSZ
- 1);
125 j
= seed
% (strlen(rubouts
[i
].wipeto
));
127 *s
= rubouts
[i
].wipeto
[j
];
131 /* didn't pick rubout; use '?' for unreadable character */
132 if (i
== SIZE(rubouts
))
137 /* trim trailing spaces */
138 while (lth
&& engr
[lth
- 1] == ' ')
142 /* check whether hero can reach something at ground level */
144 can_reach_floor(check_pit
)
151 /* Restricted/unskilled riders can't reach the floor */
152 if (u
.usteed
&& P_SKILL(P_RIDING
) < P_BASIC
)
154 if (check_pit
&& !Flying
155 && (t
= t_at(u
.ux
, u
.uy
)) != 0 && uteetering_at_seen_pit(t
))
158 return (boolean
) ((!Levitation
|| Is_airlevel(&u
.uz
)
159 || Is_waterlevel(&u
.uz
))
160 && (!u
.uundetected
|| !is_hider(youmonst
.data
)
161 || u
.umonnum
== PM_TRAPPER
));
164 /* give a message after caller has determined that hero can't reach */
166 cant_reach_floor(x
, y
, up
, check_pit
)
168 boolean up
, check_pit
;
170 You("can't reach the %s.",
172 : (check_pit
&& can_reach_floor(FALSE
))
173 ? "bottom of the pit"
181 register struct rm
*lev
= &levl
[x
][y
];
183 if (x
== u
.ux
&& y
== u
.uy
&& u
.uswallow
&& is_animal(u
.ustuck
->data
))
185 else if (IS_AIR(lev
->typ
) && Is_airlevel(&u
.uz
))
187 else if (is_pool(x
, y
))
188 return (Underwater
&& !Is_waterlevel(&u
.uz
))
189 ? "bottom" : hliquid("water");
190 else if (is_ice(x
, y
))
192 else if (is_lava(x
, y
))
193 return hliquid("lava");
194 else if (lev
->typ
== DRAWBRIDGE_DOWN
)
196 else if (IS_ALTAR(levl
[x
][y
].typ
))
198 else if (IS_GRAVE(levl
[x
][y
].typ
))
200 else if (IS_FOUNTAIN(levl
[x
][y
].typ
))
202 else if ((IS_ROOM(lev
->typ
) && !Is_earthlevel(&u
.uz
))
203 || IS_WALL(lev
->typ
) || IS_DOOR(lev
->typ
) || lev
->typ
== SDOOR
)
213 register struct rm
*lev
= &levl
[x
][y
];
216 /* other room types will no longer exist when we're interested --
217 * see check_special_room()
219 if (*in_rooms(x
, y
, VAULT
))
220 what
= "vault's ceiling";
221 else if (*in_rooms(x
, y
, TEMPLE
))
222 what
= "temple's ceiling";
223 else if (*in_rooms(x
, y
, SHOPBASE
))
224 what
= "shop's ceiling";
225 else if (Is_waterlevel(&u
.uz
))
226 /* water plane has no surface; its air bubbles aren't below sky */
227 what
= "water above";
228 else if (IS_AIR(lev
->typ
))
231 what
= "water's surface";
232 else if ((IS_ROOM(lev
->typ
) && !Is_earthlevel(&u
.uz
))
233 || IS_WALL(lev
->typ
) || IS_DOOR(lev
->typ
) || lev
->typ
== SDOOR
)
236 what
= "rock cavern";
245 register struct engr
*ep
= head_engr
;
248 if (x
== ep
->engr_x
&& y
== ep
->engr_y
)
252 return (struct engr
*) 0;
255 /* Decide whether a particular string is engraved at a specified
256 * location; a case-insensitive substring match is used.
257 * Ignore headstones, in case the player names herself "Elbereth".
259 * If strict checking is requested, the word is only considered to be
260 * present if it is intact and is the first word in the engraving.
261 * ("Elbereth burrito" matches; "o Elbereth" does not.)
264 sengr_at(s
, x
, y
, strict
)
269 register struct engr
*ep
= engr_at(x
, y
);
271 if (ep
&& ep
->engr_type
!= HEADSTONE
&& ep
->engr_time
<= moves
) {
272 return strict
? (strncmpi(ep
->engr_txt
, s
, strlen(s
)) == 0)
273 : (strstri(ep
->engr_txt
, s
) != 0);
282 if (can_reach_floor(TRUE
))
283 wipe_engr_at(u
.ux
, u
.uy
, cnt
, FALSE
);
287 wipe_engr_at(x
, y
, cnt
, magical
)
288 xchar x
, y
, cnt
, magical
;
290 register struct engr
*ep
= engr_at(x
, y
);
292 /* Headstones are indelible */
293 if (ep
&& ep
->engr_type
!= HEADSTONE
) {
294 debugpline1("asked to erode %d characters", cnt
);
295 if (ep
->engr_type
!= BURN
|| is_ice(x
, y
) || (magical
&& !rn2(2))) {
296 if (ep
->engr_type
!= DUST
&& ep
->engr_type
!= ENGR_BLOOD
) {
297 cnt
= rn2(1 + 50 / (cnt
+ 1)) ? 0 : 1;
298 debugpline1("actually eroding %d characters", cnt
);
300 wipeout_text(ep
->engr_txt
, (int) cnt
, 0);
301 while (ep
->engr_txt
[0] == ' ')
303 if (!ep
->engr_txt
[0])
313 register struct engr
*ep
= engr_at(x
, y
);
317 /* Sensing an engraving does not require sight,
318 * nor does it necessarily imply comprehension (literacy).
320 if (ep
&& ep
->engr_txt
[0]) {
321 switch (ep
->engr_type
) {
325 pline("%s is written here in the %s.", Something
,
326 is_ice(x
, y
) ? "frost" : "dust");
331 if (!Blind
|| can_reach_floor(TRUE
)) {
333 pline("%s is engraved here on the %s.", Something
,
338 if (!Blind
|| can_reach_floor(TRUE
)) {
340 pline("Some text has been %s into the %s here.",
341 is_ice(x
, y
) ? "melted" : "burned", surface(x
, y
));
347 pline("There's some graffiti on the %s here.", surface(x
, y
));
351 /* "It's a message! Scrawled in blood!"
353 * "It says... `See you next Wednesday.'" -- Thriller
357 You_see("a message scrawled in blood here.");
361 impossible("%s is written in a very strange way.", Something
);
366 unsigned maxelen
= BUFSZ
- sizeof("You feel the words: \"\". ");
367 if (strlen(ep
->engr_txt
) > maxelen
) {
368 (void) strncpy(buf
, ep
->engr_txt
, (int) maxelen
);
373 You("%s: \"%s\".", (Blind
) ? "feel the words" : "read", et
);
381 make_engr_at(x
, y
, s
, e_time
, e_type
)
389 if ((ep
= engr_at(x
, y
)) != 0)
391 ep
= newengr(strlen(s
) + 1);
392 (void) memset((genericptr_t
)ep
, 0, sizeof(struct engr
));
393 ep
->nxt_engr
= head_engr
;
397 ep
->engr_txt
= (char *) (ep
+ 1);
398 Strcpy(ep
->engr_txt
, s
);
399 /* engraving Elbereth shows wisdom */
400 if (!in_mklev
&& !strcmp(s
, "Elbereth"))
401 exercise(A_WIS
, TRUE
);
402 ep
->engr_time
= e_time
;
403 ep
->engr_type
= e_type
> 0 ? e_type
: rnd(N_ENGRAVE
- 1);
404 ep
->engr_lth
= strlen(s
) + 1;
407 /* delete any engraving at location <x,y> */
412 register struct engr
*ep
= engr_at(x
, y
);
419 * freehand - returns true if player has a free hand
424 return (!uwep
|| !welded(uwep
)
425 || (!bimanual(uwep
) && (!uarms
|| !uarms
->cursed
)));
428 static NEARDATA
const char styluses
[] = { ALL_CLASSES
, ALLOW_NONE
,
429 TOOL_CLASS
, WEAPON_CLASS
,
430 WAND_CLASS
, GEM_CLASS
,
433 /* Mohs' Hardness Scale:
434 * 1 - Talc 6 - Orthoclase
435 * 2 - Gypsum 7 - Quartz
436 * 3 - Calcite 8 - Topaz
437 * 4 - Fluorite 9 - Corundum
438 * 5 - Apatite 10 - Diamond
440 * Since granite is an igneous rock hardness ~ 7, anything >= 8 should
441 * probably be able to scratch the rock.
442 * Devaluation of less hard gems is not easily possible because obj struct
443 * does not contain individual oc_cost currently. 7/91
445 * steel - 5-8.5 (usu. weapon)
446 * diamond - 10 * jade - 5-6 (nephrite)
447 * ruby - 9 (corundum) * turquoise - 5-6
448 * sapphire - 9 (corundum) * opal - 5-6
449 * topaz - 8 * glass - ~5.5
450 * emerald - 7.5-8 (beryl) * dilithium - 4-5??
451 * aquamarine - 7.5-8 (beryl) * iron - 4-5
452 * garnet - 7.25 (var. 6.5-8) * fluorite - 4
453 * agate - 7 (quartz) * brass - 3-4
454 * amethyst - 7 (quartz) * gold - 2.5-3
455 * jasper - 7 (quartz) * silver - 2.5-3
456 * onyx - 7 (quartz) * copper - 2.5-3
457 * moonstone - 6 (orthoclase) * amber - 2-2.5
460 /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
464 boolean dengr
= FALSE
; /* TRUE if we wipe out the current engraving */
465 boolean doblind
= FALSE
; /* TRUE if engraving blinds the player */
466 boolean doknown
= FALSE
; /* TRUE if we identify the stylus */
467 boolean eow
= FALSE
; /* TRUE if we are overwriting oep */
468 boolean jello
= FALSE
; /* TRUE if we are engraving in slime */
469 boolean ptext
= TRUE
; /* TRUE if we must prompt for engrave text */
470 boolean teleengr
= FALSE
; /* TRUE if we move the old engraving */
471 boolean zapwand
= FALSE
; /* TRUE if we remove a wand charge */
472 xchar type
= DUST
; /* Type of engraving made */
473 char buf
[BUFSZ
]; /* Buffer for final/poly engraving text */
474 char ebuf
[BUFSZ
]; /* Buffer for initial engraving text */
475 char fbuf
[BUFSZ
]; /* Buffer for "your fingers" */
476 char qbuf
[QBUFSZ
]; /* Buffer for query text */
477 char post_engr_text
[BUFSZ
]; /* Text displayed after engraving prompt */
478 const char *everb
; /* Present tense of engraving type */
479 const char *eloc
; /* Where the engraving is (ie dust/floor/...) */
480 char *sp
; /* Place holder for space count of engr text */
481 int len
; /* # of nonspace chars of new engraving text */
482 int maxelen
; /* Max allowable length of engraving text */
483 struct engr
*oep
= engr_at(u
.ux
, u
.uy
);
484 /* The current engraving */
485 struct obj
*otmp
; /* Object selected with which to engrave */
488 multi
= 0; /* moves consumed */
489 nomovemsg
= (char *) 0; /* occupation end message */
493 post_engr_text
[0] = (char) 0;
495 if (is_demon(youmonst
.data
) || youmonst
.data
->mlet
== S_VAMPIRE
)
498 /* Can the adventurer engrave at all? */
501 if (is_animal(u
.ustuck
->data
)) {
502 pline("What would you write? \"Jonah was here\"?");
504 } else if (is_whirly(u
.ustuck
->data
)) {
505 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, FALSE
);
509 } else if (is_lava(u
.ux
, u
.uy
)) {
510 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
512 } else if (is_pool(u
.ux
, u
.uy
) || IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
513 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
516 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) /* in bubble */) {
517 You_cant("write in thin air!");
519 } else if (!accessible(u
.ux
, u
.uy
)) {
520 /* stone, tree, wall, secret corridor, pool, lava, bars */
521 You_cant("write here.");
524 if (cantwield(youmonst
.data
)) {
525 You_cant("even hold anything!");
528 if (check_capacity((char *) 0))
531 /* One may write with finger, or weapon, or wand, or..., or...
532 * Edited by GAN 10/20/86 so as not to change weapon wielded.
535 otmp
= getobj(styluses
, "write with");
536 if (!otmp
) /* otmp == zeroobj if fingers */
539 if (otmp
== &zeroobj
) {
540 Strcat(strcpy(fbuf
, "your "), body_part(FINGERTIP
));
543 writer
= yname(otmp
);
545 /* There's no reason you should be able to write with a wand
546 * while both your hands are tied up.
548 if (!freehand() && otmp
!= uwep
&& !otmp
->owornmask
) {
549 You("have no free %s to write with!", body_part(HAND
));
554 You("tickle %s with %s.", mon_nam(u
.ustuck
), writer
);
555 Your("message dissolves...");
558 if (otmp
->oclass
!= WAND_CLASS
&& !can_reach_floor(TRUE
)) {
559 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
562 if (IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
)) {
563 You("make a motion towards the altar with %s.", writer
);
564 altar_wrath(u
.ux
, u
.uy
);
567 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
568 if (otmp
== &zeroobj
) { /* using only finger */
569 You("would only make a small smudge on the %s.",
570 surface(u
.ux
, u
.uy
));
572 } else if (!levl
[u
.ux
][u
.uy
].disturbed
) {
573 You("disturb the undead!");
574 levl
[u
.ux
][u
.uy
].disturbed
= 1;
575 (void) makemon(&mons
[PM_GHOUL
], u
.ux
, u
.uy
, NO_MM_FLAGS
);
576 exercise(A_WIS
, FALSE
);
583 switch (otmp
->oclass
) {
591 /* "diamond" rings and others should work */
593 /* diamonds & other hard gems should work */
594 if (objects
[otmp
->otyp
].oc_tough
) {
600 if (is_boots(otmp
)) {
605 /* Objects too large to engrave with */
608 You_cant("engrave with such a large object!");
611 /* Objects too silly to engrave with */
615 pline("%s would get %s.", Yname2(otmp
),
616 is_ice(u
.ux
, u
.uy
) ? "all frosty" : "too dirty");
619 case RANDOM_CLASS
: /* This should mean fingers */
622 /* The charge is removed from the wand before prompting for
623 * the engraving text, because all kinds of setup decisions
624 * and pre-engraving messages are based upon knowing what type
625 * of engraving the wand is going to do. Also, the player
626 * will have potentially seen "You wrest .." message, and
627 * therefore will know they are using a charge.
630 if (zappable(otmp
)) {
632 if (otmp
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
633 wand_explode(otmp
, 0);
637 if (!can_reach_floor(TRUE
))
640 switch (otmp
->otyp
) {
646 case WAN_SECRET_DOOR_DETECTION
:
647 case WAN_CREATE_MONSTER
:
649 case WAN_ENLIGHTENMENT
:
652 /* IMMEDIATE wands */
653 /* If wand is "IMMEDIATE", remember to affect the
654 * previous engraving even if turning to dust.
657 Strcpy(post_engr_text
,
658 "The wand unsuccessfully fights your attempt to write!");
660 case WAN_SLOW_MONSTER
:
662 Sprintf(post_engr_text
, "The bugs on the %s slow down!",
663 surface(u
.ux
, u
.uy
));
666 case WAN_SPEED_MONSTER
:
668 Sprintf(post_engr_text
, "The bugs on the %s speed up!",
669 surface(u
.ux
, u
.uy
));
675 type
= (xchar
) 0; /* random */
676 (void) random_engraving(buf
);
682 case WAN_UNDEAD_TURNING
:
688 case WAN_MAGIC_MISSILE
:
691 Sprintf(post_engr_text
,
692 "The %s is riddled by bullet holes!",
693 surface(u
.ux
, u
.uy
));
696 /* can't tell sleep from death - Eric Backus */
700 Sprintf(post_engr_text
, "The bugs on the %s stop moving!",
701 surface(u
.ux
, u
.uy
));
706 Strcpy(post_engr_text
,
707 "A few ice cubes drop from the wand.");
708 if (!oep
|| (oep
->engr_type
!= BURN
))
710 case WAN_CANCELLATION
:
711 case WAN_MAKE_INVISIBLE
:
712 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
714 pline_The("engraving on the %s vanishes!",
715 surface(u
.ux
, u
.uy
));
719 case WAN_TELEPORTATION
:
720 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
722 pline_The("engraving on the %s vanishes!",
723 surface(u
.ux
, u
.uy
));
727 /* type = ENGRAVE wands */
731 if (!objects
[otmp
->otyp
].oc_name_known
) {
733 pline("This %s is a wand of digging!", xname(otmp
));
736 Strcpy(post_engr_text
,
738 ? "You hear drilling!"
740 ? "You feel tremors."
741 : IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)
742 ? "Chips fly out from the headstone."
744 ? "Ice chips fly up from the ice surface!"
745 : (level
.locations
[u
.ux
][u
.uy
].typ
747 ? "Splinters fly up from the bridge."
748 : "Gravel flies up from the floor.");
750 /* type = BURN wands */
754 if (!objects
[otmp
->otyp
].oc_name_known
) {
756 pline("This %s is a wand of fire!", xname(otmp
));
759 Strcpy(post_engr_text
, Blind
? "You feel the wand heat up."
760 : "Flames fly from the wand.");
765 if (!objects
[otmp
->otyp
].oc_name_known
) {
767 pline("This %s is a wand of lightning!", xname(otmp
));
771 Strcpy(post_engr_text
, "Lightning arcs from the wand.");
774 Strcpy(post_engr_text
, !Deaf
775 ? "You hear crackling!"
776 : "Your hair stands up!");
779 /* type = MARK wands */
780 /* type = ENGR_BLOOD wands */
782 } else { /* end if zappable */
783 /* failing to wrest one last charge takes time */
784 ptext
= FALSE
; /* use "early exit" below, return 1 */
785 /* give feedback here if we won't be getting the
786 "can't reach floor" message below */
787 if (can_reach_floor(TRUE
)) {
788 /* cancelled wand turns to dust */
791 /* empty wand just doesn't write */
793 pline_The("wand is too worn out to engrave.");
799 if (is_blade(otmp
)) {
800 if ((int) otmp
->spe
> -3)
803 pline("%s too dull for engraving.", Yobjnam2(otmp
, "are"));
808 if (otmp
== ublindf
) {
810 "That is a bit difficult to engrave with, don't you think?");
813 switch (otmp
->otyp
) {
816 Your("marker has dried out.");
821 /* Can't really engrave with a towel */
824 if (oep
->engr_type
== DUST
825 || oep
->engr_type
== ENGR_BLOOD
826 || oep
->engr_type
== MARK
) {
827 if (is_wet_towel(otmp
))
828 dry_a_towel(otmp
, -1, TRUE
);
830 You("wipe out the message here.");
832 pline("%s %s.", Yobjnam2(otmp
, "get"),
833 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
836 pline("%s can't wipe out this engraving.", Yname2(otmp
));
838 pline("%s %s.", Yobjnam2(otmp
, "get"),
839 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
848 pline("Writing a poison pen letter??");
853 impossible("You're engraving with an illegal object!");
857 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
858 if (type
== ENGRAVE
|| type
== 0) {
861 /* ensures the "cannot wipe out" case */
870 * End of implement setup
873 /* Identify stylus */
876 if (objects
[otmp
->otyp
].oc_name_known
)
877 more_experienced(0, 10);
881 oep
= (struct engr
*) 0;
885 oep
= (struct engr
*) 0;
887 /* Something has changed the engraving here */
889 make_engr_at(u
.ux
, u
.uy
, buf
, moves
, type
);
890 pline_The("engraving now reads: \"%s\".", buf
);
893 if (zapwand
&& (otmp
->spe
< 0)) {
894 pline("%s %sturns to dust.", The(xname(otmp
)),
895 Blind
? "" : "glows violently, then ");
896 if (!IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
))
898 "are not going to get anywhere trying to write in the %s with your dust.",
899 is_ice(u
.ux
, u
.uy
) ? "frost" : "dust");
901 otmp
= 0; /* wand is now gone */
904 /* Early exit for some implements. */
906 if (otmp
&& otmp
->oclass
== WAND_CLASS
&& !can_reach_floor(TRUE
))
907 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
911 * Special effects should have deleted the current engraving (if
915 register char c
= 'n';
917 /* Give player the choice to add to engraving. */
918 if (type
== HEADSTONE
) {
919 /* no choice, only append */
921 } else if (type
== oep
->engr_type
922 && (!Blind
|| oep
->engr_type
== BURN
923 || oep
->engr_type
== ENGRAVE
)) {
924 c
= yn_function("Do you want to add to the current engraving?",
932 if (c
== 'n' || Blind
) {
933 if (oep
->engr_type
== DUST
934 || oep
->engr_type
== ENGR_BLOOD
935 || oep
->engr_type
== MARK
) {
937 You("wipe out the message that was %s here.",
938 (oep
->engr_type
== DUST
)
939 ? "written in the dust"
940 : (oep
->engr_type
== ENGR_BLOOD
)
941 ? "scrawled in blood"
944 oep
= (struct engr
*) 0;
946 /* Don't delete engr until after we *know* we're engraving
949 } else if (type
== DUST
|| type
== MARK
|| type
== ENGR_BLOOD
) {
950 You("cannot wipe out the message that is %s the %s here.",
951 oep
->engr_type
== BURN
952 ? (is_ice(u
.ux
, u
.uy
) ? "melted into" : "burned into")
954 surface(u
.ux
, u
.uy
));
956 } else if (type
!= oep
->engr_type
|| c
== 'n') {
957 if (!Blind
|| can_reach_floor(TRUE
))
958 You("will overwrite the current message.");
964 eloc
= surface(u
.ux
, u
.uy
);
967 everb
= (oep
&& !eow
? "add to the weird writing on"
968 : "write strangely on");
971 everb
= (oep
&& !eow
? "add to the writing in" : "write in");
972 eloc
= is_ice(u
.ux
, u
.uy
) ? "frost" : "dust";
975 everb
= (oep
&& !eow
? "add to the epitaph on" : "engrave on");
978 everb
= (oep
&& !eow
? "add to the engraving in" : "engrave in");
982 ? (is_ice(u
.ux
, u
.uy
) ? "add to the text melted into"
983 : "add to the text burned into")
984 : (is_ice(u
.ux
, u
.uy
) ? "melt into" : "burn into"));
987 everb
= (oep
&& !eow
? "add to the graffiti on" : "scribble on");
990 everb
= (oep
&& !eow
? "add to the scrawl on" : "scrawl on");
994 /* Tell adventurer what is going on */
995 if (otmp
!= &zeroobj
)
996 You("%s the %s with %s.", everb
, eloc
, doname(otmp
));
998 You("%s the %s with your %s.", everb
, eloc
, body_part(FINGERTIP
));
1000 /* Prompt for engraving! */
1001 Sprintf(qbuf
, "What do you want to %s the %s here?", everb
, eloc
);
1003 /* convert tabs to spaces and condense consecutive spaces to one */
1006 /* Count the actual # of chars engraved not including spaces */
1008 for (sp
= ebuf
; *sp
; sp
++)
1012 if (len
== 0 || index(ebuf
, '\033')) {
1015 pline("%s, then %s.", Tobjnam(otmp
, "glow"),
1016 otense(otmp
, "fade"));
1024 /* A single `x' is the traditional signature of an illiterate person */
1025 if (len
!= 1 || (!index(ebuf
, 'x') && !index(ebuf
, 'X')))
1026 u
.uconduct
.literate
++;
1028 /* Mix up engraving if surface or state of mind is unsound.
1029 Note: this won't add or remove any spaces. */
1030 for (sp
= ebuf
; *sp
; sp
++) {
1033 if (((type
== DUST
|| type
== ENGR_BLOOD
) && !rn2(25))
1034 || (Blind
&& !rn2(11)) || (Confusion
&& !rn2(7))
1035 || (Stunned
&& !rn2(4)) || (Hallucination
&& !rn2(2)))
1036 *sp
= ' ' + rnd(96 - 2); /* ASCII '!' thru '~'
1037 (excludes ' ' and DEL) */
1040 /* Previous engraving is overwritten */
1043 oep
= (struct engr
*) 0;
1046 /* Figure out how long it took to engrave, and if player has
1047 * engraved too much.
1051 multi
= -(len
/ 10);
1053 nomovemsg
= "You finish your weird engraving.";
1056 multi
= -(len
/ 10);
1058 nomovemsg
= "You finish writing in the dust.";
1062 multi
= -(len
/ 10);
1063 if (otmp
->oclass
== WEAPON_CLASS
1064 && (otmp
->otyp
!= ATHAME
|| otmp
->cursed
)) {
1066 maxelen
= ((otmp
->spe
+ 3) * 2) + 1;
1067 /* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
1068 * Note: this does not allow a +0 anything (except an athame)
1069 * to engrave "Elbereth" all at once.
1070 * However, you can engrave "Elb", then "ere", then "th".
1072 pline("%s dull.", Yobjnam2(otmp
, "get"));
1073 costly_alteration(otmp
, COST_DEGRD
);
1074 if (len
> maxelen
) {
1078 otmp
->spe
-= len
>> 1;
1080 otmp
->spe
-= 1; /* Prevent infinite engraving */
1081 } else if (otmp
->oclass
== RING_CLASS
|| otmp
->oclass
== GEM_CLASS
) {
1085 nomovemsg
= "You finish engraving.";
1088 multi
= -(len
/ 10);
1090 nomovemsg
= is_ice(u
.ux
, u
.uy
)
1091 ? "You finish melting your message into the ice."
1092 : "You finish burning your message into the floor.";
1095 multi
= -(len
/ 10);
1096 if (otmp
->otyp
== MAGIC_MARKER
) {
1097 maxelen
= otmp
->spe
* 2; /* one charge / 2 letters */
1098 if (len
> maxelen
) {
1099 Your("marker dries out.");
1101 multi
= -(maxelen
/ 10);
1103 otmp
->spe
-= len
>> 1;
1105 otmp
->spe
-= 1; /* Prevent infinite graffiti */
1108 nomovemsg
= "You finish defacing the dungeon.";
1111 multi
= -(len
/ 10);
1113 nomovemsg
= "You finish scrawling.";
1117 /* Chop engraving down to size if necessary */
1118 if (len
> maxelen
) {
1119 for (sp
= ebuf
; maxelen
&& *sp
; sp
++)
1122 if (!maxelen
&& *sp
) {
1125 nomovemsg
= "You cannot write any more.";
1126 You("are only able to write \"%s\".", ebuf
);
1130 if (oep
) /* add to existing engraving */
1131 Strcpy(buf
, oep
->engr_txt
);
1132 (void) strncat(buf
, ebuf
, BUFSZ
- (int) strlen(buf
) - 1);
1133 /* Put the engraving onto the map */
1134 make_engr_at(u
.ux
, u
.uy
, buf
, moves
- multi
, type
);
1136 if (post_engr_text
[0])
1137 pline("%s", post_engr_text
);
1138 if (doblind
&& !resists_blnd(&youmonst
)) {
1139 You("are blinded by the flash!");
1140 make_blinded((long) rnd(50), FALSE
);
1142 Your1(vision_clears
);
1147 /* while loading bones, clean up text which might accidentally
1148 or maliciously disrupt player's terminal when displayed */
1150 sanitize_engravings()
1154 for (ep
= head_engr
; ep
; ep
= ep
->nxt_engr
) {
1155 sanitize_name(ep
->engr_txt
);
1160 save_engravings(fd
, mode
)
1163 struct engr
*ep
, *ep2
;
1164 unsigned no_more_engr
= 0;
1166 for (ep
= head_engr
; ep
; ep
= ep2
) {
1168 if (ep
->engr_lth
&& ep
->engr_txt
[0] && perform_bwrite(mode
)) {
1169 bwrite(fd
, (genericptr_t
) &ep
->engr_lth
, sizeof ep
->engr_lth
);
1170 bwrite(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + ep
->engr_lth
);
1172 if (release_data(mode
))
1175 if (perform_bwrite(mode
))
1176 bwrite(fd
, (genericptr_t
) &no_more_engr
, sizeof no_more_engr
);
1177 if (release_data(mode
))
1190 mread(fd
, (genericptr_t
) <h
, sizeof lth
);
1194 mread(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + lth
);
1195 ep
->nxt_engr
= head_engr
;
1197 ep
->engr_txt
= (char *) (ep
+ 1); /* Andreas Bormann */
1198 /* Mark as finished for bones levels -- no problem for
1199 * normal levels as the player must have finished engraving
1200 * to be able to move again.
1202 ep
->engr_time
= moves
;
1206 /* to support '#stats' wizard-mode command */
1208 engr_stats(hdrfmt
, hdrbuf
, count
, size
)
1215 Sprintf(hdrbuf
, hdrfmt
, (long) sizeof (struct engr
));
1216 *count
= *size
= 0L;
1217 for (ep
= head_engr
; ep
; ep
= ep
->nxt_engr
) {
1219 *size
+= (long) sizeof *ep
+ (long) ep
->engr_lth
;
1225 register struct engr
*ep
;
1227 if (ep
== head_engr
) {
1228 head_engr
= ep
->nxt_engr
;
1230 register struct engr
*ept
;
1232 for (ept
= head_engr
; ept
; ept
= ept
->nxt_engr
)
1233 if (ept
->nxt_engr
== ep
) {
1234 ept
->nxt_engr
= ep
->nxt_engr
;
1238 impossible("Error in del_engr?");
1245 /* randomly relocate an engraving */
1250 int tx
, ty
, tryct
= 200;
1255 tx
= rn1(COLNO
- 3, 2);
1257 } while (engr_at(tx
, ty
) || !goodpos(tx
, ty
, (struct monst
*) 0, 0));
1263 /* Create a headstone at the given location.
1264 * The caller is responsible for newsym(x, y).
1267 make_grave(x
, y
, str
)
1273 /* Can we put a grave here? */
1274 if ((levl
[x
][y
].typ
!= ROOM
&& levl
[x
][y
].typ
!= GRAVE
) || t_at(x
, y
))
1276 /* Make the grave */
1277 levl
[x
][y
].typ
= GRAVE
;
1278 /* Engrave the headstone */
1281 str
= get_rnd_text(EPITAPHFILE
, buf
);
1282 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);