1    | /*	SCCS Id: @(#)engrave.c	3.3	1999/08/16	*/
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))
157  | 	    return "air";
158  | 	else if (is_pool(x,y))
159  | 	    return "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  | 	    		strncpy(buf,  ep->engr_txt, 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  | 	if(strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
373  | 	ep->engr_time = e_time;
374  | 	ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1);
375  | 	ep->engr_lth = strlen(s) + 1;
376  | }
377  | 
378  | /* delete any engraving at location <x,y> */
379  | void
380  | del_engr_at(x, y)
381  | int x, y;
382  | {
383  | 	register struct engr *ep = engr_at(x, y);
384  | 
385  | 	if (ep) del_engr(ep);
386  | }
387  | 
388  | /*
389  |  *	freehand - returns true if player has a free hand
390  |  */
391  | int
392  | freehand()
393  | {
394  | 	return(!uwep || !welded(uwep) ||
395  | 	   (!bimanual(uwep) && (!uarms || !uarms->cursed)));
396  | /*	if ((uwep && bimanual(uwep)) ||
397  | 	    (uwep && uarms))
398  | 		return(0);
399  | 	else
400  | 		return(1);*/
401  | }
402  | 
403  | static NEARDATA const char styluses[] =
404  | 	{ ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
405  | 	  GEM_CLASS, RING_CLASS, 0 };
406  | 
407  | /* Mohs' Hardness Scale:
408  |  *  1 - Talc		 6 - Orthoclase
409  |  *  2 - Gypsum		 7 - Quartz
410  |  *  3 - Calcite		 8 - Topaz
411  |  *  4 - Fluorite	 9 - Corundum
412  |  *  5 - Apatite		10 - Diamond
413  |  *
414  |  * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
415  |  * probably be able to scratch the rock.
416  |  * Devaluation of less hard gems is not easily possible because obj struct
417  |  * does not contain individual oc_cost currently. 7/91
418  |  *
419  |  * steel     -	5-8.5	(usu. weapon)
420  |  * diamond    - 10			* jade	     -	5-6	 (nephrite)
421  |  * ruby       -  9	(corundum)	* turquoise  -	5-6
422  |  * sapphire   -  9	(corundum)	* opal	     -	5-6
423  |  * topaz      -  8			* glass      - ~5.5
424  |  * emerald    -  7.5-8	(beryl)		* dilithium  -	4-5??
425  |  * aquamarine -  7.5-8	(beryl)		* iron	     -	4-5
426  |  * garnet     -  7.25	(var. 6.5-8)	* fluorite   -	4
427  |  * agate      -  7	(quartz)	* brass      -	3-4
428  |  * amethyst   -  7	(quartz)	* gold	     -	2.5-3
429  |  * jasper     -  7	(quartz)	* silver     -	2.5-3
430  |  * onyx       -  7	(quartz)	* copper     -	2.5-3
431  |  * moonstone  -  6	(orthoclase)	* amber      -	2-2.5
432  |  */
433  | 
434  | /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
435  | int
436  | doengrave()
437  | {
438  | 	boolean dengr = FALSE;	/* TRUE if we wipe out the current engraving */
439  | 	boolean doblind = FALSE;/* TRUE if engraving blinds the player */
440  | 	boolean doknown = FALSE;/* TRUE if we identify the stylus */
441  | 	boolean eow = FALSE;	/* TRUE if we are overwriting oep */
442  | 	boolean jello = FALSE;	/* TRUE if we are engraving in slime */
443  | 	boolean ptext = TRUE;	/* TRUE if we must prompt for engrave text */
444  | 	boolean teleengr =FALSE;/* TRUE if we move the old engraving */
445  | 	boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
446  | 	xchar type = DUST;	/* Type of engraving made */
447  | 	char buf[BUFSZ];	/* Buffer for final/poly engraving text */
448  | 	char ebuf[BUFSZ];	/* Buffer for initial engraving text */
449  | 	char qbuf[QBUFSZ];	/* Buffer for query text */
450  | 	char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */
451  | 	const char *everb;	/* Present tense of engraving type */
452  | 	const char *eloc;	/* Where the engraving is (ie dust/floor/...) */
453  | 	register char *sp;	/* Place holder for space count of engr text */
454  | 	register int len;	/* # of nonspace chars of new engraving text */
455  | 	register int maxelen;	/* Max allowable length of new engraving text */
456  | 	register int spct;	/* # of spaces in new engraving text */
457  | 	register struct engr *oep = engr_at(u.ux,u.uy);
458  | 				/* The current engraving */
459  | 	register struct obj *otmp; /* Object selected with which to engrave */
460  | 	char *writer;
461  | 
462  | 
463  | 	multi = 0;		/* moves consumed */
464  | 	nomovemsg = (char *)0;	/* occupation end message */
465  | 
466  | 	buf[0] = (char)0;
467  | 	ebuf[0] = (char)0;
468  | 	post_engr_text[0] = (char)0;
469  | 	maxelen = BUFSZ - 1;
470  | 	if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE)
471  | 	    type = ENGR_BLOOD;
472  | 
473  | 	/* Can the adventurer engrave at all? */
474  | 
475  | 	if(u.uswallow) {
476  | 		if (is_animal(u.ustuck->data)) {
477  | 			pline("What would you write?  \"Jonah was here\"?");
478  | 			return(0);
479  | 		} else if (is_whirly(u.ustuck->data)) {
480  | 			You_cant("reach the %s.", surface(u.ux,u.uy));
481  | 			return(0);
482  | 		} else
483  | 			jello = TRUE;
484  | 	} else if (is_lava(u.ux, u.uy)) {
485  | 		You_cant("write on the lava!");
486  | 		return(0);
487  | 	} else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
488  | 		You_cant("write on the water!");
489  | 		return(0);
490  | 	}
491  | 	if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
492  | 		You_cant("write in thin air!");
493  | 		return(0);
494  | 	}
495  | 	if (cantwield(youmonst.data)) {
496  | 		You_cant("even hold anything!");
497  | 		return(0);
498  | 	}
499  | 	if (check_capacity((char *)0)) return (0);
500  | 
501  | 	/* One may write with finger, or weapon, or wand, or..., or...
502  | 	 * Edited by GAN 10/20/86 so as not to change weapon wielded.
503  | 	 */
504  | 
505  | 	otmp = getobj(styluses, "write with");
506  | 	if(!otmp) return(0);		/* otmp == zeroobj if fingers */
507  | 
508  | 	if (otmp == &zeroobj) writer = makeplural(body_part(FINGER));
509  | 	else writer = xname(otmp);
510  | 
511  | 	/* There's no reason you should be able to write with a wand
512  | 	 * while both your hands are tied up.
513  | 	 */
514  | 	if (!freehand() && otmp != uwep && !otmp->owornmask) {
515  | 		You("have no free %s to write with!", body_part(HAND));
516  | 		return(0);
517  | 	}
518  | 
519  | 	if (jello) {
520  | 		You("tickle %s with your %s.", mon_nam(u.ustuck), writer);
521  | 		Your("message dissolves...");
522  | 		return(0);
523  | 	}
524  | 	if (otmp->oclass != WAND_CLASS && !can_reach_floor()) {
525  | 		You_cant("reach the %s!", surface(u.ux,u.uy));
526  | 		return(0);
527  | 	}
528  | 	if (IS_ALTAR(levl[u.ux][u.uy].typ)) {
529  | 		You("make a motion towards the altar with your %s.", writer);
530  | 		altar_wrath(u.ux, u.uy);
531  | 		return(0);
532  | 	}
533  | 	if (IS_GRAVE(levl[u.ux][u.uy].typ)) {
534  | 		You("disturb the undead!");
535  | 		(void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS);
536  | 		exercise(A_WIS, FALSE);
537  | 		return(0);
538  | 	}
539  | 
540  | 	/* SPFX for items */
541  | 
542  | 	switch (otmp->oclass) {
543  | 	    default:
544  | 	    case AMULET_CLASS:
545  | 	    case CHAIN_CLASS:
546  | 	    case POTION_CLASS:
547  | 	    case GOLD_CLASS:
548  | 		break;
549  | 
550  | 	    case RING_CLASS:
551  | 		/* "diamond" rings and others should work */
552  | 	    case GEM_CLASS:
553  | 		/* diamonds & other hard gems should work */
554  | 		if (objects[otmp->otyp].oc_tough) {
555  | 			type = ENGRAVE;
556  | 			break;
557  | 		}
558  | 		break;
559  | 
560  | 	    case ARMOR_CLASS:
561  | 		if (is_boots(otmp)) {
562  | 			type = DUST;
563  | 			break;
564  | 		}
565  | 		/* fall through */
566  | 	    /* Objects too large to engrave with */
567  | 	    case BALL_CLASS:
568  | 	    case ROCK_CLASS:
569  | 		You_cant("engrave with such a large object!");
570  | 		ptext = FALSE;
571  | 		break;
572  | 
573  | 	    /* Objects too silly to engrave with */
574  | 	    case FOOD_CLASS:
575  | 	    case SCROLL_CLASS:
576  | 	    case SPBOOK_CLASS:
577  | 		Your("%s would get %s.", xname(otmp),
578  | 			is_ice(u.ux,u.uy) ? "all frosty" : "too dirty");
579  | 		ptext = FALSE;
580  | 		break;
581  | 
582  | 	    case RANDOM_CLASS:	/* This should mean fingers */
583  | 		break;
584  | 
585  | 	    /* The charge is removed from the wand before prompting for
586  | 	     * the engraving text, because all kinds of setup decisions
587  | 	     * and pre-engraving messages are based upon knowing what type
588  | 	     * of engraving the wand is going to do.  Also, the player
589  | 	     * will have potentially seen "You wrest .." message, and
590  | 	     * therefore will know they are using a charge.
591  | 	     */
592  | 	    case WAND_CLASS:
593  | 		if (zappable(otmp)) {
594  | 		    check_unpaid(otmp);
595  | 		    zapwand = TRUE;
596  | 		    if (Levitation) ptext = FALSE;
597  | 
598  | 		    switch (otmp->otyp) {
599  | 		    /* DUST wands */
600  | 		    default:
601  | 			break;
602  | 
603  | 			/* NODIR wands */
604  | 		    case WAN_LIGHT:
605  | 		    case WAN_SECRET_DOOR_DETECTION:
606  | 		    case WAN_CREATE_MONSTER:
607  | 		    case WAN_WISHING:
608  | 		    case WAN_ENLIGHTENMENT:
609  | 			zapnodir(otmp);
610  | 			break;
611  | 
612  | 			/* IMMEDIATE wands */
613  | 			/* If wand is "IMMEDIATE", remember to affect the
614  | 			 * previous engraving even if turning to dust.
615  | 			 */
616  | 		    case WAN_STRIKING:
617  | 			Strcpy(post_engr_text,
618  | 			"The wand unsuccessfully fights your attempt to write!"
619  | 			);
620  | 			break;
621  | 		    case WAN_SLOW_MONSTER:
622  | 			if (!Blind) {
623  | 			   Sprintf(post_engr_text,
624  | 				   "The bugs on the %s slow down!",
625  | 				   surface(u.ux, u.uy));
626  | 			}
627  | 			break;
628  | 		    case WAN_SPEED_MONSTER:
629  | 			if (!Blind) {
630  | 			   Sprintf(post_engr_text,
631  | 				   "The bugs on the %s speed up!",
632  | 				   surface(u.ux, u.uy));
633  | 			}
634  | 			break;
635  | 		    case WAN_POLYMORPH:
636  | 			if(oep)  {
637  | 			    if (!Blind) {
638  | 				type = (xchar)0;	/* random */
639  | 				(void) random_engraving(buf);
640  | 			    }
641  | 			    dengr = TRUE;
642  | 			}
643  | 			break;
644  | 		    case WAN_NOTHING:
645  | 		    case WAN_UNDEAD_TURNING:
646  | 		    case WAN_OPENING:
647  | 		    case WAN_LOCKING:
648  | 		    case WAN_PROBING:
649  | 			break;
650  | 
651  | 			/* RAY wands */
652  | 		    case WAN_MAGIC_MISSILE:
653  | 			ptext = TRUE;
654  | 			if (!Blind) {
655  | 			   Sprintf(post_engr_text,
656  | 				   "The %s is riddled by bullet holes!",
657  | 				   surface(u.ux, u.uy));
658  | 			}
659  | 			break;
660  | 
661  | 		    /* can't tell sleep from death - Eric Backus */
662  | 		    case WAN_SLEEP:
663  | 		    case WAN_DEATH:
664  | 			if (!Blind) {
665  | 			   Sprintf(post_engr_text,
666  | 				   "The bugs on the %s stop moving!",
667  | 				   surface(u.ux, u.uy));
668  | 			}
669  | 			break;
670  | 
671  | 		    case WAN_COLD:
672  | 			if (!Blind)
673  | 			    Strcpy(post_engr_text,
674  | 				"A few ice cubes drop from the wand.");
675  | 			if(!oep || (oep->engr_type != BURN))
676  | 			    break;
677  | 		    case WAN_CANCELLATION:
678  | 		    case WAN_MAKE_INVISIBLE:
679  | 			if(oep) {
680  | 			    if (!Blind)
681  | 				pline_The("engraving on the %s vanishes!",
682  | 					surface(u.ux,u.uy));
683  | 			    dengr = TRUE;
684  | 			}
685  | 			break;
686  | 		    case WAN_TELEPORTATION:
687  | 			if (oep) {
688  | 			    if (!Blind)
689  | 				pline_The("engraving on the %s vanishes!",
690  | 					surface(u.ux,u.uy));
691  | 			    teleengr = TRUE;
692  | 			}
693  | 			break;
694  | 
695  | 		    /* type = ENGRAVE wands */
696  | 		    case WAN_DIGGING:
697  | 			ptext = TRUE;
698  | 			type  = ENGRAVE;
699  | 			if(!objects[otmp->otyp].oc_name_known) {
700  | 			    if (flags.verbose)
701  | 				pline("This %s is a wand of digging!",
702  | 				xname(otmp));
703  | 			    doknown = TRUE;
704  | 			}
705  | 			if (!Blind)
706  | 			    Strcpy(post_engr_text,
707  | 				is_ice(u.ux,u.uy) ?
708  | 				"Ice chips fly up from the ice surface!" :
709  | 				"Gravel flies up from the floor.");
710  | 			else
711  | 			    Strcpy(post_engr_text, "You hear drilling!");
712  | 			break;
713  | 
714  | 		    /* type = BURN wands */
715  | 		    case WAN_FIRE:
716  | 			ptext = TRUE;
717  | 			type  = BURN;
718  | 			if(!objects[otmp->otyp].oc_name_known) {
719  | 			if (flags.verbose)
720  | 			    pline("This %s is a wand of fire!", xname(otmp));
721  | 			    doknown = TRUE;
722  | 			}
723  | 			Strcpy(post_engr_text,
724  | 				Blind ? "You feel the wand heat up." :
725  | 					"Flames fly from the wand.");
726  | 			break;
727  | 		    case WAN_LIGHTNING:
728  | 			ptext = TRUE;
729  | 			type  = BURN;
730  | 			if(!objects[otmp->otyp].oc_name_known) {
731  | 			    if (flags.verbose)
732  | 				pline("This %s is a wand of lightning!",
733  | 					xname(otmp));
734  | 			    doknown = TRUE;
735  | 			}
736  | 			if (!Blind) {
737  | 			    Strcpy(post_engr_text,
738  | 				    "Lightning arcs from the wand.");
739  | 			    doblind = TRUE;
740  | 			} else
741  | 			    Strcpy(post_engr_text, "You hear crackling!");
742  | 			break;
743  | 
744  | 		    /* type = MARK wands */
745  | 		    /* type = ENGR_BLOOD wands */
746  | 		    }
747  | 		} else /* end if zappable */
748  | 		    if (!can_reach_floor()) {
749  | 			You_cant("reach the %s!", surface(u.ux,u.uy));
750  | 			return(0);
751  | 		    }
752  | 		break;
753  | 
754  | 	    case WEAPON_CLASS:
755  | 		if (is_blade(otmp)) {
756  | 		    if ((int)otmp->spe > -3)
757  | 			type = ENGRAVE;
758  | 		    else
759  | 			Your("%s too dull for engraving.", aobjnam(otmp,"are"));
760  | 		}
761  | 		break;
762  | 
763  | 	    case TOOL_CLASS:
764  | 		if(otmp == ublindf) {
765  | 		    pline(
766  | 		"That is a bit difficult to engrave with, don't you think?");
767  | 		    return(0);
768  | 		}
769  | 		switch (otmp->otyp)  {
770  | 		    case MAGIC_MARKER:
771  | 			if (otmp->spe <= 0)
772  | 			    Your("marker has dried out.");
773  | 			else
774  | 			    type = MARK;
775  | 			break;
776  | 		    case TOWEL:
777  | 			/* Can't really engrave with a towel */
778  | 			ptext = FALSE;
779  | 			if (oep)
780  | 			    if ((oep->engr_type == DUST ) ||
781  | 				(oep->engr_type == ENGR_BLOOD) ||
782  | 				(oep->engr_type == MARK )) {
783  | 				if (!Blind)
784  | 				    You("wipe out the message here.");
785  | 				else
786  | 				    Your("%s gets %s.", xname(otmp),
787  | 					  is_ice(u.ux,u.uy) ?
788  | 					  "frosty" : "dusty");
789  | 				dengr = TRUE;
790  | 			    } else
791  | 				Your("%s can't wipe out this engraving.",
792  | 				     xname(otmp));
793  | 			else
794  | 			    Your("%s gets %s.", xname(otmp),
795  | 				  is_ice(u.ux,u.uy) ? "frosty" : "dusty");
796  | 			break;
797  | 		    default:
798  | 			break;
799  | 		}
800  | 		break;
801  | 
802  | 	    case VENOM_CLASS:
803  | #ifdef WIZARD
804  | 		if (wizard) {
805  | 		    pline("Writing a poison pen letter??");
806  | 		    break;
807  | 		}
808  | #endif
809  | 	    case ILLOBJ_CLASS:
810  | 		impossible("You're engraving with an illegal object!");
811  | 		break;
812  | 	}
813  | 
814  | 	/* End of implement setup */
815  | 
816  | 	/* Identify stylus */
817  | 	if (doknown) {
818  | 	    makeknown(otmp->otyp);
819  | 	    more_experienced(0,10);
820  | 	}
821  | 
822  | 	if (teleengr) {
823  | 	    rloc_engr(oep);
824  | 	    oep = (struct engr *)0;
825  | 	}
826  | 
827  | 	if (dengr) {
828  | 	    del_engr(oep);
829  | 	    oep = (struct engr *)0;
830  | 	}
831  | 
832  | 	/* Something has changed the engraving here */
833  | 	if (*buf) {
834  | 	    make_engr_at(u.ux, u.uy, buf, moves, type);
835  | 	    pline_The("engraving now reads: \"%s\".", buf);
836  | 	    ptext = FALSE;
837  | 	}
838  | 
839  | 	if (zapwand && (otmp->spe < 0)) {
840  | 	    pline("%s %sturns to dust.",
841  | 		  The(xname(otmp)), Blind ? "" : "glows violently, then ");
842  |  You("are not going to get anywhere trying to write in the %s with your dust.",
843  | 		is_ice(u.ux,u.uy) ? "frost" : "dust");
844  | 	    useup(otmp);
845  | 	    ptext = FALSE;
846  | 	}
847  | 
848  | 	if (!ptext) {		/* Early exit for some implements. */
849  | 	    if (otmp->oclass == WAND_CLASS && !can_reach_floor())
850  | 		You_cant("reach the %s!", surface(u.ux,u.uy));
851  | 	    return(1);
852  | 	}
853  | 
854  | 	/* Special effects should have deleted the current engraving (if
855  | 	 * possible) by now.
856  | 	 */
857  | 
858  | 	if (oep) {
859  | 	    register char c = 'n';
860  | 
861  | 	    /* Give player the choice to add to engraving. */
862  | 
863  | 	    if ( (type == oep->engr_type) && (!Blind ||
864  | 		 (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) {
865  | 		c = yn_function("Do you want to add to the current engraving?",
866  | 				ynqchars, 'y');
867  | 		if (c == 'q') {
868  | 		    pline(Never_mind);
869  | 		    return(0);
870  | 		}
871  | 	    }
872  | 
873  | 	    if (c == 'n' || Blind) {
874  | 
875  | 		if( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) ||
876  | 		    (oep->engr_type == MARK) ) {
877  | 		    if (!Blind) {
878  | 			You("wipe out the message that was %s here.",
879  | 			    ((oep->engr_type == DUST)  ? "written in the dust" :
880  | 			    ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood"   :
881  | 							 "written")));
882  | 			del_engr(oep);
883  | 			oep = (struct engr *)0;
884  | 		    } else
885  | 		   /* Don't delete engr until after we *know* we're engraving */
886  | 			eow = TRUE;
887  | 		} else
888  | 		    if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) {
889  | 			You(
890  | 			 "cannot wipe out the message that is %s the %s here.",
891  | 			 oep->engr_type == BURN ?
892  | 			   (is_ice(u.ux,u.uy) ? "melted into" : "burned into") :
893  | 			   "engraved in", surface(u.ux,u.uy));
894  | 			return(1);
895  | 		    } else
896  | 			if ( (type != oep->engr_type) || (c == 'n') ) {
897  | 			    if (!Blind || can_reach_floor())
898  | 				You("will overwrite the current message.");
899  | 			    eow = TRUE;
900  | 			}
901  | 	}
902  | 	}
903  | 
904  | 	eloc = surface(u.ux,u.uy);
905  | 	switch(type){
906  | 	    default:
907  | 		everb = (oep && !eow ? "add to the weird writing on" :
908  | 				       "write strangely on");
909  | 		break;
910  | 	    case DUST:
911  | 		everb = (oep && !eow ? "add to the writing in" :
912  | 				       "write in");
913  | 		eloc = is_ice(u.ux,u.uy) ? "frost" : "dust";
914  | 		break;
915  | 	    case ENGRAVE:
916  | 		everb = (oep && !eow ? "add to the engraving in" :
917  | 				       "engrave in");
918  | 		break;
919  | 	    case BURN:
920  | 		everb = (oep && !eow ?
921  | 			( is_ice(u.ux,u.uy) ? "add to the text melted into" :
922  | 					      "add to the text burned into") :
923  | 			( is_ice(u.ux,u.uy) ? "melt into" : "burn into"));
924  | 		break;
925  | 	    case MARK:
926  | 		everb = (oep && !eow ? "add to the graffiti on" :
927  | 				       "scribble on");
928  | 		break;
929  | 	    case ENGR_BLOOD:
930  | 		everb = (oep && !eow ? "add to the scrawl on" :
931  | 				       "scrawl on");
932  | 		break;
933  | 	}
934  | 
935  | 	/* Tell adventurer what is going on */
936  | 	if (otmp != &zeroobj)
937  | 	    You("%s the %s with %s.", everb, eloc, doname(otmp));
938  | 	else
939  | 	    You("%s the %s with your %s.", everb, eloc,
940  | 		makeplural(body_part(FINGER)));
941  | 
942  | 	/* Prompt for engraving! */
943  | 	Sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc);
944  | 	getlin(qbuf, ebuf);
945  | 
946  | 	/* Mix up engraving if surface or state of mind is unsound.  */
947  | 	/* Original kludge by stewr 870708.  modified by njm 910722. */
948  | 	for (sp = ebuf; *sp; sp++)
949  | 	    if ( ((type == DUST || type == ENGR_BLOOD) && !rn2(25)) ||
950  | 		 (Blind   && !rn2(9)) || (Confusion     && !rn2(12)) ||
951  | 		 (Stunned && !rn2(4)) || (Hallucination && !rn2(1)) )
952  | 		 *sp = '!' + rn2(93); /* ASCII-code only */
953  | 
954  | 	/* Count the actual # of chars engraved not including spaces */
955  | 	len = strlen(ebuf);
956  | 
957  | 	for (sp = ebuf, spct = 0; *sp; sp++) if (isspace(*sp)) spct++;
958  | 
959  | 	if ( (len == spct) || index(ebuf, '\033') ) {
960  | 	    if (zapwand) {
961  | 		if (!Blind)
962  | 		    pline("%s glows, then fades.", The(xname(otmp)));
963  | 		return(1);
964  | 	    } else {
965  | 		pline(Never_mind);
966  | 		return(0);
967  | 	    }
968  | 	}
969  | 
970  | 	len -= spct;
971  | 
972  | 	/* A single `x' is the traditional signature of an illiterate person */
973  | 	if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X')))
974  | 	    u.uconduct.literate++;
975  | 
976  | 	/* Previous engraving is overwritten */
977  | 	if (eow) {
978  | 	    del_engr(oep);
979  | 	    oep = (struct engr *)0;
980  | 	}
981  | 
982  | 	/* Figure out how long it took to engrave, and if player has
983  | 	 * engraved too much.
984  | 	 */
985  | 	switch(type){
986  | 	    default:
987  | 		multi = -(len/10);
988  | 		if (multi) nomovemsg = "You finish your weird engraving.";
989  | 		break;
990  | 	    case DUST:
991  | 		multi = -(len/10);
992  | 		if (multi) nomovemsg = "You finish writing in the dust.";
993  | 		break;
994  | 	    case ENGRAVE:
995  | 		multi = -(len/10);
996  | 		if ((otmp->oclass == WEAPON_CLASS) &&
997  | 		    ((otmp->otyp != ATHAME) || otmp->cursed)) {
998  | 		    multi = -len;
999  | 		    maxelen = ((otmp->spe + 3) * 2) + 1;
1000 | 			/* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11
1001 | 			 * Note: this does not allow a +0 anything (except
1002 | 			 *	 an athame) to engrave "Elbereth" all at once.
1003 | 			 *	 However, you could now engrave "Elb", then
1004 | 			 *	 "ere", then "th".
1005 | 			 */
1006 | 		    Your("%s dull.", aobjnam(otmp, "get"));
1007 | 		    if (len > maxelen) {
1008 | 			multi = -maxelen;
1009 | 			otmp->spe = -3;
1010 | 		    } else
1011 | 			if (len > 1) otmp->spe -= len >> 1;
1012 | 			else otmp->spe -= 1; /* Prevent infinite engraving */
1013 | 		} else
1014 | 		    if ( (otmp->oclass == RING_CLASS) ||
1015 | 			 (otmp->oclass == GEM_CLASS) )
1016 | 			multi = -len;
1017 | 		if (multi) nomovemsg = "You finish engraving.";
1018 | 		break;
1019 | 	    case BURN:
1020 | 		multi = -(len/10);
1021 | 		if (multi)
1022 | 		    nomovemsg = is_ice(u.ux,u.uy) ?
1023 | 			"You finish melting your message into the ice.":
1024 | 			"You finish burning your message into the floor.";
1025 | 		break;
1026 | 	    case MARK:
1027 | 		multi = -(len/10);
1028 | 		if ((otmp->oclass == TOOL_CLASS) &&
1029 | 		    (otmp->otyp == MAGIC_MARKER)) {
1030 | 		    maxelen = (otmp->spe) * 2; /* one charge / 2 letters */
1031 | 		    if (len > maxelen) {
1032 | 			Your("marker dries out.");
1033 | 			otmp->spe = 0;
1034 | 			multi = -(maxelen/10);
1035 | 		    } else
1036 | 			if (len > 1) otmp->spe -= len >> 1;
1037 | 			else otmp->spe -= 1; /* Prevent infinite grafitti */
1038 | 		}
1039 | 		if (multi) nomovemsg = "You finish defacing the dungeon.";
1040 | 		break;
1041 | 	    case ENGR_BLOOD:
1042 | 		multi = -(len/10);
1043 | 		if (multi) nomovemsg = "You finish scrawling.";
1044 | 		break;
1045 | 	}
1046 | 
1047 | 	/* Chop engraving down to size if necessary */
1048 | 	if (len > maxelen) {
1049 | 	    for (sp = ebuf; (maxelen && *sp); sp++)
1050 | 		if (!isspace(*sp)) maxelen--;
1051 | 	    if (!maxelen && *sp) {
1052 | 		*sp = (char)0;
1053 | 		if (multi) nomovemsg = "You cannot write any more.";
1054 | 		You("only are able to write \"%s\"", ebuf);
1055 | 	    }
1056 | 	}
1057 | 
1058 | 	/* Add to existing engraving */
1059 | 	if (oep) Strcpy(buf, oep->engr_txt);
1060 | 
1061 | 	(void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
1062 | 
1063 | 	make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
1064 | 
1065 | 	if (post_engr_text[0]) pline(post_engr_text);
1066 | 
1067 | 	if (doblind && !resists_blnd(&youmonst)) {
1068 | 	    You("are blinded by the flash!");
1069 | 	    make_blinded((long)rnd(50),FALSE);
1070 | 	}
1071 | 
1072 | 	return(1);
1073 | }
1074 | 
1075 | void
1076 | save_engravings(fd, mode)
1077 | int fd, mode;
1078 | {
1079 | 	register struct engr *ep = head_engr;
1080 | 	register struct engr *ep2;
1081 | 	unsigned no_more_engr = 0;
1082 | 
1083 | 	while (ep) {
1084 | 	    ep2 = ep->nxt_engr;
1085 | 	    if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) {
1086 | 		bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
1087 | 		bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
1088 | 	    }
1089 | 	    if (release_data(mode))
1090 | 		dealloc_engr(ep);
1091 | 	    ep = ep2;
1092 | 	}
1093 | 	if (perform_bwrite(mode))
1094 | 	    bwrite(fd, (genericptr_t)&no_more_engr, sizeof no_more_engr);
1095 | 	if (release_data(mode))
1096 | 	    head_engr = 0;
1097 | }
1098 | 
1099 | void
1100 | rest_engravings(fd)
1101 | int fd;
1102 | {
1103 | 	register struct engr *ep;
1104 | 	unsigned lth;
1105 | 
1106 | 	head_engr = 0;
1107 | 	while(1) {
1108 | 		mread(fd, (genericptr_t) &lth, sizeof(unsigned));
1109 | 		if(lth == 0) return;
1110 | 		ep = newengr(lth);
1111 | 		mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
1112 | 		ep->nxt_engr = head_engr;
1113 | 		head_engr = ep;
1114 | 		ep->engr_txt = (char *) (ep + 1);	/* Andreas Bormann */
1115 | 		/* mark as finished for bones levels -- no problem for
1116 | 		 * normal levels as the player must have finished engraving
1117 | 		 * to be able to move again */
1118 | 		ep->engr_time = moves;
1119 | 	}
1120 | }
1121 | 
1122 | void
1123 | del_engr(ep)
1124 | register struct engr *ep;
1125 | {
1126 | 	if (ep == head_engr) {
1127 | 		head_engr = ep->nxt_engr;
1128 | 	} else {
1129 | 		register struct engr *ept;
1130 | 
1131 | 		for (ept = head_engr; ept; ept = ept->nxt_engr)
1132 | 		    if (ept->nxt_engr == ep) {
1133 | 			ept->nxt_engr = ep->nxt_engr;
1134 | 			break;
1135 | 		    }
1136 | 		if (!ept) {
1137 | 		    impossible("Error in del_engr?");
1138 | 		    return;
1139 | 		}
1140 | 	}
1141 | 	dealloc_engr(ep);
1142 | }
1143 | 
1144 | /* randomly relocate an engraving */
1145 | void
1146 | rloc_engr(ep)
1147 | struct engr *ep;
1148 | {
1149 | 	int tx, ty, tryct = 200;
1150 | 
1151 | 	do  {
1152 | 	    if (--tryct < 0) return;
1153 | 	    tx = rn1(COLNO-3,2);
1154 | 	    ty = rn2(ROWNO);
1155 | 	} while (engr_at(tx, ty) ||
1156 | 		!goodpos(tx, ty, (struct monst *)0));
1157 | 
1158 | 	ep->engr_x = tx;
1159 | 	ep->engr_y = ty;
1160 | }
1161 | 
1162 | 
1163 | /* Epitaphs for random headstones */
1164 | static const char *epitaphs[] = {
1165 | 	"Rest in peace",
1166 | 	"R.I.P.",
1167 | 	"Rest In Pieces",
1168 | 	"Note -- there are NO valuable items in this grave",
1169 | 	"1994-1995. The Longest-Lived Hacker Ever",
1170 | 	"The Grave of the Unknown Hacker",
1171 | 	"We weren't sure who this was, but we buried him here anyway",
1172 | 	"Sparky -- he was a very good dog",
1173 | 	"Beware of Electric Third Rail",
1174 | 	"Made in Taiwan",
1175 | 	"Og friend. Og good dude. Og died. Og now food",
1176 | 	"Beetlejuice Beetlejuice Beetlejuice",
1177 | 	"Look out below!",
1178 | 	"Please don't dig me up. I'm perfectly happy down here. -- Resident",
1179 | 	"Postman, please note forwarding address: Gehennom, Asmodeus's Fortress, fifth lemure on the left",
1180 | 	"Mary had a little lamb/Its fleece was white as snow/When Mary was in trouble/The lamb was first to go",
1181 | 	"Be careful, or this could happen to you!",
1182 | 	"Soon you'll join this fellow in hell! -- the Wizard of Yendor",
1183 | 	"Caution! This grave contains toxic waste",
1184 | 	"Sum quod eris",
1185 | 	"Here lies an Atheist, all dressed up and no place to go",
1186 | 	"Here lies Ezekiel, age 102.  The good die young.",
1187 | 	"Here lies my wife: Here let her lie! Now she's at rest and so am I.",
1188 | 	"Here lies Johnny Yeast. Pardon me for not rising.",
1189 | 	"He always lied while on the earth and now he's lying in it",
1190 | 	"I made an ash of myself",
1191 | 	"Soon ripe. Soon rotten. Soon gone. But not forgotten.",
1192 | 	"Here lies the body of Jonathan Blake. Stepped on the gas instead of the brake.",
1193 | 	"Go away!"
1194 | };
1195 | 
1196 | /* Create a headstone at the given location.
1197 |  * The caller is responsible for newsym(x, y).
1198 |  */
1199 | void
1200 | make_grave(x, y, str)
1201 | int x, y;
1202 | const char *str;
1203 | {
1204 | 	/* Can we put a grave here? */
1205 | 	if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x,y)) return;
1206 | 
1207 | 	/* Make the grave */
1208 | 	levl[x][y].typ = GRAVE;
1209 | 
1210 | 	/* Engrave the headstone */
1211 | 	if (!str) str = epitaphs[rn2(SIZE(epitaphs))];
1212 | 	del_engr_at(x, y);
1213 | 	make_engr_at(x, y, str, 0L, HEADSTONE);
1214 | 	return;
1215 | }
1216 | 
1217 | 
1218 | #endif /* OVLB */
1219 | 
1220 | /*engrave.c*/