OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / engrave.c
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. */
4
5 #include "hack.h"
6 #include "lev.h"
7 #include <ctype.h>
8
9 STATIC_VAR NEARDATA struct engr *head_engr;
10
11 #ifdef OVLB
12 /* random engravings */
13 static const char *random_mesg[] = {
14         "Elbereth",
15         /* trap engravings */
16         "Vlad was here", "ad aerarium",
17         /* take-offs and other famous engravings */
18         "Owlbreath", "Galadriel",
19         "Kilroy was here",
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 */
32 #ifdef MAIL
33         "You've got mail!", /* AOL */
34 #endif
35         "As if!", /* Clueless */
36 };
37
38 char *
39 random_engraving(outbuf)
40 char *outbuf;
41 {
42         const char *rumor;
43
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))]);
48
49         wipeout_text(outbuf, (int)(strlen(outbuf) / 4), 0);
50         return outbuf;
51 }
52
53 /* Partial rubouts for engraving characters. -3. */
54 static const struct {
55         char            wipefrom;
56         const char *    wipeto;
57 } rubouts[] = {
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', "/"},
70         {'8', "3o"}
71 };
72
73 void
74 wipeout_text(engr, cnt, seed)
75 char *engr;
76 int cnt;
77 unsigned seed;          /* for semi-controlled randomization */
78 {
79         char *s;
80         int i, j, nxt, use_rubout, lth = (int)strlen(engr);
81
82         if (lth && cnt > 0) {
83             while (cnt--) {
84                 /* pick next character */
85                 if (!seed) {
86                     /* random */
87                     nxt = rn2(lth);
88                     use_rubout = rn2(4);
89                 } else {
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 */
93                     nxt = seed % lth;
94                     seed *= 31,  seed %= (BUFSZ-1);
95                     use_rubout = seed & 3;
96                 }
97                 s = &engr[nxt];
98                 if (*s == ' ') continue;
99
100                 /* rub out unreadable & small punctuation marks */
101                 if (index("?.,'`-|_", *s)) {
102                     *s = ' ';
103                     continue;
104                 }
105
106                 if (!use_rubout)
107                     i = SIZE(rubouts);
108                 else
109                     for (i = 0; i < SIZE(rubouts); i++)
110                         if (*s == rubouts[i].wipefrom) {
111                             /*
112                              * Pick one of the substitutes at random.
113                              */
114                             if (!seed)
115                                 j = rn2(strlen(rubouts[i].wipeto));
116                             else {
117                                 seed *= 31,  seed %= (BUFSZ-1);
118                                 j = seed % (strlen(rubouts[i].wipeto));
119                             }
120                             *s = rubouts[i].wipeto[j];
121                             break;
122                         }
123
124                 /* didn't pick rubout; use '?' for unreadable character */
125                 if (i == SIZE(rubouts)) *s = '?';
126             }
127         }
128
129         /* trim trailing spaces */
130         while (lth && engr[lth-1] == ' ') engr[--lth] = 0;
131 }
132
133 boolean
134 can_reach_floor()
135 {
136         return (boolean)(!u.uswallow &&
137 #ifdef STEED
138                         /* Restricted/unskilled riders can't reach the floor */
139                         !(u.usteed && P_SKILL(P_RIDING) < P_BASIC) &&
140 #endif
141                          (!Levitation ||
142                           Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)));
143 }
144 #endif /* OVLB */
145 #ifdef OVL0
146
147 const char *
148 surface(x, y)
149 register int x, y;
150 {
151         register struct rm *lev = &levl[x][y];
152
153         if ((x == u.ux) && (y == u.uy) && u.uswallow &&
154                 is_animal(u.ustuck->data))
155             return "maw";
156         else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
157             return "air";
158         else if (is_pool(x,y))
159             return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
160         else if (is_ice(x,y))
161             return "ice";
162         else if (is_lava(x,y))
163             return "lava";
164         else if (lev->typ == DRAWBRIDGE_DOWN)
165             return "bridge";
166         else if(IS_ALTAR(levl[x][y].typ))
167             return "altar";
168         else if(IS_GRAVE(levl[x][y].typ))
169             return "headstone";
170         else if(IS_FOUNTAIN(levl[x][y].typ))
171             return "fountain";
172         else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) ||
173                  IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR)
174             return "floor";
175         else
176             return "ground";
177 }
178
179 const char *
180 ceiling(x, y)
181 register int x, y;
182 {
183         register struct rm *lev = &levl[x][y];
184         const char *what;
185
186         /* other room types will no longer exist when we're interested --
187          * see check_special_room()
188          */
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))
196             what = "sky";
197         else if (Underwater)
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)
201             what = "ceiling";
202         else
203             what = "rock above";
204
205         return what;
206 }
207
208 struct engr *
209 engr_at(x, y)
210 xchar x, y;
211 {
212         register struct engr *ep = head_engr;
213
214         while(ep) {
215                 if(x == ep->engr_x && y == ep->engr_y)
216                         return(ep);
217                 ep = ep->nxt_engr;
218         }
219         return((struct engr *) 0);
220 }
221
222 #ifdef ELBERETH
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".
226  */
227 int
228 sengr_at(s, x, y)
229         const char *s;
230         xchar x, y;
231 {
232         register struct engr *ep = engr_at(x,y);
233
234         return (ep && ep->engr_type != HEADSTONE &&
235                 ep->engr_time <= moves && strstri(ep->engr_txt, s) != 0);
236 }
237 #endif /* ELBERETH */
238
239 #endif /* OVL0 */
240 #ifdef OVL2
241
242 void
243 u_wipe_engr(cnt)
244 register int cnt;
245 {
246         if (can_reach_floor())
247                 wipe_engr_at(u.ux, u.uy, cnt);
248 }
249
250 #endif /* OVL2 */
251 #ifdef OVL1
252
253 void
254 wipe_engr_at(x,y,cnt)
255 register xchar x,y,cnt;
256 {
257         register struct engr *ep = engr_at(x,y);
258
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;
264                 }
265                 wipeout_text(ep->engr_txt, (int)cnt, 0);
266                 while(ep->engr_txt[0] == ' ')
267                         ep->engr_txt++;
268                 if(!ep->engr_txt[0]) del_engr(ep);
269             }
270         }
271 }
272
273 #endif /* OVL1 */
274 #ifdef OVL2
275
276 void
277 read_engr_at(x,y)
278 register int x,y;
279 {
280         register struct engr *ep = engr_at(x,y);
281         register int    sensed = 0;
282         char buf[BUFSZ];
283         
284         /* Sensing an engraving does not require sight,
285          * nor does it necessarily imply comprehension (literacy).
286          */
287         if(ep && ep->engr_txt[0]) {
288             switch(ep->engr_type) {
289             case DUST:
290                 if(!Blind) {
291                         sensed = 1;
292                         pline("%s is written here in the %s.", Something,
293                                 is_ice(x,y) ? "frost" : "dust");
294                 }
295                 break;
296             case ENGRAVE:
297             case HEADSTONE:
298                 if (!Blind || can_reach_floor()) {
299                         sensed = 1;
300                         pline("%s is engraved here on the %s.",
301                                 Something,
302                                 surface(x,y));
303                 }
304                 break;
305             case BURN:
306                 if (!Blind || can_reach_floor()) {
307                         sensed = 1;
308                         pline("Some text has been %s into the %s here.",
309                                 is_ice(x,y) ? "melted" : "burned",
310                                 surface(x,y));
311                 }
312                 break;
313             case MARK:
314                 if(!Blind) {
315                         sensed = 1;
316                         pline("There's some graffiti on the %s here.",
317                                 surface(x,y));
318                 }
319                 break;
320             case ENGR_BLOOD:
321                 /* "It's a message!  Scrawled in blood!"
322                  * "What's it say?"
323                  * "It says... `See you next Wednesday.'" -- Thriller
324                  */
325                 if(!Blind) {
326                         sensed = 1;
327                         You("see a message scrawled in blood here.");
328                 }
329                 break;
330             default:
331                 impossible("%s is written in a very strange way.",
332                                 Something);
333                 sensed = 1;
334             }
335             if (sensed) {
336                 char *et;
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);
340                         buf[maxelen] = '\0';
341                         et = buf;
342                 } else
343                         et = ep->engr_txt;
344                 You("%s: \"%s\".",
345                       (Blind) ? "feel the words" : "read",  et);
346                 if(flags.run > 1) nomul(0);
347             }
348         }
349 }
350
351 #endif /* OVL2 */
352 #ifdef OVLB
353
354 void
355 make_engr_at(x,y,s,e_time,e_type)
356 register int x,y;
357 register const char *s;
358 register long e_time;
359 register xchar e_type;
360 {
361         register struct engr *ep;
362
363         if ((ep = engr_at(x,y)) != 0)
364             del_engr(ep);
365         ep = newengr(strlen(s) + 1);
366         ep->nxt_engr = head_engr;
367         head_engr = ep;
368         ep->engr_x = x;
369         ep->engr_y = y;
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;
377 }
378
379 /* delete any engraving at location <x,y> */
380 void
381 del_engr_at(x, y)
382 int x, y;
383 {
384         register struct engr *ep = engr_at(x, y);
385
386         if (ep) del_engr(ep);
387 }
388
389 /*
390  *      freehand - returns true if player has a free hand
391  */
392 int
393 freehand()
394 {
395         return(!uwep || !welded(uwep) ||
396            (!bimanual(uwep) && (!uarms || !uarms->cursed)));
397 /*      if ((uwep && bimanual(uwep)) ||
398             (uwep && uarms))
399                 return(0);
400         else
401                 return(1);*/
402 }
403
404 static NEARDATA const char styluses[] =
405         { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
406           GEM_CLASS, RING_CLASS, 0 };
407
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
414  *
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
419  *
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
433  */
434
435 /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
436 int
437 doengrave()
438 {
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 */
460         char *writer;
461
462         multi = 0;              /* moves consumed */
463         nomovemsg = (char *)0;  /* occupation end message */
464
465         buf[0] = (char)0;
466         ebuf[0] = (char)0;
467         post_engr_text[0] = (char)0;
468         maxelen = BUFSZ - 1;
469         if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
470             type = ENGR_BLOOD;
471
472         /* Can the adventurer engrave at all? */
473
474         if(u.uswallow) {
475                 if (is_animal(u.ustuck->data)) {
476                         pline("What would you write?  \"Jonah was here\"?");
477                         return(0);
478                 } else if (is_whirly(u.ustuck->data)) {
479                         You_cant("reach the %s.", surface(u.ux,u.uy));
480                         return(0);
481                 } else
482                         jello = TRUE;
483         } else if (is_lava(u.ux, u.uy)) {
484                 You_cant("write on the lava!");
485                 return(0);
486         } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
487                 You_cant("write on the water!");
488                 return(0);
489         }
490         if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
491                 You_cant("write in thin air!");
492                 return(0);
493         }
494         if (cantwield(youmonst.data)) {
495                 You_cant("even hold anything!");
496                 return(0);
497         }
498         if (check_capacity((char *)0)) return (0);
499
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.
502          */
503
504         otmp = getobj(styluses, "write with");
505         if(!otmp) return(0);            /* otmp == zeroobj if fingers */
506
507         if (otmp == &zeroobj) writer = makeplural(body_part(FINGER));
508         else writer = xname(otmp);
509
510         /* There's no reason you should be able to write with a wand
511          * while both your hands are tied up.
512          */
513         if (!freehand() && otmp != uwep && !otmp->owornmask) {
514                 You("have no free %s to write with!", body_part(HAND));
515                 return(0);
516         }
517
518         if (jello) {
519                 You("tickle %s with your %s.", mon_nam(u.ustuck), writer);
520                 Your("message dissolves...");
521                 return(0);
522         }
523         if (otmp->oclass != WAND_CLASS && !can_reach_floor()) {
524                 You_cant("reach the %s!", surface(u.ux,u.uy));
525                 return(0);
526         }
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);
530                 return(0);
531         }
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));
536                 return(0);
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);
542                 return(1);
543             }
544         }
545
546         /* SPFX for items */
547
548         switch (otmp->oclass) {
549             default:
550             case AMULET_CLASS:
551             case CHAIN_CLASS:
552             case POTION_CLASS:
553             case COIN_CLASS:
554                 break;
555
556             case RING_CLASS:
557                 /* "diamond" rings and others should work */
558             case GEM_CLASS:
559                 /* diamonds & other hard gems should work */
560                 if (objects[otmp->otyp].oc_tough) {
561                         type = ENGRAVE;
562                         break;
563                 }
564                 break;
565
566             case ARMOR_CLASS:
567                 if (is_boots(otmp)) {
568                         type = DUST;
569                         break;
570                 }
571                 /* fall through */
572             /* Objects too large to engrave with */
573             case BALL_CLASS:
574             case ROCK_CLASS:
575                 You_cant("engrave with such a large object!");
576                 ptext = FALSE;
577                 break;
578
579             /* Objects too silly to engrave with */
580             case FOOD_CLASS:
581             case SCROLL_CLASS:
582             case SPBOOK_CLASS:
583                 Your("%s would get %s.", xname(otmp),
584                         is_ice(u.ux,u.uy) ? "all frosty" : "too dirty");
585                 ptext = FALSE;
586                 break;
587
588             case RANDOM_CLASS:  /* This should mean fingers */
589                 break;
590
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.
597              */
598             case WAND_CLASS:
599                 if (zappable(otmp)) {
600                     check_unpaid(otmp);
601                     zapwand = TRUE;
602                     if (Levitation) ptext = FALSE;
603
604                     switch (otmp->otyp) {
605                     /* DUST wands */
606                     default:
607                         break;
608
609                         /* NODIR wands */
610                     case WAN_LIGHT:
611                     case WAN_SECRET_DOOR_DETECTION:
612                     case WAN_CREATE_MONSTER:
613                     case WAN_WISHING:
614                     case WAN_ENLIGHTENMENT:
615                         zapnodir(otmp);
616                         break;
617
618                         /* IMMEDIATE wands */
619                         /* If wand is "IMMEDIATE", remember to affect the
620                          * previous engraving even if turning to dust.
621                          */
622                     case WAN_STRIKING:
623                         Strcpy(post_engr_text,
624                         "The wand unsuccessfully fights your attempt to write!"
625                         );
626                         break;
627                     case WAN_SLOW_MONSTER:
628                         if (!Blind) {
629                            Sprintf(post_engr_text,
630                                    "The bugs on the %s slow down!",
631                                    surface(u.ux, u.uy));
632                         }
633                         break;
634                     case WAN_SPEED_MONSTER:
635                         if (!Blind) {
636                            Sprintf(post_engr_text,
637                                    "The bugs on the %s speed up!",
638                                    surface(u.ux, u.uy));
639                         }
640                         break;
641                     case WAN_POLYMORPH:
642                         if(oep)  {
643                             if (!Blind) {
644                                 type = (xchar)0;        /* random */
645                                 (void) random_engraving(buf);
646                             }
647                             dengr = TRUE;
648                         }
649                         break;
650                     case WAN_NOTHING:
651                     case WAN_UNDEAD_TURNING:
652                     case WAN_OPENING:
653                     case WAN_LOCKING:
654                     case WAN_PROBING:
655                         break;
656
657                         /* RAY wands */
658                     case WAN_MAGIC_MISSILE:
659                         ptext = TRUE;
660                         if (!Blind) {
661                            Sprintf(post_engr_text,
662                                    "The %s is riddled by bullet holes!",
663                                    surface(u.ux, u.uy));
664                         }
665                         break;
666
667                     /* can't tell sleep from death - Eric Backus */
668                     case WAN_SLEEP:
669                     case WAN_DEATH:
670                         if (!Blind) {
671                            Sprintf(post_engr_text,
672                                    "The bugs on the %s stop moving!",
673                                    surface(u.ux, u.uy));
674                         }
675                         break;
676
677                     case WAN_COLD:
678                         if (!Blind)
679                             Strcpy(post_engr_text,
680                                 "A few ice cubes drop from the wand.");
681                         if(!oep || (oep->engr_type != BURN))
682                             break;
683                     case WAN_CANCELLATION:
684                     case WAN_MAKE_INVISIBLE:
685                         if (oep && oep->engr_type != HEADSTONE) {
686                             if (!Blind)
687                                 pline_The("engraving on the %s vanishes!",
688                                         surface(u.ux,u.uy));
689                             dengr = TRUE;
690                         }
691                         break;
692                     case WAN_TELEPORTATION:
693                         if (oep && oep->engr_type != HEADSTONE) {
694                             if (!Blind)
695                                 pline_The("engraving on the %s vanishes!",
696                                         surface(u.ux,u.uy));
697                             teleengr = TRUE;
698                         }
699                         break;
700
701                     /* type = ENGRAVE wands */
702                     case WAN_DIGGING:
703                         ptext = TRUE;
704                         type  = ENGRAVE;
705                         if(!objects[otmp->otyp].oc_name_known) {
706                             if (flags.verbose)
707                                 pline("This %s is a wand of digging!",
708                                 xname(otmp));
709                             doknown = TRUE;
710                         }
711                         if (!Blind)
712                             Strcpy(post_engr_text,
713                                 IS_GRAVE(levl[u.ux][u.uy].typ) ?
714                                 "Chips fly out from the headstone." :
715                                 is_ice(u.ux,u.uy) ?
716                                 "Ice chips fly up from the ice surface!" :
717                                 "Gravel flies up from the floor.");
718                         else
719                             Strcpy(post_engr_text, "You hear drilling!");
720                         break;
721
722                     /* type = BURN wands */
723                     case WAN_FIRE:
724                         ptext = TRUE;
725                         type  = BURN;
726                         if(!objects[otmp->otyp].oc_name_known) {
727                         if (flags.verbose)
728                             pline("This %s is a wand of fire!", xname(otmp));
729                             doknown = TRUE;
730                         }
731                         Strcpy(post_engr_text,
732                                 Blind ? "You feel the wand heat up." :
733                                         "Flames fly from the wand.");
734                         break;
735                     case WAN_LIGHTNING:
736                         ptext = TRUE;
737                         type  = BURN;
738                         if(!objects[otmp->otyp].oc_name_known) {
739                             if (flags.verbose)
740                                 pline("This %s is a wand of lightning!",
741                                         xname(otmp));
742                             doknown = TRUE;
743                         }
744                         if (!Blind) {
745                             Strcpy(post_engr_text,
746                                     "Lightning arcs from the wand.");
747                             doblind = TRUE;
748                         } else
749                             Strcpy(post_engr_text, "You hear crackling!");
750                         break;
751
752                     /* type = MARK wands */
753                     /* type = ENGR_BLOOD wands */
754                     }
755                 } else /* end if zappable */
756                     if (!can_reach_floor()) {
757                         You_cant("reach the %s!", surface(u.ux,u.uy));
758                         return(0);
759                     }
760                 break;
761
762             case WEAPON_CLASS:
763                 if (is_blade(otmp)) {
764                     if ((int)otmp->spe > -3)
765                         type = ENGRAVE;
766                     else
767                         Your("%s too dull for engraving.", aobjnam(otmp,"are"));
768                 }
769                 break;
770
771             case TOOL_CLASS:
772                 if(otmp == ublindf) {
773                     pline(
774                 "That is a bit difficult to engrave with, don't you think?");
775                     return(0);
776                 }
777                 switch (otmp->otyp)  {
778                     case MAGIC_MARKER:
779                         if (otmp->spe <= 0)
780                             Your("marker has dried out.");
781                         else
782                             type = MARK;
783                         break;
784                     case TOWEL:
785                         /* Can't really engrave with a towel */
786                         ptext = FALSE;
787                         if (oep)
788                             if ((oep->engr_type == DUST ) ||
789                                 (oep->engr_type == ENGR_BLOOD) ||
790                                 (oep->engr_type == MARK )) {
791                                 if (!Blind)
792                                     You("wipe out the message here.");
793                                 else
794                                     Your("%s %s %s.", xname(otmp),
795                                          otense(otmp, "get"),
796                                          is_ice(u.ux,u.uy) ?
797                                          "frosty" : "dusty");
798                                 dengr = TRUE;
799                             } else
800                                 Your("%s can't wipe out this engraving.",
801                                      xname(otmp));
802                         else
803                             Your("%s %s %s.", xname(otmp), otense(otmp, "get"),
804                                   is_ice(u.ux,u.uy) ? "frosty" : "dusty");
805                         break;
806                     default:
807                         break;
808                 }
809                 break;
810
811             case VENOM_CLASS:
812 #ifdef WIZARD
813                 if (wizard) {
814                     pline("Writing a poison pen letter??");
815                     break;
816                 }
817 #endif
818             case ILLOBJ_CLASS:
819                 impossible("You're engraving with an illegal object!");
820                 break;
821         }
822
823         if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
824             if (type == ENGRAVE || type == 0)
825                 type = HEADSTONE;
826             else {
827                 /* ensures the "cannot wipe out" case */
828                 type = DUST;
829                 dengr = FALSE;
830                 teleengr = FALSE;
831                 buf[0] = (char)0;
832             }
833         }
834
835         /* End of implement setup */
836
837         /* Identify stylus */
838         if (doknown) {
839             makeknown(otmp->otyp);
840             more_experienced(0,10);
841         }
842
843         if (teleengr) {
844             rloc_engr(oep);
845             oep = (struct engr *)0;
846         }
847
848         if (dengr) {
849             del_engr(oep);
850             oep = (struct engr *)0;
851         }
852
853         /* Something has changed the engraving here */
854         if (*buf) {
855             make_engr_at(u.ux, u.uy, buf, moves, type);
856             pline_The("engraving now reads: \"%s\".", buf);
857             ptext = FALSE;
858         }
859
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");
866             useup(otmp);
867             ptext = FALSE;
868         }
869
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));
873             return(1);
874         }
875
876         /* Special effects should have deleted the current engraving (if
877          * possible) by now.
878          */
879
880         if (oep) {
881             register char c = 'n';
882
883             /* Give player the choice to add to engraving. */
884
885             if (type == HEADSTONE) {
886                 /* no choice, only append */
887                 c = 'y';
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?",
891                                 ynqchars, 'y');
892                 if (c == 'q') {
893                     pline(Never_mind);
894                     return(0);
895                 }
896             }
897
898             if (c == 'n' || Blind) {
899
900                 if( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) ||
901                     (oep->engr_type == MARK) ) {
902                     if (!Blind) {
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"   :
906                                                          "written")));
907                         del_engr(oep);
908                         oep = (struct engr *)0;
909                     } else
910                    /* Don't delete engr until after we *know* we're engraving */
911                         eow = TRUE;
912                 } else
913                     if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) {
914                         You(
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));
919                         return(1);
920                     } else
921                         if ( (type != oep->engr_type) || (c == 'n') ) {
922                             if (!Blind || can_reach_floor())
923                                 You("will overwrite the current message.");
924                             eow = TRUE;
925                         }
926             }
927         }
928
929         eloc = surface(u.ux,u.uy);
930         switch(type){
931             default:
932                 everb = (oep && !eow ? "add to the weird writing on" :
933                                        "write strangely on");
934                 break;
935             case DUST:
936                 everb = (oep && !eow ? "add to the writing in" :
937                                        "write in");
938                 eloc = is_ice(u.ux,u.uy) ? "frost" : "dust";
939                 break;
940             case HEADSTONE:
941                 everb = (oep && !eow ? "add to the epitaph on" :
942                                        "engrave on");
943                 break;
944             case ENGRAVE:
945                 everb = (oep && !eow ? "add to the engraving in" :
946                                        "engrave in");
947                 break;
948             case BURN:
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"));
953                 break;
954             case MARK:
955                 everb = (oep && !eow ? "add to the graffiti on" :
956                                        "scribble on");
957                 break;
958             case ENGR_BLOOD:
959                 everb = (oep && !eow ? "add to the scrawl on" :
960                                        "scrawl on");
961                 break;
962         }
963
964         /* Tell adventurer what is going on */
965         if (otmp != &zeroobj)
966             You("%s the %s with %s.", everb, eloc, doname(otmp));
967         else
968             You("%s the %s with your %s.", everb, eloc,
969                 makeplural(body_part(FINGER)));
970
971         /* Prompt for engraving! */
972         Sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc);
973         getlin(qbuf, ebuf);
974
975         /* Count the actual # of chars engraved not including spaces */
976         len = strlen(ebuf);
977         for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1;
978
979         if (len == 0 || index(ebuf, '\033')) {
980             if (zapwand) {
981                 if (!Blind)
982                     pline("%s, then %s.",
983                           Tobjnam(otmp, "glow"), otense(otmp, "fade"));
984                 return(1);
985             } else {
986                 pline(Never_mind);
987                 return(0);
988             }
989         }
990
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++;
994
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) */
1004         }
1005
1006         /* Previous engraving is overwritten */
1007         if (eow) {
1008             del_engr(oep);
1009             oep = (struct engr *)0;
1010         }
1011
1012         /* Figure out how long it took to engrave, and if player has
1013          * engraved too much.
1014          */
1015         switch(type){
1016             default:
1017                 multi = -(len/10);
1018                 if (multi) nomovemsg = "You finish your weird engraving.";
1019                 break;
1020             case DUST:
1021                 multi = -(len/10);
1022                 if (multi) nomovemsg = "You finish writing in the dust.";
1023                 break;
1024             case HEADSTONE:
1025             case ENGRAVE:
1026                 multi = -(len/10);
1027                 if ((otmp->oclass == WEAPON_CLASS) &&
1028                     ((otmp->otyp != ATHAME) || otmp->cursed)) {
1029                     multi = -len;
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
1035                          *       "ere", then "th".
1036                          */
1037                     Your("%s dull.", aobjnam(otmp, "get"));
1038                     if (otmp->unpaid) {
1039                         struct monst *shkp = shop_keeper(*u.ushops);
1040                         if (shkp) {
1041                             You("damage it, you pay for it!");
1042                             bill_dummy_object(otmp);
1043                         }
1044                     }
1045                     if (len > maxelen) {
1046                         multi = -maxelen;
1047                         otmp->spe = -3;
1048                     } else if (len > 1)
1049                         otmp->spe -= len >> 1;
1050                     else otmp->spe -= 1; /* Prevent infinite engraving */
1051                 } else
1052                     if ( (otmp->oclass == RING_CLASS) ||
1053                          (otmp->oclass == GEM_CLASS) )
1054                         multi = -len;
1055                 if (multi) nomovemsg = "You finish engraving.";
1056                 break;
1057             case BURN:
1058                 multi = -(len/10);
1059                 if (multi)
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.";
1063                 break;
1064             case MARK:
1065                 multi = -(len/10);
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.");
1071                         otmp->spe = 0;
1072                         multi = -(maxelen/10);
1073                     } else
1074                         if (len > 1) otmp->spe -= len >> 1;
1075                         else otmp->spe -= 1; /* Prevent infinite grafitti */
1076                 }
1077                 if (multi) nomovemsg = "You finish defacing the dungeon.";
1078                 break;
1079             case ENGR_BLOOD:
1080                 multi = -(len/10);
1081                 if (multi) nomovemsg = "You finish scrawling.";
1082                 break;
1083         }
1084
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) {
1090                 *sp = (char)0;
1091                 if (multi) nomovemsg = "You cannot write any more.";
1092                 You("only are able to write \"%s\"", ebuf);
1093             }
1094         }
1095
1096         /* Add to existing engraving */
1097         if (oep) Strcpy(buf, oep->engr_txt);
1098
1099         (void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
1100
1101         make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
1102
1103         if (post_engr_text[0]) pline(post_engr_text);
1104
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);
1109         }
1110
1111         return(1);
1112 }
1113
1114 void
1115 save_engravings(fd, mode)
1116 int fd, mode;
1117 {
1118         register struct engr *ep = head_engr;
1119         register struct engr *ep2;
1120         unsigned no_more_engr = 0;
1121
1122         while (ep) {
1123             ep2 = ep->nxt_engr;
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);
1127             }
1128             if (release_data(mode))
1129                 dealloc_engr(ep);
1130             ep = ep2;
1131         }
1132         if (perform_bwrite(mode))
1133             bwrite(fd, (genericptr_t)&no_more_engr, sizeof no_more_engr);
1134         if (release_data(mode))
1135             head_engr = 0;
1136 }
1137
1138 void
1139 rest_engravings(fd)
1140 int fd;
1141 {
1142         register struct engr *ep;
1143         unsigned lth;
1144
1145         head_engr = 0;
1146         while(1) {
1147                 mread(fd, (genericptr_t) &lth, sizeof(unsigned));
1148                 if(lth == 0) return;
1149                 ep = newengr(lth);
1150                 mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
1151                 ep->nxt_engr = head_engr;
1152                 head_engr = ep;
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;
1158         }
1159 }
1160
1161 void
1162 del_engr(ep)
1163 register struct engr *ep;
1164 {
1165         if (ep == head_engr) {
1166                 head_engr = ep->nxt_engr;
1167         } else {
1168                 register struct engr *ept;
1169
1170                 for (ept = head_engr; ept; ept = ept->nxt_engr)
1171                     if (ept->nxt_engr == ep) {
1172                         ept->nxt_engr = ep->nxt_engr;
1173                         break;
1174                     }
1175                 if (!ept) {
1176                     impossible("Error in del_engr?");
1177                     return;
1178                 }
1179         }
1180         dealloc_engr(ep);
1181 }
1182
1183 /* randomly relocate an engraving */
1184 void
1185 rloc_engr(ep)
1186 struct engr *ep;
1187 {
1188         int tx, ty, tryct = 200;
1189
1190         do  {
1191             if (--tryct < 0) return;
1192             tx = rn1(COLNO-3,2);
1193             ty = rn2(ROWNO);
1194         } while (engr_at(tx, ty) ||
1195                 !goodpos(tx, ty, (struct monst *)0, 0));
1196
1197         ep->engr_x = tx;
1198         ep->engr_y = ty;
1199 }
1200
1201
1202 /* Epitaphs for random headstones */
1203 static const char *epitaphs[] = {
1204         "Rest in peace",
1205         "R.I.P.",
1206         "Rest In Pieces",
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",
1213         "Made in Taiwan",
1214         "Og friend. Og good dude. Og died. Og now food",
1215         "Beetlejuice Beetlejuice Beetlejuice",
1216         "Look out below!",
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",
1223         "Sum quod eris",
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.",
1232         "Go away!"
1233 };
1234
1235 /* Create a headstone at the given location.
1236  * The caller is responsible for newsym(x, y).
1237  */
1238 void
1239 make_grave(x, y, str)
1240 int x, y;
1241 const char *str;
1242 {
1243         /* Can we put a grave here? */
1244         if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x,y)) return;
1245
1246         /* Make the grave */
1247         levl[x][y].typ = GRAVE;
1248
1249         /* Engrave the headstone */
1250         if (!str) str = epitaphs[rn2(SIZE(epitaphs))];
1251         del_engr_at(x, y);
1252         make_engr_at(x, y, str, 0L, HEADSTONE);
1253         return;
1254 }
1255
1256
1257 #endif /* OVLB */
1258
1259 /*engrave.c*/