1 /* SCCS Id: @(#)engrave.c 3.4 2001/11/04 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
9 STATIC_VAR NEARDATA struct engr *head_engr;
12 /* random engravings */
13 static const char *random_mesg[] = {
16 "Vlad was here", "ad aerarium",
17 /* take-offs and other famous engravings */
18 "Owlbreath", "Galadriel",
20 "A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */
21 "You won't get it up the steps", /* Adventure */
22 "Lasciate ogni speranza o voi ch'entrate.", /* Inferno */
23 "Well Come", /* Prisoner */
24 "We apologize for the inconvenience.", /* So Long... */
25 "See you next Wednesday", /* Thriller */
26 "notary sojak", /* Smokey Stover */
27 "For a good time call 8?7-5309",
28 "Please don't feed the animals.", /* Various zoos around the world */
29 "Madam, in Eden, I'm Adam.", /* A palindrome */
30 "Two thumbs up!", /* Siskel & Ebert */
31 "Hello, World!", /* The First C Program */
33 "You've got mail!", /* AOL */
35 "As if!", /* Clueless */
39 random_engraving(outbuf)
44 /* a random engraving may come from the "rumors" file,
45 or from the list above */
46 if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor)
47 Strcpy(outbuf, random_mesg[rn2(SIZE(random_mesg))]);
49 wipeout_text(outbuf, (int)(strlen(outbuf) / 4), 0);
53 /* Partial rubouts for engraving characters. -3. */
58 {'A', "^"}, {'B', "Pb["}, {'C', "("}, {'D', "|)["},
59 {'E', "|FL[_"}, {'F', "|-"}, {'G', "C("}, {'H', "|-"},
60 {'I', "|"}, {'K', "|<"}, {'L', "|_"}, {'M', "|"},
61 {'N', "|\\"}, {'O', "C("}, {'P', "F"}, {'Q', "C("},
62 {'R', "PF"}, {'T', "|"}, {'U', "J"}, {'V', "/\\"},
63 {'W', "V/\\"}, {'Z', "/"},
64 {'b', "|"}, {'d', "c|"}, {'e', "c"}, {'g', "c"},
65 {'h', "n"}, {'j', "i"}, {'k', "|"}, {'l', "|"},
66 {'m', "nr"}, {'n', "r"}, {'o', "c"}, {'q', "c"},
67 {'w', "v"}, {'y', "v"},
68 {':', "."}, {';', ","},
69 {'0', "C("}, {'1', "|"}, {'6', "o"}, {'7', "/"},
74 wipeout_text(engr, cnt, seed)
77 unsigned seed; /* for semi-controlled randomization */
80 int i, j, nxt, use_rubout, lth = (int)strlen(engr);
84 /* pick next character */
90 /* predictable; caller can reproduce the same sequence by
91 supplying the same arguments later, or a pseudo-random
92 sequence by varying any of them */
94 seed *= 31, seed %= (BUFSZ-1);
95 use_rubout = seed & 3;
98 if (*s == ' ') continue;
100 /* rub out unreadable & small punctuation marks */
101 if (index("?.,'`-|_", *s)) {
109 for (i = 0; i < SIZE(rubouts); i++)
110 if (*s == rubouts[i].wipefrom) {
112 * Pick one of the substitutes at random.
115 j = rn2(strlen(rubouts[i].wipeto));
117 seed *= 31, seed %= (BUFSZ-1);
118 j = seed % (strlen(rubouts[i].wipeto));
120 *s = rubouts[i].wipeto[j];
124 /* didn't pick rubout; use '?' for unreadable character */
125 if (i == SIZE(rubouts)) *s = '?';
129 /* trim trailing spaces */
130 while (lth && engr[lth-1] == ' ') engr[--lth] = 0;
136 return (boolean)(!u.uswallow &&
138 /* Restricted/unskilled riders can't reach the floor */
139 !(u.usteed && P_SKILL(P_RIDING) < P_BASIC) &&
142 Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)));
151 register struct rm *lev = &levl[x][y];
153 if ((x == u.ux) && (y == u.uy) && u.uswallow &&
154 is_animal(u.ustuck->data))
156 else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
158 else if (is_pool(x,y))
159 return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
160 else if (is_ice(x,y))
162 else if (is_lava(x,y))
164 else if (lev->typ == DRAWBRIDGE_DOWN)
166 else if(IS_ALTAR(levl[x][y].typ))
168 else if(IS_GRAVE(levl[x][y].typ))
170 else if(IS_FOUNTAIN(levl[x][y].typ))
172 else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
173 IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
183 register struct rm *lev = &levl[x][y];
186 /* other room types will no longer exist when we're interested --
187 * see check_special_room()
189 if (*in_rooms(x,y,VAULT))
190 what = "vault's ceiling";
191 else if (*in_rooms(x,y,TEMPLE))
192 what = "temple's ceiling";
193 else if (*in_rooms(x,y,SHOPBASE))
194 what = "shop's ceiling";
195 else if (IS_AIR(lev->typ))
198 what = "water's surface";
199 else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
200 IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
212 register struct engr *ep = head_engr;
215 if(x == ep->engr_x && y == ep->engr_y)
219 return((struct engr *) 0);
223 /* Decide whether a particular string is engraved at a specified
224 * location; a case-insensitive substring match used.
225 * Ignore headstones, in case the player names herself "Elbereth".
232 register struct engr *ep = engr_at(x,y);
234 return (ep && ep->engr_type != HEADSTONE &&
235 ep->engr_time <= moves && strstri(ep->engr_txt, s) != 0);
237 #endif /* ELBERETH */
246 if (can_reach_floor())
247 wipe_engr_at(u.ux, u.uy, cnt);
254 wipe_engr_at(x,y,cnt)
255 register xchar x,y,cnt;
257 register struct engr *ep = engr_at(x,y);
259 /* Headstones are indelible */
260 if(ep && ep->engr_type != HEADSTONE){
261 if(ep->engr_type != BURN || is_ice(x,y)) {
262 if(ep->engr_type != DUST && ep->engr_type != ENGR_BLOOD) {
263 cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
265 wipeout_text(ep->engr_txt, (int)cnt, 0);
266 while(ep->engr_txt[0] == ' ')
268 if(!ep->engr_txt[0]) del_engr(ep);
280 register struct engr *ep = engr_at(x,y);
281 register int sensed = 0;
284 /* Sensing an engraving does not require sight,
285 * nor does it necessarily imply comprehension (literacy).
287 if(ep && ep->engr_txt[0]) {
288 switch(ep->engr_type) {
292 pline("%s is written here in the %s.", Something,
293 is_ice(x,y) ? "frost" : "dust");
298 if (!Blind || can_reach_floor()) {
300 pline("%s is engraved here on the %s.",
306 if (!Blind || can_reach_floor()) {
308 pline("Some text has been %s into the %s here.",
309 is_ice(x,y) ? "melted" : "burned",
316 pline("There's some graffiti on the %s here.",
321 /* "It's a message! Scrawled in blood!"
323 * "It says... `See you next Wednesday.'" -- Thriller
327 You("see a message scrawled in blood here.");
331 impossible("%s is written in a very strange way.",
337 unsigned maxelen = BUFSZ - sizeof("You feel the words: \"\". ");
338 if (strlen(ep->engr_txt) > maxelen) {
339 (void) strncpy(buf, ep->engr_txt, (int)maxelen);
345 (Blind) ? "feel the words" : "read", et);
346 if(flags.run > 1) nomul(0);
355 make_engr_at(x,y,s,e_time,e_type)
357 register const char *s;
358 register long e_time;
359 register xchar e_type;
361 register struct engr *ep;
363 if ((ep = engr_at(x,y)) != 0)
365 ep = newengr(strlen(s) + 1);
366 ep->nxt_engr = head_engr;
370 ep->engr_txt = (char *)(ep + 1);
371 Strcpy(ep->engr_txt, s);
372 /* engraving Elbereth shows wisdom */
373 if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
374 ep->engr_time = e_time;
375 ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1);
376 ep->engr_lth = strlen(s) + 1;
379 /* delete any engraving at location <x,y> */
384 register struct engr *ep = engr_at(x, y);
386 if (ep) del_engr(ep);
390 * freehand - returns true if player has a free hand
395 return(!uwep || !welded(uwep) ||
396 (!bimanual(uwep) && (!uarms || !uarms->cursed)));
397 /* if ((uwep && bimanual(uwep)) ||
404 static NEARDATA const char styluses[] =
405 { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
406 GEM_CLASS, RING_CLASS, 0 };
408 /* Mohs' Hardness Scale:
409 * 1 - Talc 6 - Orthoclase
410 * 2 - Gypsum 7 - Quartz
411 * 3 - Calcite 8 - Topaz
412 * 4 - Fluorite 9 - Corundum
413 * 5 - Apatite 10 - Diamond
415 * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
416 * probably be able to scratch the rock.
417 * Devaluation of less hard gems is not easily possible because obj struct
418 * does not contain individual oc_cost currently. 7/91
420 * steel - 5-8.5 (usu. weapon)
421 * diamond - 10 * jade - 5-6 (nephrite)
422 * ruby - 9 (corundum) * turquoise - 5-6
423 * sapphire - 9 (corundum) * opal - 5-6
424 * topaz - 8 * glass - ~5.5
425 * emerald - 7.5-8 (beryl) * dilithium - 4-5??
426 * aquamarine - 7.5-8 (beryl) * iron - 4-5
427 * garnet - 7.25 (var. 6.5-8) * fluorite - 4
428 * agate - 7 (quartz) * brass - 3-4
429 * amethyst - 7 (quartz) * gold - 2.5-3
430 * jasper - 7 (quartz) * silver - 2.5-3
431 * onyx - 7 (quartz) * copper - 2.5-3
432 * moonstone - 6 (orthoclase) * amber - 2-2.5
435 /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
439 boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */
440 boolean doblind = FALSE;/* TRUE if engraving blinds the player */
441 boolean doknown = FALSE;/* TRUE if we identify the stylus */
442 boolean eow = FALSE; /* TRUE if we are overwriting oep */
443 boolean jello = FALSE; /* TRUE if we are engraving in slime */
444 boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */
445 boolean teleengr =FALSE;/* TRUE if we move the old engraving */
446 boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
447 xchar type = DUST; /* Type of engraving made */
448 char buf[BUFSZ]; /* Buffer for final/poly engraving text */
449 char ebuf[BUFSZ]; /* Buffer for initial engraving text */
450 char qbuf[QBUFSZ]; /* Buffer for query text */
451 char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */
452 const char *everb; /* Present tense of engraving type */
453 const char *eloc; /* Where the engraving is (ie dust/floor/...) */
454 char *sp; /* Place holder for space count of engr text */
455 int len; /* # of nonspace chars of new engraving text */
456 int maxelen; /* Max allowable length of engraving text */
457 struct engr *oep = engr_at(u.ux,u.uy);
458 /* The current engraving */
459 struct obj *otmp; /* Object selected with which to engrave */
462 multi = 0; /* moves consumed */
463 nomovemsg = (char *)0; /* occupation end message */
467 post_engr_text[0] = (char)0;
469 if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
472 /* Can the adventurer engrave at all? */
475 if (is_animal(u.ustuck->data)) {
476 pline("What would you write? \"Jonah was here\"?");
478 } else if (is_whirly(u.ustuck->data)) {
479 You_cant("reach the %s.", surface(u.ux,u.uy));
483 } else if (is_lava(u.ux, u.uy)) {
484 You_cant("write on the lava!");
486 } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
487 You_cant("write on the water!");
490 if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
491 You_cant("write in thin air!");
494 if (cantwield(youmonst.data)) {
495 You_cant("even hold anything!");
498 if (check_capacity((char *)0)) return (0);
500 /* One may write with finger, or weapon, or wand, or..., or...
501 * Edited by GAN 10/20/86 so as not to change weapon wielded.
504 otmp = getobj(styluses, "write with");
505 if(!otmp) return(0); /* otmp == zeroobj if fingers */
507 if (otmp == &zeroobj) writer = makeplural(body_part(FINGER));
508 else writer = xname(otmp);
510 /* There's no reason you should be able to write with a wand
511 * while both your hands are tied up.
513 if (!freehand() && otmp != uwep && !otmp->owornmask) {
514 You("have no free %s to write with!", body_part(HAND));
519 You("tickle %s with your %s.", mon_nam(u.ustuck), writer);
520 Your("message dissolves...");
523 if (otmp->oclass != WAND_CLASS && !can_reach_floor()) {
524 You_cant("reach the %s!", surface(u.ux,u.uy));
527 if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
528 You("make a motion towards the altar with your %s.", writer);
529 altar_wrath(u.ux, u.uy);
532 if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
533 if (otmp == &zeroobj) { /* using only finger */
534 You("would only make a small smudge on the %s.",
535 surface(u.ux, u.uy));
537 } else if (!levl[u.ux][u.uy].disturbed) {
538 You("disturb the undead!");
539 levl[u.ux][u.uy].disturbed = 1;
540 (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
541 exercise(A_WIS, FALSE);
548 switch (otmp->oclass) {
557 /* "diamond" rings and others should work */
559 /* diamonds & other hard gems should work */
560 if (objects[otmp->otyp].oc_tough) {
567 if (is_boots(otmp)) {
572 /* Objects too large to engrave with */
575 You_cant("engrave with such a large object!");
579 /* Objects too silly to engrave with */
583 Your("%s would get %s.", xname(otmp),
584 is_ice(u.ux,u.uy) ? "all frosty" : "too dirty");
588 case RANDOM_CLASS: /* This should mean fingers */
591 /* The charge is removed from the wand before prompting for
592 * the engraving text, because all kinds of setup decisions
593 * and pre-engraving messages are based upon knowing what type
594 * of engraving the wand is going to do. Also, the player
595 * will have potentially seen "You wrest .." message, and
596 * therefore will know they are using a charge.
599 if (zappable(otmp)) {
602 if (Levitation) ptext = FALSE;
604 switch (otmp->otyp) {
611 case WAN_SECRET_DOOR_DETECTION:
612 case WAN_CREATE_MONSTER:
614 case WAN_ENLIGHTENMENT:
618 /* IMMEDIATE wands */
619 /* If wand is "IMMEDIATE", remember to affect the
620 * previous engraving even if turning to dust.
623 Strcpy(post_engr_text,
624 "The wand unsuccessfully fights your attempt to write!"
627 case WAN_SLOW_MONSTER:
629 Sprintf(post_engr_text,
630 "The bugs on the %s slow down!",
631 surface(u.ux, u.uy));
634 case WAN_SPEED_MONSTER:
636 Sprintf(post_engr_text,
637 "The bugs on the %s speed up!",
638 surface(u.ux, u.uy));
644 type = (xchar)0; /* random */
645 (void) random_engraving(buf);
651 case WAN_UNDEAD_TURNING:
658 case WAN_MAGIC_MISSILE:
661 Sprintf(post_engr_text,
662 "The %s is riddled by bullet holes!",
663 surface(u.ux, u.uy));
667 /* can't tell sleep from death - Eric Backus */
671 Sprintf(post_engr_text,
672 "The bugs on the %s stop moving!",
673 surface(u.ux, u.uy));
679 Strcpy(post_engr_text,
680 "A few ice cubes drop from the wand.");
681 if(!oep || (oep->engr_type != BURN))
683 case WAN_CANCELLATION:
684 case WAN_MAKE_INVISIBLE:
685 if (oep && oep->engr_type != HEADSTONE) {
687 pline_The("engraving on the %s vanishes!",
692 case WAN_TELEPORTATION:
693 if (oep && oep->engr_type != HEADSTONE) {
695 pline_The("engraving on the %s vanishes!",
701 /* type = ENGRAVE wands */
705 if(!objects[otmp->otyp].oc_name_known) {
707 pline("This %s is a wand of digging!",
712 Strcpy(post_engr_text,
713 IS_GRAVE(levl[u.ux][u.uy].typ) ?
714 "Chips fly out from the headstone." :
716 "Ice chips fly up from the ice surface!" :
717 "Gravel flies up from the floor.");
719 Strcpy(post_engr_text, "You hear drilling!");
722 /* type = BURN wands */
726 if(!objects[otmp->otyp].oc_name_known) {
728 pline("This %s is a wand of fire!", xname(otmp));
731 Strcpy(post_engr_text,
732 Blind ? "You feel the wand heat up." :
733 "Flames fly from the wand.");
738 if(!objects[otmp->otyp].oc_name_known) {
740 pline("This %s is a wand of lightning!",
745 Strcpy(post_engr_text,
746 "Lightning arcs from the wand.");
749 Strcpy(post_engr_text, "You hear crackling!");
752 /* type = MARK wands */
753 /* type = ENGR_BLOOD wands */
755 } else /* end if zappable */
756 if (!can_reach_floor()) {
757 You_cant("reach the %s!", surface(u.ux,u.uy));
763 if (is_blade(otmp)) {
764 if ((int)otmp->spe > -3)
767 Your("%s too dull for engraving.", aobjnam(otmp,"are"));
772 if(otmp == ublindf) {
774 "That is a bit difficult to engrave with, don't you think?");
777 switch (otmp->otyp) {
780 Your("marker has dried out.");
785 /* Can't really engrave with a towel */
788 if ((oep->engr_type == DUST ) ||
789 (oep->engr_type == ENGR_BLOOD) ||
790 (oep->engr_type == MARK )) {
792 You("wipe out the message here.");
794 Your("%s %s %s.", xname(otmp),
800 Your("%s can't wipe out this engraving.",
803 Your("%s %s %s.", xname(otmp), otense(otmp, "get"),
804 is_ice(u.ux,u.uy) ? "frosty" : "dusty");
814 pline("Writing a poison pen letter??");
819 impossible("You're engraving with an illegal object!");
823 if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
824 if (type == ENGRAVE || type == 0)
827 /* ensures the "cannot wipe out" case */
835 /* End of implement setup */
837 /* Identify stylus */
839 makeknown(otmp->otyp);
840 more_experienced(0,10);
845 oep = (struct engr *)0;
850 oep = (struct engr *)0;
853 /* Something has changed the engraving here */
855 make_engr_at(u.ux, u.uy, buf, moves, type);
856 pline_The("engraving now reads: \"%s\".", buf);
860 if (zapwand && (otmp->spe < 0)) {
861 pline("%s %sturns to dust.",
862 The(xname(otmp)), Blind ? "" : "glows violently, then ");
863 if (!IS_GRAVE(levl[u.ux][u.uy].typ))
864 You("are not going to get anywhere trying to write in the %s with your dust.",
865 is_ice(u.ux,u.uy) ? "frost" : "dust");
870 if (!ptext) { /* Early exit for some implements. */
871 if (otmp->oclass == WAND_CLASS && !can_reach_floor())
872 You_cant("reach the %s!", surface(u.ux,u.uy));
876 /* Special effects should have deleted the current engraving (if
881 register char c = 'n';
883 /* Give player the choice to add to engraving. */
885 if (type == HEADSTONE) {
886 /* no choice, only append */
888 } else if ( (type == oep->engr_type) && (!Blind ||
889 (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) {
890 c = yn_function("Do you want to add to the current engraving?",
898 if (c == 'n' || Blind) {
900 if( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) ||
901 (oep->engr_type == MARK) ) {
903 You("wipe out the message that was %s here.",
904 ((oep->engr_type == DUST) ? "written in the dust" :
905 ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood" :
908 oep = (struct engr *)0;
910 /* Don't delete engr until after we *know* we're engraving */
913 if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) {
915 "cannot wipe out the message that is %s the %s here.",
916 oep->engr_type == BURN ?
917 (is_ice(u.ux,u.uy) ? "melted into" : "burned into") :
918 "engraved in", surface(u.ux,u.uy));
921 if ( (type != oep->engr_type) || (c == 'n') ) {
922 if (!Blind || can_reach_floor())
923 You("will overwrite the current message.");
929 eloc = surface(u.ux,u.uy);
932 everb = (oep && !eow ? "add to the weird writing on" :
933 "write strangely on");
936 everb = (oep && !eow ? "add to the writing in" :
938 eloc = is_ice(u.ux,u.uy) ? "frost" : "dust";
941 everb = (oep && !eow ? "add to the epitaph on" :
945 everb = (oep && !eow ? "add to the engraving in" :
949 everb = (oep && !eow ?
950 ( is_ice(u.ux,u.uy) ? "add to the text melted into" :
951 "add to the text burned into") :
952 ( is_ice(u.ux,u.uy) ? "melt into" : "burn into"));
955 everb = (oep && !eow ? "add to the graffiti on" :
959 everb = (oep && !eow ? "add to the scrawl on" :
964 /* Tell adventurer what is going on */
965 if (otmp != &zeroobj)
966 You("%s the %s with %s.", everb, eloc, doname(otmp));
968 You("%s the %s with your %s.", everb, eloc,
969 makeplural(body_part(FINGER)));
971 /* Prompt for engraving! */
972 Sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc);
975 /* Count the actual # of chars engraved not including spaces */
977 for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1;
979 if (len == 0 || index(ebuf, '\033')) {
982 pline("%s, then %s.",
983 Tobjnam(otmp, "glow"), otense(otmp, "fade"));
991 /* A single `x' is the traditional signature of an illiterate person */
992 if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X')))
993 u.uconduct.literate++;
995 /* Mix up engraving if surface or state of mind is unsound.
996 Note: this won't add or remove any spaces. */
997 for (sp = ebuf; *sp; sp++) {
998 if (isspace(*sp)) continue;
999 if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) ||
1000 (Blind && !rn2(11)) || (Confusion && !rn2(7)) ||
1001 (Stunned && !rn2(4)) || (Hallucination && !rn2(2)))
1002 *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~'
1003 (excludes ' ' and DEL) */
1006 /* Previous engraving is overwritten */
1009 oep = (struct engr *)0;
1012 /* Figure out how long it took to engrave, and if player has
1013 * engraved too much.
1018 if (multi) nomovemsg = "You finish your weird engraving.";
1022 if (multi) nomovemsg = "You finish writing in the dust.";
1027 if ((otmp->oclass == WEAPON_CLASS) &&
1028 ((otmp->otyp != ATHAME) || otmp->cursed)) {
1030 maxelen = ((otmp->spe + 3) * 2) + 1;
1031 /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11
1032 * Note: this does not allow a +0 anything (except
1033 * an athame) to engrave "Elbereth" all at once.
1034 * However, you could now engrave "Elb", then
1037 Your("%s dull.", aobjnam(otmp, "get"));
1039 struct monst *shkp = shop_keeper(*u.ushops);
1041 You("damage it, you pay for it!");
1042 bill_dummy_object(otmp);
1045 if (len > maxelen) {
1049 otmp->spe -= len >> 1;
1050 else otmp->spe -= 1; /* Prevent infinite engraving */
1052 if ( (otmp->oclass == RING_CLASS) ||
1053 (otmp->oclass == GEM_CLASS) )
1055 if (multi) nomovemsg = "You finish engraving.";
1060 nomovemsg = is_ice(u.ux,u.uy) ?
1061 "You finish melting your message into the ice.":
1062 "You finish burning your message into the floor.";
1066 if ((otmp->oclass == TOOL_CLASS) &&
1067 (otmp->otyp == MAGIC_MARKER)) {
1068 maxelen = (otmp->spe) * 2; /* one charge / 2 letters */
1069 if (len > maxelen) {
1070 Your("marker dries out.");
1072 multi = -(maxelen/10);
1074 if (len > 1) otmp->spe -= len >> 1;
1075 else otmp->spe -= 1; /* Prevent infinite grafitti */
1077 if (multi) nomovemsg = "You finish defacing the dungeon.";
1081 if (multi) nomovemsg = "You finish scrawling.";
1085 /* Chop engraving down to size if necessary */
1086 if (len > maxelen) {
1087 for (sp = ebuf; (maxelen && *sp); sp++)
1088 if (!isspace(*sp)) maxelen--;
1089 if (!maxelen && *sp) {
1091 if (multi) nomovemsg = "You cannot write any more.";
1092 You("only are able to write \"%s\"", ebuf);
1096 /* Add to existing engraving */
1097 if (oep) Strcpy(buf, oep->engr_txt);
1099 (void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
1101 make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
1103 if (post_engr_text[0]) pline(post_engr_text);
1105 if (doblind && !resists_blnd(&youmonst)) {
1106 You("are blinded by the flash!");
1107 make_blinded((long)rnd(50),FALSE);
1108 if (!Blind) Your(vision_clears);
1115 save_engravings(fd, mode)
1118 register struct engr *ep = head_engr;
1119 register struct engr *ep2;
1120 unsigned no_more_engr = 0;
1124 if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) {
1125 bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
1126 bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
1128 if (release_data(mode))
1132 if (perform_bwrite(mode))
1133 bwrite(fd, (genericptr_t)&no_more_engr, sizeof no_more_engr);
1134 if (release_data(mode))
1142 register struct engr *ep;
1147 mread(fd, (genericptr_t) <h, sizeof(unsigned));
1148 if(lth == 0) return;
1150 mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
1151 ep->nxt_engr = head_engr;
1153 ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */
1154 /* mark as finished for bones levels -- no problem for
1155 * normal levels as the player must have finished engraving
1156 * to be able to move again */
1157 ep->engr_time = moves;
1163 register struct engr *ep;
1165 if (ep == head_engr) {
1166 head_engr = ep->nxt_engr;
1168 register struct engr *ept;
1170 for (ept = head_engr; ept; ept = ept->nxt_engr)
1171 if (ept->nxt_engr == ep) {
1172 ept->nxt_engr = ep->nxt_engr;
1176 impossible("Error in del_engr?");
1183 /* randomly relocate an engraving */
1188 int tx, ty, tryct = 200;
1191 if (--tryct < 0) return;
1192 tx = rn1(COLNO-3,2);
1194 } while (engr_at(tx, ty) ||
1195 !goodpos(tx, ty, (struct monst *)0, 0));
1202 /* Epitaphs for random headstones */
1203 static const char *epitaphs[] = {
1207 "Note -- there are NO valuable items in this grave",
1208 "1994-1995. The Longest-Lived Hacker Ever",
1209 "The Grave of the Unknown Hacker",
1210 "We weren't sure who this was, but we buried him here anyway",
1211 "Sparky -- he was a very good dog",
1212 "Beware of Electric Third Rail",
1214 "Og friend. Og good dude. Og died. Og now food",
1215 "Beetlejuice Beetlejuice Beetlejuice",
1217 "Please don't dig me up. I'm perfectly happy down here. -- Resident",
1218 "Postman, please note forwarding address: Gehennom, Asmodeus's Fortress, fifth lemure on the left",
1219 "Mary had a little lamb/Its fleece was white as snow/When Mary was in trouble/The lamb was first to go",
1220 "Be careful, or this could happen to you!",
1221 "Soon you'll join this fellow in hell! -- the Wizard of Yendor",
1222 "Caution! This grave contains toxic waste",
1224 "Here lies an Atheist, all dressed up and no place to go",
1225 "Here lies Ezekiel, age 102. The good die young.",
1226 "Here lies my wife: Here let her lie! Now she's at rest and so am I.",
1227 "Here lies Johnny Yeast. Pardon me for not rising.",
1228 "He always lied while on the earth and now he's lying in it",
1229 "I made an ash of myself",
1230 "Soon ripe. Soon rotten. Soon gone. But not forgotten.",
1231 "Here lies the body of Jonathan Blake. Stepped on the gas instead of the brake.",
1235 /* Create a headstone at the given location.
1236 * The caller is responsible for newsym(x, y).
1239 make_grave(x, y, str)
1243 /* Can we put a grave here? */
1244 if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x,y)) return;
1246 /* Make the grave */
1247 levl[x][y].typ = GRAVE;
1249 /* Engrave the headstone */
1250 if (!str) str = epitaphs[rn2(SIZE(epitaphs))];
1252 make_engr_at(x, y, str, 0L, HEADSTONE);