1 /* aNetHack 0.0.1 engrave.c $ANH-Date: 1456304550 2016/02/24 09:02:30 $ $ANH-Branch: master $:$ANH-Revision: 1.61 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack 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 entire content of the engraving.
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
? (fuzzymatch(ep
->engr_txt
, s
, "", TRUE
))
272 : (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
)
388 unsigned smem
= strlen(s
) + 1;
390 if ((ep
= engr_at(x
, y
)) != 0)
393 (void) memset((genericptr_t
)ep
, 0, smem
+ sizeof(struct engr
));
394 ep
->nxt_engr
= head_engr
;
398 ep
->engr_txt
= (char *) (ep
+ 1);
399 Strcpy(ep
->engr_txt
, s
);
400 /* engraving Elbereth shows wisdom */
401 if (!in_mklev
&& !strcmp(s
, "Elbereth"))
402 exercise(A_WIS
, TRUE
);
403 ep
->engr_time
= e_time
;
404 ep
->engr_type
= e_type
> 0 ? e_type
: rnd(N_ENGRAVE
- 1);
408 /* delete any engraving at location <x,y> */
413 register struct engr
*ep
= engr_at(x
, y
);
420 * freehand - returns true if player has a free hand
425 return (!uwep
|| !welded(uwep
)
426 || (!bimanual(uwep
) && (!uarms
|| !uarms
->cursed
)));
429 static NEARDATA
const char styluses
[] = { ALL_CLASSES
, ALLOW_NONE
,
430 TOOL_CLASS
, WEAPON_CLASS
,
431 WAND_CLASS
, GEM_CLASS
,
434 /* Mohs' Hardness Scale:
435 * 1 - Talc 6 - Orthoclase
436 * 2 - Gypsum 7 - Quartz
437 * 3 - Calcite 8 - Topaz
438 * 4 - Fluorite 9 - Corundum
439 * 5 - Apatite 10 - Diamond
441 * Since granite is an igneous rock hardness ~ 7, anything >= 8 should
442 * probably be able to scratch the rock.
443 * Devaluation of less hard gems is not easily possible because obj struct
444 * does not contain individual oc_cost currently. 7/91
446 * steel - 5-8.5 (usu. weapon)
447 * diamond - 10 * jade - 5-6 (nephrite)
448 * ruby - 9 (corundum) * turquoise - 5-6
449 * sapphire - 9 (corundum) * opal - 5-6
450 * topaz - 8 * glass - ~5.5
451 * emerald - 7.5-8 (beryl) * dilithium - 4-5??
452 * aquamarine - 7.5-8 (beryl) * iron - 4-5
453 * garnet - 7.25 (var. 6.5-8) * fluorite - 4
454 * agate - 7 (quartz) * brass - 3-4
455 * amethyst - 7 (quartz) * gold - 2.5-3
456 * jasper - 7 (quartz) * silver - 2.5-3
457 * onyx - 7 (quartz) * copper - 2.5-3
458 * moonstone - 6 (orthoclase) * amber - 2-2.5
461 /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
465 boolean dengr
= FALSE
; /* TRUE if we wipe out the current engraving */
466 boolean doblind
= FALSE
; /* TRUE if engraving blinds the player */
467 boolean doknown
= FALSE
; /* TRUE if we identify the stylus */
468 boolean eow
= FALSE
; /* TRUE if we are overwriting oep */
469 boolean jello
= FALSE
; /* TRUE if we are engraving in slime */
470 boolean ptext
= TRUE
; /* TRUE if we must prompt for engrave text */
471 boolean teleengr
= FALSE
; /* TRUE if we move the old engraving */
472 boolean zapwand
= FALSE
; /* TRUE if we remove a wand charge */
473 xchar type
= DUST
; /* Type of engraving made */
474 char buf
[BUFSZ
]; /* Buffer for final/poly engraving text */
475 char ebuf
[BUFSZ
]; /* Buffer for initial engraving text */
476 char fbuf
[BUFSZ
]; /* Buffer for "your fingers" */
477 char qbuf
[QBUFSZ
]; /* Buffer for query text */
478 char post_engr_text
[BUFSZ
]; /* Text displayed after engraving prompt */
479 const char *everb
; /* Present tense of engraving type */
480 const char *eloc
; /* Where the engraving is (ie dust/floor/...) */
481 char *sp
; /* Place holder for space count of engr text */
482 int len
; /* # of nonspace chars of new engraving text */
483 int maxelen
; /* Max allowable length of engraving text */
484 struct engr
*oep
= engr_at(u
.ux
, u
.uy
);
485 /* The current engraving */
486 struct obj
*otmp
; /* Object selected with which to engrave */
489 multi
= 0; /* moves consumed */
490 nomovemsg
= (char *) 0; /* occupation end message */
494 post_engr_text
[0] = (char) 0;
496 if (is_demon(youmonst
.data
) || youmonst
.data
->mlet
== S_VAMPIRE
)
499 /* Can the adventurer engrave at all? */
502 if (is_animal(u
.ustuck
->data
)) {
503 pline("What would you write? \"Jonah was here\"?");
505 } else if (is_whirly(u
.ustuck
->data
)) {
506 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, FALSE
);
510 } else if (is_lava(u
.ux
, u
.uy
)) {
511 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
513 } else if (is_pool(u
.ux
, u
.uy
) || IS_FOUNTAIN(levl
[u
.ux
][u
.uy
].typ
)) {
514 You_cant("write on the %s!", surface(u
.ux
, u
.uy
));
517 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) /* in bubble */) {
518 You_cant("write in thin air!");
520 } else if (!accessible(u
.ux
, u
.uy
)) {
521 /* stone, tree, wall, secret corridor, pool, lava, bars */
522 You_cant("write here.");
525 if (cantwield(youmonst
.data
)) {
526 You_cant("even hold anything!");
529 if (check_capacity((char *) 0))
532 /* One may write with finger, or weapon, or wand, or..., or...
533 * Edited by GAN 10/20/86 so as not to change weapon wielded.
536 otmp
= getobj(styluses
, "write with");
537 if (!otmp
) /* otmp == zeroobj if fingers */
540 if (otmp
== &zeroobj
) {
541 Strcat(strcpy(fbuf
, "your "), body_part(FINGERTIP
));
544 writer
= yname(otmp
);
546 /* There's no reason you should be able to write with a wand
547 * while both your hands are tied up.
549 if (!freehand() && otmp
!= uwep
&& !otmp
->owornmask
) {
550 You("have no free %s to write with!", body_part(HAND
));
555 You("tickle %s with %s.", mon_nam(u
.ustuck
), writer
);
556 Your("message dissolves...");
559 if (otmp
->oclass
!= WAND_CLASS
&& !can_reach_floor(TRUE
)) {
560 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
563 if (IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
)) {
564 You("make a motion towards the altar with %s.", writer
);
565 altar_wrath(u
.ux
, u
.uy
);
568 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
569 if (otmp
== &zeroobj
) { /* using only finger */
570 You("would only make a small smudge on the %s.",
571 surface(u
.ux
, u
.uy
));
573 } else if (!levl
[u
.ux
][u
.uy
].disturbed
) {
574 You("disturb the undead!");
575 levl
[u
.ux
][u
.uy
].disturbed
= 1;
576 (void) makemon(&mons
[PM_GHOUL
], u
.ux
, u
.uy
, NO_MM_FLAGS
);
577 exercise(A_WIS
, FALSE
);
584 switch (otmp
->oclass
) {
592 /* "diamond" rings and others should work */
594 /* diamonds & other hard gems should work */
595 if (objects
[otmp
->otyp
].oc_tough
) {
601 if (is_boots(otmp
)) {
606 /* Objects too large to engrave with */
609 You_cant("engrave with such a large object!");
612 /* Objects too silly to engrave with */
616 pline("%s would get %s.", Yname2(otmp
),
617 is_ice(u
.ux
, u
.uy
) ? "all frosty" : "too dirty");
620 case RANDOM_CLASS
: /* This should mean fingers */
623 /* The charge is removed from the wand before prompting for
624 * the engraving text, because all kinds of setup decisions
625 * and pre-engraving messages are based upon knowing what type
626 * of engraving the wand is going to do. Also, the player
627 * will have potentially seen "You wrest .." message, and
628 * therefore will know they are using a charge.
631 if (zappable(otmp
)) {
633 if (otmp
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
634 wand_explode(otmp
, 0);
638 if (!can_reach_floor(TRUE
))
641 switch (otmp
->otyp
) {
647 case WAN_SECRET_DOOR_DETECTION
:
648 case WAN_CREATE_MONSTER
:
650 case WAN_ENLIGHTENMENT
:
653 /* IMMEDIATE wands */
654 /* If wand is "IMMEDIATE", remember to affect the
655 * previous engraving even if turning to dust.
658 Strcpy(post_engr_text
,
659 "The wand unsuccessfully fights your attempt to write!");
661 case WAN_SLOW_MONSTER
:
663 Sprintf(post_engr_text
, "The bugs on the %s slow down!",
664 surface(u
.ux
, u
.uy
));
667 case WAN_SPEED_MONSTER
:
669 Sprintf(post_engr_text
, "The bugs on the %s speed up!",
670 surface(u
.ux
, u
.uy
));
676 type
= (xchar
) 0; /* random */
677 (void) random_engraving(buf
);
683 case WAN_UNDEAD_TURNING
:
689 case WAN_MAGIC_MISSILE
:
692 Sprintf(post_engr_text
,
693 "The %s is riddled by bullet holes!",
694 surface(u
.ux
, u
.uy
));
697 /* can't tell sleep from death - Eric Backus */
701 Sprintf(post_engr_text
, "The bugs on the %s stop moving!",
702 surface(u
.ux
, u
.uy
));
707 Strcpy(post_engr_text
,
708 "A few ice cubes drop from the wand.");
709 if (!oep
|| (oep
->engr_type
!= BURN
))
711 case WAN_CANCELLATION
:
712 case WAN_MAKE_INVISIBLE
:
713 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
715 pline_The("engraving on the %s vanishes!",
716 surface(u
.ux
, u
.uy
));
720 case WAN_TELEPORTATION
:
721 if (oep
&& oep
->engr_type
!= HEADSTONE
) {
723 pline_The("engraving on the %s vanishes!",
724 surface(u
.ux
, u
.uy
));
728 /* type = ENGRAVE wands */
732 if (!objects
[otmp
->otyp
].oc_name_known
) {
734 pline("This %s is a wand of digging!", xname(otmp
));
737 Strcpy(post_engr_text
,
739 ? "You hear drilling!"
741 ? "You feel tremors."
742 : IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)
743 ? "Chips fly out from the headstone."
745 ? "Ice chips fly up from the ice surface!"
746 : (level
.locations
[u
.ux
][u
.uy
].typ
748 ? "Splinters fly up from the bridge."
749 : "Gravel flies up from the floor.");
751 /* type = BURN wands */
755 if (!objects
[otmp
->otyp
].oc_name_known
) {
757 pline("This %s is a wand of fire!", xname(otmp
));
760 Strcpy(post_engr_text
, Blind
? "You feel the wand heat up."
761 : "Flames fly from the wand.");
766 if (!objects
[otmp
->otyp
].oc_name_known
) {
768 pline("This %s is a wand of lightning!", xname(otmp
));
772 Strcpy(post_engr_text
, "Lightning arcs from the wand.");
775 Strcpy(post_engr_text
, !Deaf
776 ? "You hear crackling!"
777 : "Your hair stands up!");
780 /* type = MARK wands */
781 /* type = ENGR_BLOOD wands */
783 } else { /* end if zappable */
784 /* failing to wrest one last charge takes time */
785 ptext
= FALSE
; /* use "early exit" below, return 1 */
786 /* give feedback here if we won't be getting the
787 "can't reach floor" message below */
788 if (can_reach_floor(TRUE
)) {
789 /* cancelled wand turns to dust */
792 /* empty wand just doesn't write */
794 pline_The("wand is too worn out to engrave.");
800 if (is_blade(otmp
)) {
801 if ((int) otmp
->spe
> -3)
804 pline("%s too dull for engraving.", Yobjnam2(otmp
, "are"));
809 if (otmp
== ublindf
) {
811 "That is a bit difficult to engrave with, don't you think?");
814 switch (otmp
->otyp
) {
817 Your("marker has dried out.");
822 /* Can't really engrave with a towel */
825 if (oep
->engr_type
== DUST
826 || oep
->engr_type
== ENGR_BLOOD
827 || oep
->engr_type
== MARK
) {
828 if (is_wet_towel(otmp
))
829 dry_a_towel(otmp
, -1, TRUE
);
831 You("wipe out the message here.");
833 pline("%s %s.", Yobjnam2(otmp
, "get"),
834 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
837 pline("%s can't wipe out this engraving.", Yname2(otmp
));
839 pline("%s %s.", Yobjnam2(otmp
, "get"),
840 is_ice(u
.ux
, u
.uy
) ? "frosty" : "dusty");
849 pline("Writing a poison pen letter??");
854 impossible("You're engraving with an illegal object!");
858 if (IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
)) {
859 if (type
== ENGRAVE
|| type
== 0) {
862 /* ensures the "cannot wipe out" case */
871 * End of implement setup
874 /* Identify stylus */
877 if (objects
[otmp
->otyp
].oc_name_known
)
878 more_experienced(0, 10);
882 oep
= (struct engr
*) 0;
886 oep
= (struct engr
*) 0;
888 /* Something has changed the engraving here */
890 make_engr_at(u
.ux
, u
.uy
, buf
, moves
, type
);
891 pline_The("engraving now reads: \"%s\".", buf
);
894 if (zapwand
&& (otmp
->spe
< 0)) {
895 pline("%s %sturns to dust.", The(xname(otmp
)),
896 Blind
? "" : "glows violently, then ");
897 if (!IS_GRAVE(levl
[u
.ux
][u
.uy
].typ
))
899 "are not going to get anywhere trying to write in the %s with your dust.",
900 is_ice(u
.ux
, u
.uy
) ? "frost" : "dust");
902 otmp
= 0; /* wand is now gone */
905 /* Early exit for some implements. */
907 if (otmp
&& otmp
->oclass
== WAND_CLASS
&& !can_reach_floor(TRUE
))
908 cant_reach_floor(u
.ux
, u
.uy
, FALSE
, TRUE
);
912 * Special effects should have deleted the current engraving (if
916 register char c
= 'n';
918 /* Give player the choice to add to engraving. */
919 if (type
== HEADSTONE
) {
920 /* no choice, only append */
922 } else if (type
== oep
->engr_type
923 && (!Blind
|| oep
->engr_type
== BURN
924 || oep
->engr_type
== ENGRAVE
)) {
925 c
= yn_function("Do you want to add to the current engraving?",
933 if (c
== 'n' || Blind
) {
934 if (oep
->engr_type
== DUST
935 || oep
->engr_type
== ENGR_BLOOD
936 || oep
->engr_type
== MARK
) {
938 You("wipe out the message that was %s here.",
939 (oep
->engr_type
== DUST
)
940 ? "written in the dust"
941 : (oep
->engr_type
== ENGR_BLOOD
)
942 ? "scrawled in blood"
945 oep
= (struct engr
*) 0;
947 /* Don't delete engr until after we *know* we're engraving
950 } else if (type
== DUST
|| type
== MARK
|| type
== ENGR_BLOOD
) {
951 You("cannot wipe out the message that is %s the %s here.",
952 oep
->engr_type
== BURN
953 ? (is_ice(u
.ux
, u
.uy
) ? "melted into" : "burned into")
955 surface(u
.ux
, u
.uy
));
957 } else if (type
!= oep
->engr_type
|| c
== 'n') {
958 if (!Blind
|| can_reach_floor(TRUE
))
959 You("will overwrite the current message.");
965 eloc
= surface(u
.ux
, u
.uy
);
968 everb
= (oep
&& !eow
? "add to the weird writing on"
969 : "write strangely on");
972 everb
= (oep
&& !eow
? "add to the writing in" : "write in");
973 eloc
= is_ice(u
.ux
, u
.uy
) ? "frost" : "dust";
976 everb
= (oep
&& !eow
? "add to the epitaph on" : "engrave on");
979 everb
= (oep
&& !eow
? "add to the engraving in" : "engrave in");
983 ? (is_ice(u
.ux
, u
.uy
) ? "add to the text melted into"
984 : "add to the text burned into")
985 : (is_ice(u
.ux
, u
.uy
) ? "melt into" : "burn into"));
988 everb
= (oep
&& !eow
? "add to the graffiti on" : "scribble on");
991 everb
= (oep
&& !eow
? "add to the scrawl on" : "scrawl on");
995 /* Tell adventurer what is going on */
996 if (otmp
!= &zeroobj
)
997 You("%s the %s with %s.", everb
, eloc
, doname(otmp
));
999 You("%s the %s with your %s.", everb
, eloc
, body_part(FINGERTIP
));
1001 /* Prompt for engraving! */
1002 Sprintf(qbuf
, "What do you want to %s the %s here?", everb
, eloc
);
1004 /* convert tabs to spaces and condense consecutive spaces to one */
1007 /* Count the actual # of chars engraved not including spaces */
1009 for (sp
= ebuf
; *sp
; sp
++)
1013 if (len
== 0 || index(ebuf
, '\033')) {
1016 pline("%s, then %s.", Tobjnam(otmp
, "glow"),
1017 otense(otmp
, "fade"));
1025 /* A single `x' is the traditional signature of an illiterate person */
1026 if (len
!= 1 || (!index(ebuf
, 'x') && !index(ebuf
, 'X')))
1027 u
.uconduct
.literate
++;
1029 /* Mix up engraving if surface or state of mind is unsound.
1030 Note: this won't add or remove any spaces. */
1031 for (sp
= ebuf
; *sp
; sp
++) {
1034 if (((type
== DUST
|| type
== ENGR_BLOOD
) && !rn2(25))
1035 || (Blind
&& !rn2(11)) || (Confusion
&& !rn2(7))
1036 || (Stunned
&& !rn2(4)) || (Hallucination
&& !rn2(2)))
1037 *sp
= ' ' + rnd(96 - 2); /* ASCII '!' thru '~'
1038 (excludes ' ' and DEL) */
1041 /* Previous engraving is overwritten */
1044 oep
= (struct engr
*) 0;
1047 /* Figure out how long it took to engrave, and if player has
1048 * engraved too much.
1052 multi
= -(len
/ 10);
1054 nomovemsg
= "You finish your weird engraving.";
1057 multi
= -(len
/ 10);
1059 nomovemsg
= "You finish writing in the dust.";
1063 multi
= -(len
/ 10);
1064 if (otmp
->oclass
== WEAPON_CLASS
1065 && (otmp
->otyp
!= ATHAME
|| otmp
->cursed
)) {
1067 maxelen
= ((otmp
->spe
+ 3) * 2) + 1;
1068 /* -2 => 3, -1 => 5, 0 => 7, +1 => 9, +2 => 11
1069 * Note: this does not allow a +0 anything (except an athame)
1070 * to engrave "Elbereth" all at once.
1071 * However, you can engrave "Elb", then "ere", then "th".
1073 pline("%s dull.", Yobjnam2(otmp
, "get"));
1074 costly_alteration(otmp
, COST_DEGRD
);
1075 if (len
> maxelen
) {
1079 otmp
->spe
-= len
>> 1;
1081 otmp
->spe
-= 1; /* Prevent infinite engraving */
1082 } else if (otmp
->oclass
== RING_CLASS
|| otmp
->oclass
== GEM_CLASS
) {
1086 nomovemsg
= "You finish engraving.";
1089 multi
= -(len
/ 10);
1091 nomovemsg
= is_ice(u
.ux
, u
.uy
)
1092 ? "You finish melting your message into the ice."
1093 : "You finish burning your message into the floor.";
1096 multi
= -(len
/ 10);
1097 if (otmp
->otyp
== MAGIC_MARKER
) {
1098 maxelen
= otmp
->spe
* 2; /* one charge / 2 letters */
1099 if (len
> maxelen
) {
1100 Your("marker dries out.");
1102 multi
= -(maxelen
/ 10);
1104 otmp
->spe
-= len
>> 1;
1106 otmp
->spe
-= 1; /* Prevent infinite graffiti */
1109 nomovemsg
= "You finish defacing the dungeon.";
1112 multi
= -(len
/ 10);
1114 nomovemsg
= "You finish scrawling.";
1118 /* Chop engraving down to size if necessary */
1119 if (len
> maxelen
) {
1120 for (sp
= ebuf
; maxelen
&& *sp
; sp
++)
1123 if (!maxelen
&& *sp
) {
1126 nomovemsg
= "You cannot write any more.";
1127 You("are only able to write \"%s\".", ebuf
);
1131 if (oep
) /* add to existing engraving */
1132 Strcpy(buf
, oep
->engr_txt
);
1133 (void) strncat(buf
, ebuf
, BUFSZ
- (int) strlen(buf
) - 1);
1134 /* Put the engraving onto the map */
1135 make_engr_at(u
.ux
, u
.uy
, buf
, moves
- multi
, type
);
1137 if (post_engr_text
[0])
1138 pline("%s", post_engr_text
);
1139 if (doblind
&& !resists_blnd(&youmonst
)) {
1140 You("are blinded by the flash!");
1141 make_blinded((long) rnd(50), FALSE
);
1143 Your1(vision_clears
);
1148 /* while loading bones, clean up text which might accidentally
1149 or maliciously disrupt player's terminal when displayed */
1151 sanitize_engravings()
1155 for (ep
= head_engr
; ep
; ep
= ep
->nxt_engr
) {
1156 sanitize_name(ep
->engr_txt
);
1161 save_engravings(fd
, mode
)
1164 struct engr
*ep
, *ep2
;
1165 unsigned no_more_engr
= 0;
1167 for (ep
= head_engr
; ep
; ep
= ep2
) {
1169 if (ep
->engr_lth
&& ep
->engr_txt
[0] && perform_bwrite(mode
)) {
1170 bwrite(fd
, (genericptr_t
) &ep
->engr_lth
, sizeof ep
->engr_lth
);
1171 bwrite(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + ep
->engr_lth
);
1173 if (release_data(mode
))
1176 if (perform_bwrite(mode
))
1177 bwrite(fd
, (genericptr_t
) &no_more_engr
, sizeof no_more_engr
);
1178 if (release_data(mode
))
1191 mread(fd
, (genericptr_t
) <h
, sizeof lth
);
1195 mread(fd
, (genericptr_t
) ep
, sizeof (struct engr
) + lth
);
1196 ep
->nxt_engr
= head_engr
;
1198 ep
->engr_txt
= (char *) (ep
+ 1); /* Andreas Bormann */
1199 /* Mark as finished for bones levels -- no problem for
1200 * normal levels as the player must have finished engraving
1201 * to be able to move again.
1203 ep
->engr_time
= moves
;
1207 /* to support '#stats' wizard-mode command */
1209 engr_stats(hdrfmt
, hdrbuf
, count
, size
)
1216 Sprintf(hdrbuf
, hdrfmt
, (long) sizeof (struct engr
));
1217 *count
= *size
= 0L;
1218 for (ep
= head_engr
; ep
; ep
= ep
->nxt_engr
) {
1220 *size
+= (long) sizeof *ep
+ (long) ep
->engr_lth
;
1226 register struct engr
*ep
;
1228 if (ep
== head_engr
) {
1229 head_engr
= ep
->nxt_engr
;
1231 register struct engr
*ept
;
1233 for (ept
= head_engr
; ept
; ept
= ept
->nxt_engr
)
1234 if (ept
->nxt_engr
== ep
) {
1235 ept
->nxt_engr
= ep
->nxt_engr
;
1239 impossible("Error in del_engr?");
1246 /* randomly relocate an engraving */
1251 int tx
, ty
, tryct
= 200;
1256 tx
= rn1(COLNO
- 3, 2);
1258 } while (engr_at(tx
, ty
) || !goodpos(tx
, ty
, (struct monst
*) 0, 0));
1264 /* Create a headstone at the given location.
1265 * The caller is responsible for newsym(x, y).
1268 make_grave(x
, y
, str
)
1274 /* Can we put a grave here? */
1275 if ((levl
[x
][y
].typ
!= ROOM
&& levl
[x
][y
].typ
!= GRAVE
) || t_at(x
, y
))
1277 /* Make the grave */
1278 levl
[x
][y
].typ
= GRAVE
;
1279 /* Engrave the headstone */
1282 str
= get_rnd_text(EPITAPHFILE
, buf
);
1283 make_engr_at(x
, y
, str
, 0L, HEADSTONE
);