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
)) ? "bottom" : "water";
189 else if (is_ice(x
, y
))
191 else if (is_lava(x
, y
))
193 else if (lev
->typ
== DRAWBRIDGE_DOWN
)
195 else if (IS_ALTAR(levl
[x
][y
].typ
))
197 else if (IS_GRAVE(levl
[x
][y
].typ
))
199 else if (IS_FOUNTAIN(levl
[x
][y
].typ
))
201 else if ((IS_ROOM(lev
->typ
) && !Is_earthlevel(&u
.uz
))
202 || IS_WALL(lev
->typ
) || IS_DOOR(lev
->typ
) || lev
->typ
== SDOOR
)
212 register struct rm
*lev
= &levl
[x
][y
];
215 /* other room types will no longer exist when we're interested --
216 * see check_special_room()
218 if (*in_rooms(x
, y
, VAULT
))
219 what
= "vault's ceiling";
220 else if (*in_rooms(x
, y
, TEMPLE
))
221 what
= "temple's ceiling";
222 else if (*in_rooms(x
, y
, SHOPBASE
))
223 what
= "shop's ceiling";
224 else if (Is_waterlevel(&u
.uz
))
225 /* water plane has no surface; its air bubbles aren't below sky */
226 what
= "water above";
227 else if (IS_AIR(lev
->typ
))
230 what
= "water's surface";
231 else if ((IS_ROOM(lev
->typ
) && !Is_earthlevel(&u
.uz
))
232 || IS_WALL(lev
->typ
) || IS_DOOR(lev
->typ
) || lev
->typ
== SDOOR
)
235 what
= "rock cavern";
244 register struct engr
*ep
= head_engr
;
247 if (x
== ep
->engr_x
&& y
== ep
->engr_y
)
251 return (struct engr
*) 0;
254 /* Decide whether a particular string is engraved at a specified
255 * location; a case-insensitive substring match is used.
256 * Ignore headstones, in case the player names herself "Elbereth".
258 * If strict checking is requested, the word is only considered to be
259 * present if it is intact and is the first word in the engraving.
260 * ("Elbereth burrito" matches; "o Elbereth" does not.)
263 sengr_at(s
, x
, y
, strict
)
268 register struct engr
*ep
= engr_at(x
, y
);
270 if (ep
&& ep
->engr_type
!= HEADSTONE
&& ep
->engr_time
<= moves
) {
271 return strict
? (strncmpi(ep
->engr_txt
, s
, strlen(s
)) == 0)
272 : (strstri(ep
->engr_txt
, s
) != 0);
281 if (can_reach_floor(TRUE
))
282 wipe_engr_at(u
.ux
, u
.uy
, cnt
, FALSE
);
286 wipe_engr_at(x
, y
, cnt
, magical
)
287 xchar x
, y
, cnt
, magical
;
289 register struct engr
*ep
= engr_at(x
, y
);
291 /* Headstones are indelible */
292 if (ep
&& ep
->engr_type
!= HEADSTONE
) {
293 debugpline1("asked to erode %d characters", cnt
);
294 if (ep
->engr_type
!= BURN
|| is_ice(x
, y
) || (magical
&& !rn2(2))) {
295 if (ep
->engr_type
!= DUST
&& ep
->engr_type
!= ENGR_BLOOD
) {
296 cnt
= rn2(1 + 50 / (cnt
+ 1)) ? 0 : 1;
297 debugpline1("actually eroding %d characters", cnt
);
299 wipeout_text(ep
->engr_txt
, (int) cnt
, 0);
300 while (ep
->engr_txt
[0] == ' ')
302 if (!ep
->engr_txt
[0])
312 register struct engr
*ep
= engr_at(x
, y
);
316 /* Sensing an engraving does not require sight,
317 * nor does it necessarily imply comprehension (literacy).
319 if (ep
&& ep
->engr_txt
[0]) {
320 switch (ep
->engr_type
) {
324 pline("%s is written here in the %s.", Something
,
325 is_ice(x
, y
) ? "frost" : "dust");
330 if (!Blind
|| can_reach_floor(TRUE
)) {
332 pline("%s is engraved here on the %s.", Something
,
337 if (!Blind
|| can_reach_floor(TRUE
)) {
339 pline("Some text has been %s into the %s here.",
340 is_ice(x
, y
) ? "melted" : "burned", surface(x
, y
));
346 pline("There's some graffiti on the %s here.", surface(x
, y
));
350 /* "It's a message! Scrawled in blood!"
352 * "It says... `See you next Wednesday.'" -- Thriller
356 You_see("a message scrawled in blood here.");
360 impossible("%s is written in a very strange way.", Something
);
365 unsigned maxelen
= BUFSZ
- sizeof("You feel the words: \"\". ");
366 if (strlen(ep
->engr_txt
) > maxelen
) {
367 (void) strncpy(buf
, ep
->engr_txt
, (int) maxelen
);
372 You("%s: \"%s\".", (Blind
) ? "feel the words" : "read", et
);
380 make_engr_at(x
, y
, s
, e_time
, e_type
)
388 if ((ep
= engr_at(x
, y
)) != 0)
390 ep
= newengr(strlen(s
) + 1);
391 ep
->nxt_engr
= head_engr
;
395 ep
->engr_txt
= (char *) (ep
+ 1);
396 Strcpy(ep
->engr_txt
, s
);
397 /* engraving Elbereth shows wisdom */
398 if (!in_mklev
&& !strcmp(s
, "Elbereth"))
399 exercise(A_WIS
, TRUE
);
400 ep
->engr_time
= e_time
;
401 ep
->engr_type
= e_type
> 0 ? e_type
: rnd(N_ENGRAVE
- 1);
402 ep
->engr_lth
= strlen(s
) + 1;
405 /* delete any engraving at location <x,y> */
410 register struct engr
*ep
= engr_at(x
, y
);
417 * freehand - returns true if player has a free hand
422 return (!uwep
|| !welded(uwep
)
423 || (!bimanual(uwep
) && (!uarms
|| !uarms
->cursed
)));
426 static NEARDATA
const char styluses
[] = { ALL_CLASSES
, ALLOW_NONE
,
427 TOOL_CLASS
, WEAPON_CLASS
,
428 WAND_CLASS
, GEM_CLASS
,
431 /* Mohs' Hardness Scale:
432 * 1 - Talc 6 - Orthoclase
433 * 2 - Gypsum 7 - Quartz
434 * 3 - Calcite 8 - Topaz
435 * 4 - Fluorite 9 - Corundum
436 * 5 - Apatite 10 - Diamond
438 * Since granite is an igneous rock hardness ~ 7, anything >= 8 should
439 * probably be able to scratch the rock.
440 * Devaluation of less hard gems is not easily possible because obj struct
441 * does not contain individual oc_cost currently. 7/91
443 * steel - 5-8.5 (usu. weapon)
444 * diamond - 10 * jade - 5-6 (nephrite)
445 * ruby - 9 (corundum) * turquoise - 5-6
446 * sapphire - 9 (corundum) * opal - 5-6
447 * topaz - 8 * glass - ~5.5
448 * emerald - 7.5-8 (beryl) * dilithium - 4-5??
449 * aquamarine - 7.5-8 (beryl) * iron - 4-5
450 * garnet - 7.25 (var. 6.5-8) * fluorite - 4
451 * agate - 7 (quartz) * brass - 3-4
452 * amethyst - 7 (quartz) * gold - 2.5-3
453 * jasper - 7 (quartz) * silver - 2.5-3
454 * onyx - 7 (quartz) * copper - 2.5-3
455 * moonstone - 6 (orthoclase) * amber - 2-2.5
458 /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
462 boolean dengr
= FALSE
; /* TRUE if we wipe out the current engraving */
463 boolean doblind
= FALSE
; /* TRUE if engraving blinds the player */
464 boolean doknown
= FALSE
; /* TRUE if we identify the stylus */
465 boolean eow
= FALSE
; /* TRUE if we are overwriting oep */
466 boolean jello
= FALSE
; /* TRUE if we are engraving in slime */
467 boolean ptext
= TRUE
; /* TRUE if we must prompt for engrave text */
468 boolean teleengr
= FALSE
; /* TRUE if we move the old engraving */
469 boolean zapwand
= FALSE
; /* TRUE if we remove a wand charge */
470 xchar type
= DUST
; /* Type of engraving made */
471 char buf
[BUFSZ
]; /* Buffer for final/poly engraving text */
472 char ebuf
[BUFSZ
]; /* Buffer for initial engraving text */
473 char fbuf
[BUFSZ
]; /* Buffer for "your fingers" */
474 char qbuf
[QBUFSZ
]; /* Buffer for query text */
475 char post_engr_text
[BUFSZ
]; /* Text displayed after engraving prompt */
476 const char *everb
; /* Present tense of engraving type */
477 const char *eloc
; /* Where the engraving is (ie dust/floor/...) */
478 char *sp
; /* Place holder for space count of engr text */
479 int len
; /* # of nonspace chars of new engraving text */
480 int maxelen
; /* Max allowable length of engraving text */
481 struct engr
*oep
= engr_at(u
.ux
, u
.uy
);
482 /* The current engraving */
483 struct obj
*otmp
; /* Object selected with which to engrave */
486 multi
= 0; /* moves consumed */
487 nomovemsg
= (char *) 0; /* occupation end message */
491 post_engr_text
[0] = (char) 0;
493 if (is_demon(youmonst
.data
) || youmonst
.data
->mlet
== S_VAMPIRE
)
496 /* Can the adventurer engrave at all? */
499 if (is_animal(u
.ustuck
->data
)) {
500 pline("What would you write? \"Jonah was here\"?");
502 } else if (is_whirly(u
.ustuck
->data
)) {
503 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, FALSE
);
507 } else if (is_lava(u
.ux
, u
.uy
)) {
508 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
510 } else if (is_pool(u
.ux
, u
.uy
) || IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
511 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
514 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) /* in bubble */) {
515 You_cant("write in thin air!");
517 } else if (!accessible(u
.ux
, u
.uy
)) {
518 /* stone, tree, wall, secret corridor, pool, lava, bars */
519 You_cant("write here.");
522 if (cantwield(youmonst
.data
)) {
523 You_cant("even hold anything!");
526 if (check_capacity((char *) 0))
529 /* One may write with finger, or weapon, or wand, or..., or...
530 * Edited by GAN 10/20/86 so as not to change weapon wielded.
533 otmp
= getobj(styluses
, "write with");
534 if (!otmp
) /* otmp == zeroobj if fingers */
537 if (otmp
== &zeroobj
) {
538 Strcat(strcpy(fbuf
, "your "), body_part(FINGERTIP
));
541 writer
= yname(otmp
);
543 /* There's no reason you should be able to write with a wand
544 * while both your hands are tied up.
546 if (!freehand() && otmp
!= uwep
&& !otmp
->owornmask
) {
547 You("have no free %s to write with!", body_part(HAND
));
552 You("tickle %s with %s.", mon_nam(u
.ustuck
), writer
);
553 Your("message dissolves...");
556 if (otmp
->oclass
!= WAND_CLASS
&& !can_reach_floor(TRUE
)) {
557 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
560 if (IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
)) {
561 You("make a motion towards the altar with %s.", writer
);
562 altar_wrath(u
.ux
, u
.uy
);
565 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
566 if (otmp
== &zeroobj
) { /* using only finger */
567 You("would only make a small smudge on the %s.",
568 surface(u
.ux
, u
.uy
));
570 } else if (!levl
[u
.ux
][u
.uy
].disturbed
) {
571 You("disturb the undead!");
572 levl
[u
.ux
][u
.uy
].disturbed
= 1;
573 (void) makemon(&mons
[PM_GHOUL
], u
.ux
, u
.uy
, NO_MM_FLAGS
);
574 exercise(A_WIS
, FALSE
);
581 switch (otmp
->oclass
) {
589 /* "diamond" rings and others should work */
591 /* diamonds & other hard gems should work */
592 if (objects
[otmp
->otyp
].oc_tough
) {
598 if (is_boots(otmp
)) {
603 /* Objects too large to engrave with */
606 You_cant("engrave with such a large object!");
609 /* Objects too silly to engrave with */
613 pline("%s would get %s.", Yname2(otmp
),
614 is_ice(u
.ux
, u
.uy
) ? "all frosty" : "too dirty");
617 case RANDOM_CLASS
: /* This should mean fingers */
620 /* The charge is removed from the wand before prompting for
621 * the engraving text, because all kinds of setup decisions
622 * and pre-engraving messages are based upon knowing what type
623 * of engraving the wand is going to do. Also, the player
624 * will have potentially seen "You wrest .." message, and
625 * therefore will know they are using a charge.
628 if (zappable(otmp
)) {
630 if (otmp
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
631 wand_explode(otmp
, 0);
635 if (!can_reach_floor(TRUE
))
638 switch (otmp
->otyp
) {
644 case WAN_SECRET_DOOR_DETECTION
:
645 case WAN_CREATE_MONSTER
:
647 case WAN_ENLIGHTENMENT
:
650 /* IMMEDIATE wands */
651 /* If wand is "IMMEDIATE", remember to affect the
652 * previous engraving even if turning to dust.
655 Strcpy(post_engr_text
,
656 "The wand unsuccessfully fights your attempt to write!");
658 case WAN_SLOW_MONSTER
:
660 Sprintf(post_engr_text
, "The bugs on the %s slow down!",
661 surface(u
.ux
, u
.uy
));
664 case WAN_SPEED_MONSTER
:
666 Sprintf(post_engr_text
, "The bugs on the %s speed up!",
667 surface(u
.ux
, u
.uy
));
673 type
= (xchar
) 0; /* random */
674 (void) random_engraving(buf
);
680 case WAN_UNDEAD_TURNING
:
686 case WAN_MAGIC_MISSILE
:
689 Sprintf(post_engr_text
,
690 "The %s is riddled by bullet holes!",
691 surface(u
.ux
, u
.uy
));
694 /* can't tell sleep from death - Eric Backus */
698 Sprintf(post_engr_text
, "The bugs on the %s stop moving!",
699 surface(u
.ux
, u
.uy
));
704 Strcpy(post_engr_text
,
705 "A few ice cubes drop from the wand.");
706 if (!oep
|| (oep
->engr_type
!= BURN
))
708 case WAN_CANCELLATION
:
709 case WAN_MAKE_INVISIBLE
:
710 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
712 pline_The("engraving on the %s vanishes!",
713 surface(u
.ux
, u
.uy
));
717 case WAN_TELEPORTATION
:
718 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
720 pline_The("engraving on the %s vanishes!",
721 surface(u
.ux
, u
.uy
));
725 /* type = ENGRAVE wands */
729 if (!objects
[otmp
->otyp
].oc_name_known
) {
731 pline("This %s is a wand of digging!", xname(otmp
));
734 Strcpy(post_engr_text
,
736 ? "You hear drilling!"
738 ? "You feel tremors."
739 : IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)
740 ? "Chips fly out from the headstone."
742 ? "Ice chips fly up from the ice surface!"
743 : (level
.locations
[u
.ux
][u
.uy
].typ
745 ? "Splinters fly up from the bridge."
746 : "Gravel flies up from the floor.");
748 /* type = BURN wands */
752 if (!objects
[otmp
->otyp
].oc_name_known
) {
754 pline("This %s is a wand of fire!", xname(otmp
));
757 Strcpy(post_engr_text
, Blind
? "You feel the wand heat up."
758 : "Flames fly from the wand.");
763 if (!objects
[otmp
->otyp
].oc_name_known
) {
765 pline("This %s is a wand of lightning!", xname(otmp
));
769 Strcpy(post_engr_text
, "Lightning arcs from the wand.");
772 Strcpy(post_engr_text
, !Deaf
773 ? "You hear crackling!"
774 : "Your hair stands up!");
777 /* type = MARK wands */
778 /* type = ENGR_BLOOD wands */
780 } else { /* end if zappable */
781 /* failing to wrest one last charge takes time */
782 ptext
= FALSE
; /* use "early exit" below, return 1 */
783 /* give feedback here if we won't be getting the
784 "can't reach floor" message below */
785 if (can_reach_floor(TRUE
)) {
786 /* cancelled wand turns to dust */
789 /* empty wand just doesn't write */
791 pline_The("wand is too worn out to engrave.");
797 if (is_blade(otmp
)) {
798 if ((int) otmp
->spe
> -3)
801 pline("%s too dull for engraving.", Yobjnam2(otmp
, "are"));
806 if (otmp
== ublindf
) {
808 "That is a bit difficult to engrave with, don't you think?");
811 switch (otmp
->otyp
) {
814 Your("marker has dried out.");
819 /* Can't really engrave with a towel */
822 if (oep
->engr_type
== DUST
823 || oep
->engr_type
== ENGR_BLOOD
824 || oep
->engr_type
== MARK
) {
825 if (is_wet_towel(otmp
))
826 dry_a_towel(otmp
, -1, TRUE
);
828 You("wipe out the message here.");
830 pline("%s %s.", Yobjnam2(otmp
, "get"),
831 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
834 pline("%s can't wipe out this engraving.", Yname2(otmp
));
836 pline("%s %s.", Yobjnam2(otmp
, "get"),
837 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
846 pline("Writing a poison pen letter??");
851 impossible("You're engraving with an illegal object!");
855 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
856 if (type
== ENGRAVE
|| type
== 0) {
859 /* ensures the "cannot wipe out" case */
868 * End of implement setup
871 /* Identify stylus */
874 if (objects
[otmp
->otyp
].oc_name_known
)
875 more_experienced(0, 10);
879 oep
= (struct engr
*) 0;
883 oep
= (struct engr
*) 0;
885 /* Something has changed the engraving here */
887 make_engr_at(u
.ux
, u
.uy
, buf
, moves
, type
);
888 pline_The("engraving now reads: \"%s\".", buf
);
891 if (zapwand
&& (otmp
->spe
< 0)) {
892 pline("%s %sturns to dust.", The(xname(otmp
)),
893 Blind
? "" : "glows violently, then ");
894 if (!IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
))
896 "are not going to get anywhere trying to write in the %s with your dust.",
897 is_ice(u
.ux
, u
.uy
) ? "frost" : "dust");
899 otmp
= 0; /* wand is now gone */
902 /* Early exit for some implements. */
904 if (otmp
&& otmp
->oclass
== WAND_CLASS
&& !can_reach_floor(TRUE
))
905 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
909 * Special effects should have deleted the current engraving (if
913 register char c
= 'n';
915 /* Give player the choice to add to engraving. */
916 if (type
== HEADSTONE
) {
917 /* no choice, only append */
919 } else if (type
== oep
->engr_type
920 && (!Blind
|| oep
->engr_type
== BURN
921 || oep
->engr_type
== ENGRAVE
)) {
922 c
= yn_function("Do you want to add to the current engraving?",
930 if (c
== 'n' || Blind
) {
931 if (oep
->engr_type
== DUST
932 || oep
->engr_type
== ENGR_BLOOD
933 || oep
->engr_type
== MARK
) {
935 You("wipe out the message that was %s here.",
936 (oep
->engr_type
== DUST
)
937 ? "written in the dust"
938 : (oep
->engr_type
== ENGR_BLOOD
)
939 ? "scrawled in blood"
942 oep
= (struct engr
*) 0;
944 /* Don't delete engr until after we *know* we're engraving
947 } else if (type
== DUST
|| type
== MARK
|| type
== ENGR_BLOOD
) {
948 You("cannot wipe out the message that is %s the %s here.",
949 oep
->engr_type
== BURN
950 ? (is_ice(u
.ux
, u
.uy
) ? "melted into" : "burned into")
952 surface(u
.ux
, u
.uy
));
954 } else if (type
!= oep
->engr_type
|| c
== 'n') {
955 if (!Blind
|| can_reach_floor(TRUE
))
956 You("will overwrite the current message.");
962 eloc
= surface(u
.ux
, u
.uy
);
965 everb
= (oep
&& !eow
? "add to the weird writing on"
966 : "write strangely on");
969 everb
= (oep
&& !eow
? "add to the writing in" : "write in");
970 eloc
= is_ice(u
.ux
, u
.uy
) ? "frost" : "dust";
973 everb
= (oep
&& !eow
? "add to the epitaph on" : "engrave on");
976 everb
= (oep
&& !eow
? "add to the engraving in" : "engrave in");
980 ? (is_ice(u
.ux
, u
.uy
) ? "add to the text melted into"
981 : "add to the text burned into")
982 : (is_ice(u
.ux
, u
.uy
) ? "melt into" : "burn into"));
985 everb
= (oep
&& !eow
? "add to the graffiti on" : "scribble on");
988 everb
= (oep
&& !eow
? "add to the scrawl on" : "scrawl on");
992 /* Tell adventurer what is going on */
993 if (otmp
!= &zeroobj
)
994 You("%s the %s with %s.", everb
, eloc
, doname(otmp
));
996 You("%s the %s with your %s.", everb
, eloc
, body_part(FINGERTIP
));
998 /* Prompt for engraving! */
999 Sprintf(qbuf
, "What do you want to %s the %s here?", everb
, eloc
);
1001 /* convert tabs to spaces and condense consecutive spaces to one */
1004 /* Count the actual # of chars engraved not including spaces */
1006 for (sp
= ebuf
; *sp
; sp
++)
1010 if (len
== 0 || index(ebuf
, '\033')) {
1013 pline("%s, then %s.", Tobjnam(otmp
, "glow"),
1014 otense(otmp
, "fade"));
1022 /* A single `x' is the traditional signature of an illiterate person */
1023 if (len
!= 1 || (!index(ebuf
, 'x') && !index(ebuf
, 'X')))
1024 u
.uconduct
.literate
++;
1026 /* Mix up engraving if surface or state of mind is unsound.
1027 Note: this won't add or remove any spaces. */
1028 for (sp
= ebuf
; *sp
; sp
++) {
1031 if (((type
== DUST
|| type
== ENGR_BLOOD
) && !rn2(25))
1032 || (Blind
&& !rn2(11)) || (Confusion
&& !rn2(7))
1033 || (Stunned
&& !rn2(4)) || (Hallucination
&& !rn2(2)))
1034 *sp
= ' ' + rnd(96 - 2); /* ASCII '!' thru '~'
1035 (excludes ' ' and DEL) */
1038 /* Previous engraving is overwritten */
1041 oep
= (struct engr
*) 0;
1044 /* Figure out how long it took to engrave, and if player has
1045 * engraved too much.
1049 multi
= -(len
/ 10);
1051 nomovemsg
= "You finish your weird engraving.";
1054 multi
= -(len
/ 10);
1056 nomovemsg
= "You finish writing in the dust.";
1060 multi
= -(len
/ 10);
1061 if (otmp
->oclass
== WEAPON_CLASS
1062 && (otmp
->otyp
!= ATHAME
|| otmp
->cursed
)) {
1064 maxelen
= ((otmp
->spe
+ 3) * 2) + 1;
1065 /* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
1066 * Note: this does not allow a +0 anything (except an athame)
1067 * to engrave "Elbereth" all at once.
1068 * However, you can engrave "Elb", then "ere", then "th".
1070 pline("%s dull.", Yobjnam2(otmp
, "get"));
1071 costly_alteration(otmp
, COST_DEGRD
);
1072 if (len
> maxelen
) {
1076 otmp
->spe
-= len
>> 1;
1078 otmp
->spe
-= 1; /* Prevent infinite engraving */
1079 } else if (otmp
->oclass
== RING_CLASS
|| otmp
->oclass
== GEM_CLASS
) {
1083 nomovemsg
= "You finish engraving.";
1086 multi
= -(len
/ 10);
1088 nomovemsg
= is_ice(u
.ux
, u
.uy
)
1089 ? "You finish melting your message into the ice."
1090 : "You finish burning your message into the floor.";
1093 multi
= -(len
/ 10);
1094 if (otmp
->otyp
== MAGIC_MARKER
) {
1095 maxelen
= otmp
->spe
* 2; /* one charge / 2 letters */
1096 if (len
> maxelen
) {
1097 Your("marker dries out.");
1099 multi
= -(maxelen
/ 10);
1101 otmp
->spe
-= len
>> 1;
1103 otmp
->spe
-= 1; /* Prevent infinite graffiti */
1106 nomovemsg
= "You finish defacing the dungeon.";
1109 multi
= -(len
/ 10);
1111 nomovemsg
= "You finish scrawling.";
1115 /* Chop engraving down to size if necessary */
1116 if (len
> maxelen
) {
1117 for (sp
= ebuf
; maxelen
&& *sp
; sp
++)
1120 if (!maxelen
&& *sp
) {
1123 nomovemsg
= "You cannot write any more.";
1124 You("are only able to write \"%s\".", ebuf
);
1128 if (oep
) /* add to existing engraving */
1129 Strcpy(buf
, oep
->engr_txt
);
1130 (void) strncat(buf
, ebuf
, BUFSZ
- (int) strlen(buf
) - 1);
1131 /* Put the engraving onto the map */
1132 make_engr_at(u
.ux
, u
.uy
, buf
, moves
- multi
, type
);
1134 if (post_engr_text
[0])
1135 pline("%s", post_engr_text
);
1136 if (doblind
&& !resists_blnd(&youmonst
)) {
1137 You("are blinded by the flash!");
1138 make_blinded((long) rnd(50), FALSE
);
1140 Your1(vision_clears
);
1145 /* while loading bones, clean up text which might accidentally
1146 or maliciously disrupt player's terminal when displayed */
1148 sanitize_engravings()
1152 for (ep
= head_engr
; ep
; ep
= ep
->nxt_engr
) {
1153 sanitize_name(ep
->engr_txt
);
1158 save_engravings(fd
, mode
)
1161 struct engr
*ep
, *ep2
;
1162 unsigned no_more_engr
= 0;
1164 for (ep
= head_engr
; ep
; ep
= ep2
) {
1166 if (ep
->engr_lth
&& ep
->engr_txt
[0] && perform_bwrite(mode
)) {
1167 bwrite(fd
, (genericptr_t
) &ep
->engr_lth
, sizeof ep
->engr_lth
);
1168 bwrite(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + ep
->engr_lth
);
1170 if (release_data(mode
))
1173 if (perform_bwrite(mode
))
1174 bwrite(fd
, (genericptr_t
) &no_more_engr
, sizeof no_more_engr
);
1175 if (release_data(mode
))
1188 mread(fd
, (genericptr_t
) <h
, sizeof lth
);
1192 mread(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + lth
);
1193 ep
->nxt_engr
= head_engr
;
1195 ep
->engr_txt
= (char *) (ep
+ 1); /* Andreas Bormann */
1196 /* Mark as finished for bones levels -- no problem for
1197 * normal levels as the player must have finished engraving
1198 * to be able to move again.
1200 ep
->engr_time
= moves
;
1206 register struct engr
*ep
;
1208 if (ep
== head_engr
) {
1209 head_engr
= ep
->nxt_engr
;
1211 register struct engr
*ept
;
1213 for (ept
= head_engr
; ept
; ept
= ept
->nxt_engr
)
1214 if (ept
->nxt_engr
== ep
) {
1215 ept
->nxt_engr
= ep
->nxt_engr
;
1219 impossible("Error in del_engr?");
1226 /* randomly relocate an engraving */
1231 int tx
, ty
, tryct
= 200;
1236 tx
= rn1(COLNO
- 3, 2);
1238 } while (engr_at(tx
, ty
) || !goodpos(tx
, ty
, (struct monst
*) 0, 0));
1244 /* Create a headstone at the given location.
1245 * The caller is responsible for newsym(x, y).
1248 make_grave(x
, y
, str
)
1254 /* Can we put a grave here? */
1255 if ((levl
[x
][y
].typ
!= ROOM
&& levl
[x
][y
].typ
!= GRAVE
) || t_at(x
, y
))
1257 /* Make the grave */
1258 levl
[x
][y
].typ
= GRAVE
;
1259 /* Engrave the headstone */
1262 str
= get_rnd_text(EPITAPHFILE
, buf
);
1263 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);