Source:NetHack 3.1.0/engrave.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to engrave.c from the source code of NetHack 3.1.0.

Warning! This is the source code from an old release. For newer releases, see Source code

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)engrave.c	3.1	92/02/25	*/
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 struct engr NEARDATA *head_engr;
10.   
11.   STATIC_DCL void FDECL(del_engr, (struct engr *));
12.   
13.   #ifdef OVLB
14.   /* random engravings */
15.   const char *random_mesg[] = {
16.   	"Elbereth", "ad ae?ar um",
17.   	"?la? ?as he??",
18.   	/* take-offs and other famous engravings */
19.   	"Owlbreath", "?ala??iel",
20.   	"?ilroy wa? h?re",
21.   	"A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */
22.   	"Y?u won t get i? up ?he ste?s", /* Adventure */
23.   	"Lasc?ate o?ni sp?ranz? o vo? c?'en?rate", /* Inferno */
24.   	"Well Come", /* Prisoner */
25.   	"W? ap?l???ze for t?e inc?nve??e?ce", /* So Long... */
26.   	"S?e you n?xt Wed?esd?y", /* Thriller */
27.   	"Fo? a ?ood time c?ll 8?7-53?9",
28.   };
29.   
30.   const char *
31.   random_engraving()
32.   {
33.   	char *rumor, *s;
34.   
35.   /* a random engraving may come from the "rumors" file, or from the
36.      list above */
37.   	rumor = getrumor(0);
38.   	if (rn2(4) && *rumor) {
39.   		for (s = rumor; *s; s++)
40.   			if (!rn2(7) && *s != ' ') *s = '?';
41.   		if (s[-1] == '.') s[-1] = 0;
42.   		return (const char *)rumor;
43.   	}
44.   	else
45.   		return random_mesg[rn2(SIZE(random_mesg))];
46.   }
47.   #endif /* OVLB */
48.   #ifdef OVL0
49.   
50.   struct engr *
51.   engr_at(x,y) register xchar x,y; {
52.   register struct engr *ep = head_engr;
53.   	while(ep) {
54.   		if(x == ep->engr_x && y == ep->engr_y)
55.   			return(ep);
56.   		ep = ep->nxt_engr;
57.   	}
58.   	return((struct engr *) 0);
59.   }
60.   
61.   #ifdef ELBERETH
62.   int
63.   sengr_at(s,x,y)
64.   	register const char *s;
65.   	register xchar x,y;
66.   {
67.   	register struct engr *ep = engr_at(x,y);
68.   	register char *t;
69.   	register int n;
70.   
71.   	if(ep && ep->engr_time <= moves) {
72.   		t = ep->engr_txt;
73.   /*
74.   		if(!strcmp(s,t)) return(1);
75.   */
76.   		n = strlen(s);
77.   		while(*t) {
78.   			if(!strncmp(s,t,n)) return(1);
79.   			t++;
80.   		}
81.   	}
82.   	return(0);
83.   }
84.   #endif
85.   
86.   #endif /* OVL0 */
87.   #ifdef OVL2
88.   
89.   void
90.   u_wipe_engr(cnt)
91.   register int cnt;
92.   {
93.   	if(!u.uswallow && !Levitation)
94.   		wipe_engr_at(u.ux, u.uy, cnt);
95.   }
96.   
97.   #endif /* OVL2 */
98.   #ifdef OVL1
99.   
100.  void
101.  wipe_engr_at(x,y,cnt) register xchar x,y,cnt; {
102.  register struct engr *ep = engr_at(x,y);
103.  register int lth,pos;
104.  char ch;
105.  	if(ep){
106.  	    if(ep->engr_type != BURN) {
107.  		if(ep->engr_type != DUST && ep->engr_type != BLOOD) {
108.  			cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1;
109.  		}
110.  		lth = strlen(ep->engr_txt);
111.  		if(lth && cnt > 0 ) {
112.  			while(cnt--) {
113.  				pos = rn2(lth);
114.  				if((ch = ep->engr_txt[pos]) == ' ')
115.  					continue;
116.  				ep->engr_txt[pos] = (ch != '?') ? '?' : ' ';
117.  			}
118.  		}
119.  		while(lth && ep->engr_txt[lth-1] == ' ')
120.  			ep->engr_txt[--lth] = 0;
121.  		while(ep->engr_txt[0] == ' ')
122.  			ep->engr_txt++;
123.  		if(!ep->engr_txt[0]) del_engr(ep);
124.  	    }
125.  	}
126.  }
127.  
128.  #endif /* OVL1 */
129.  #ifdef OVL2
130.  
131.  void
132.  read_engr_at(x,y)
133.  register int x,y;
134.  {
135.  	register struct engr *ep = engr_at(x,y);
136.  	register int	sensed = 0;
137.  
138.  	if(ep && ep->engr_txt[0]) {
139.  	    switch(ep->engr_type) {
140.  	    case DUST:
141.  		if(!Blind) {
142.  			sensed = 1;
143.  			pline("Something is written here in the dust.");
144.  		}
145.  		break;
146.  	    case ENGRAVE:
147.  		if(!Blind || !Levitation) {
148.  			sensed = 1;
149.  			pline("Something is engraved here on the floor.");
150.  		}
151.  		break;
152.  	    case BURN:
153.  		if(!Blind || !Levitation) {
154.  			sensed = 1;
155.  			pline("Some text has been burned into the floor here.");
156.  		}
157.  		break;
158.  	    case MARK:
159.  		if(!Blind) {
160.  			sensed = 1;
161.  			pline("There's some graffiti on the floor here.");
162.  		}
163.  		break;
164.  	    case BLOOD:
165.  		/* "It's a message!  Scrawled in blood!"
166.  		 * "What's it say?"
167.  		 * "It says... `See you next Wednesday.'" -- Thriller
168.  		 */
169.  		if(!Blind) {
170.  			sensed = 1;
171.  			You("see a message scrawled in blood here.");
172.  		}
173.  		break;
174.  	    default:
175.  		impossible("Something is written in a very strange way.");
176.  		sensed = 1;
177.  	    }
178.  	    if (sensed) {
179.  		You("%s: \"%s\".",
180.  		      (Blind) ? "feel the words" : "read",  ep->engr_txt);
181.  		if(flags.run > 1) nomul(0);
182.  	    }
183.  	}
184.  }
185.  
186.  #endif /* OVL2 */
187.  #ifdef OVLB
188.  
189.  void
190.  make_engr_at(x,y,s,e_time,e_type)
191.  register int x,y;
192.  register const char *s;
193.  register long e_time;
194.  register xchar e_type;
195.  {
196.  	register struct engr *ep;
197.  
198.  	if(ep = engr_at(x,y))
199.  	    del_engr(ep);
200.  	ep = newengr(strlen(s) + 1);
201.  	ep->nxt_engr = head_engr;
202.  	head_engr = ep;
203.  	ep->engr_x = x;
204.  	ep->engr_y = y;
205.  	ep->engr_txt = (char *)(ep + 1);
206.  	Strcpy(ep->engr_txt, s);
207.  	if(strcmp(s, "Elbereth")) exercise(A_WIS, TRUE);
208.  	ep->engr_time = e_time;
209.  	ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE);
210.  	ep->engr_lth = strlen(s) + 1;
211.  }
212.  
213.  /*
214.   *	freehand - returns true if player has a free hand
215.   */
216.  int
217.  freehand()
218.  {
219.  	return(!uwep || !welded(uwep) ||
220.  	   (!bimanual(uwep) && (!uarms || !uarms->cursed)));
221.  /*	if ((uwep && bimanual(uwep)) ||
222.  	    (uwep && uarms))
223.  		return(0);
224.  	else
225.  		return(1);*/
226.  }
227.  
228.  static const char NEARDATA styluses[] =
229.  	{ ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS,
230.  	  GEM_CLASS, RING_CLASS, 0 };
231.  
232.  /* Mohs' Hardness Scale:
233.   *  1 - Talc		 6 - Orthoclase
234.   *  2 - Gypsum		 7 - Quartz
235.   *  3 - Calcite		 8 - Topaz
236.   *  4 - Fluorite	 9 - Corundum
237.   *  5 - Apatite		10 - Diamond
238.   *
239.   * Since granite is a igneous rock hardness ~ 7, anything >= 8 should
240.   * probably be able to scratch the rock.
241.   * Devaluation of less hard gems is not easily possible because obj struct
242.   * does not contain individual oc_cost currently. 7/91
243.   *
244.   * dilithium  - ??			* jade	    -  5-6	(nephrite)
245.   * diamond    - 10			* turquoise -  5-6
246.   * ruby	      -  9	(corundum)	* opal	    -  5-6
247.   * sapphire   -  9	(corundum)	* iron	    -  4-5
248.   * topaz      -  8			* fluorite  -  4
249.   * emerald    -  7.5-8	(beryl)		* brass     -  3-4
250.   * aquamarine -  7.5-8	(beryl)		* gold	    -  2.5-3
251.   * garnet     -  7.25	(var. 6.5-8)	* silver    -  2.5-3
252.   * agate      -  7	(quartz)	* copper    -  2.5-3
253.   * amethyst   -  7	(quartz)	* amber     -  2-2.5
254.   * jasper     -  7	(quartz)	*	
255.   * onyx	      -  7 	(quartz)	* steel     -  5-8.5	(usu. weapon)
256.   * moonstone  -  6	(orthoclase)	*
257.   */
258.  
259.  static const short NEARDATA hard_gems[] =
260.  	{ DIAMOND, RUBY, SAPPHIRE, TOPAZ, EMERALD, AQUAMARINE, GARNET, 0 };
261.  
262.  static const char NEARDATA *hard_ring_names[] =
263.  	{"diamond", "ruby", "sapphire", "emerald", "topaz", ""};
264.  
265.  /* return 1 if action took 1 (or more) moves, 0 if error or aborted */
266.  int
267.  doengrave()
268.  {
269.  	boolean dengr = FALSE;	/* TRUE if we wipe out the current engraving */
270.  	boolean doblind = FALSE;/* TRUE if engraving blinds the player */
271.  	boolean doknown = FALSE;/* TRUE if we identify the stylus */
272.  	boolean eow = FALSE;	/* TRUE if we are overwriting oep */
273.  	boolean jello = FALSE;	/* TRUE if we are engraving in slime */
274.  	boolean ptext = TRUE;	/* TRUE if we must prompt for engrave text */
275.  	boolean teleengr =FALSE;/* TRUE if we move the old engraving */
276.  	boolean zapwand = FALSE;/* TRUE if we remove a wand charge */
277.  	xchar type = DUST;	/* Type of engraving made */
278.  	char buf[BUFSZ];	/* Buffer for final/poly engraving text */
279.  	char ebuf[BUFSZ];	/* Buffer for initial engraving text */
280.  	char qbuf[QBUFSZ];	/* Buffer for query text */
281.  	const char *everb;	/* Present tense of engraving type */
282.  	const char *eloc;	/* Where the engraving is (ie dust/floor/...) */
283.  	const char *post_engr_text; /* Text displayed after engraving prompt */
284.  	register char *sp;	/* Place holder for space count of engr text */
285.  	register int len;	/* # of nonspace chars of new engraving text */
286.  	register int maxelen;	/* Max allowable length of new engraving text */
287.  	register int spct;	/* # of spaces in new engraving text */
288.  	register struct engr *oep = engr_at(u.ux,u.uy);
289.  				/* The current engraving */
290.  	register struct obj *otmp; /* Object selected with which to engrave */
291.  
292.  
293.  	multi = 0;		/* moves consumed */
294.  	nomovemsg = (char *)0;	/* occupation end message */
295.  
296.  	buf[0] = (char)0;
297.  	ebuf[0] = (char)0;
298.  	post_engr_text = (char *)0;
299.  	maxelen = BUFSZ - 1;
300.  
301.  	/* Can the adventurer engrave at all? */
302.  
303.  	if(u.uswallow) {
304.  		if (is_animal(u.ustuck->data)) {
305.  			pline("What would you write?  \"Jonah was here\"?");
306.  			return(0);
307.  		} else if (is_whirly(u.ustuck->data)) {
308.  			You("can't reach the ground.");
309.  			return(0);
310.  		} else 
311.  			jello = TRUE;
312.      	} else if (is_lava(u.ux, u.uy)) {
313.  		You("can't write on the lava!");
314.  		return(0);
315.  	} else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
316.  		You("can't write on the water!");
317.  		return(0);
318.  	}
319.  	if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) {
320.  		You("can't write in thin air!");
321.  		return(0);
322.  	}
323.  #ifdef POLYSELF
324.  	if (cantwield(uasmon)) {
325.  		You("can't even hold anything!");
326.  		return(0);
327.  	}
328.  #endif
329.  	if (check_capacity(NULL)) return (0);
330.  
331.  	/* One may write with finger, or weapon, or wand, or..., or...
332.  	 * Edited by GAN 10/20/86 so as not to change weapon wielded.
333.  	 */
334.  
335.  	otmp = getobj(styluses, "write with");
336.  	if(!otmp) return(0);		/* otmp == zeroobj if fingers */
337.  
338.  	/* There's no reason you should be able to write with a wand
339.  	 * while both your hands are tied up.
340.  	 */
341.  	if (!freehand() && otmp != uwep && !otmp->owornmask) {
342.  		You("have no free %s to write with!", body_part(HAND));
343.  		return(0);
344.  	}
345.  
346.  	if (jello) {
347.  		You("tickle %s with your %s.", mon_nam(u.ustuck), 
348.  		    (otmp == &zeroobj) ? makeplural(body_part(FINGER)) :
349.  			xname(otmp));
350.  		Your("message dissolves...");
351.  		return(0);
352.  	}
353.  	if(Levitation && otmp->oclass != WAND_CLASS){		/* riv05!a3 */
354.  		You("can't reach the floor!");
355.  		return(0);
356.  	}
357.  
358.  	/* SPFX for items */
359.  
360.  	switch (otmp->oclass) {
361.  	    default:
362.  	    case AMULET_CLASS:
363.  	    case CHAIN_CLASS:
364.  	    case POTION_CLASS:
365.  	    case GOLD_CLASS:
366.  		break;
367.  
368.  	    case RING_CLASS:
369.  		/* "diamond" rings and others should work */
370.  		{
371.  		    register int i, j;
372.  
373.  		    for (i=0, j=strlen(hard_ring_names[i]); j; i++)
374.  			if ( !strncmp(hard_ring_names[i],
375.  			     OBJ_DESCR(objects[otmp->otyp]),
376.  			     j=strlen(hard_ring_names[i])) ) {
377.  			    type = ENGRAVE;
378.  			    break;
379.  			}
380.  		}
381.  		break;
382.  
383.  	    case GEM_CLASS:
384.  		/* diamonds & other gems should work */
385.  		{
386.  		    register int i;
387.  
388.  		    for (i=0; hard_gems[i]; i++)
389.  			if (otmp->otyp == hard_gems[i]) {
390.  			    type = ENGRAVE;
391.  			    break;
392.  			}
393.  		}
394.  		break;
395.  
396.  	    /* Objects too large to engrave with */
397.  	    case BALL_CLASS:
398.  	    case ROCK_CLASS:
399.  	    case ARMOR_CLASS:
400.  		You("can't engrave with such a large object!");
401.  		ptext = FALSE;
402.  		break;
403.  
404.  	    /* Objects too silly to engrave with */
405.  	    case FOOD_CLASS:
406.  	    case SCROLL_CLASS:
407.  	    case SPBOOK_CLASS:
408.  		Your("%s would get too dirty.", xname(otmp));
409.  		ptext = FALSE;
410.  		break;
411.  
412.  	    case RANDOM_CLASS:	/* This should mean fingers */
413.  		break;
414.  
415.  	    /* The charge is removed from the wand before prompting for
416.  	     * the engraving text, because all kinds of setup decisions
417.  	     * and pre-engraving messages are based upon knowing what type
418.  	     * of engraving the wand is going to do.  Also, the player
419.  	     * will have potentially seen "You wrest .." message, and
420.  	     * therefore will know they are using a charge.
421.  	     */
422.  	    case WAND_CLASS:
423.  		if (zappable(otmp)) {
424.  		    zapwand = TRUE;
425.  		    if (Levitation) ptext = FALSE;
426.  
427.  		    switch (otmp->otyp) {
428.  		    /* DUST wands */
429.  		    default:
430.  			break;
431.  
432.  			/* NODIR wands */
433.  		    case WAN_LIGHT:
434.  		    case WAN_SECRET_DOOR_DETECTION:
435.  		    case WAN_CREATE_MONSTER:
436.  		    case WAN_WISHING:
437.  	  		zapnodir(otmp);
438.  			break;
439.  
440.  			/* IMMEDIATE wands */
441.  	    		/* If wand is "IMMEDIATE", remember to effect the
442.  			 * previous engraving even if turning to dust.,
443.  			 */
444.  		    case WAN_STRIKING:
445.  			post_engr_text =
446.  			"The wand unsuccessfully fights your attempt to write!";
447.  			break;
448.  		    case WAN_SLOW_MONSTER:
449.  			if (!Blind)
450.  			   post_engr_text = "The bugs on the ground slow down!";
451.  			break;
452.  		    case WAN_SPEED_MONSTER:
453.  			if (!Blind)
454.  			   post_engr_text = "The bugs on the ground speed up!";
455.  			break;
456.  		    case WAN_POLYMORPH:
457.  			if(oep)  {
458.  			    if (!Blind) {
459.  				type = (xchar)0;	/* random */
460.  				Strcpy(buf,random_engraving());
461.  			    }
462.  			    dengr = TRUE;
463.  			}
464.  			break;
465.  		    case WAN_NOTHING:
466.  		    case WAN_UNDEAD_TURNING:
467.  		    case WAN_OPENING:
468.  		    case WAN_LOCKING:
469.  		    case WAN_PROBING:
470.  			break;
471.  
472.  			/* RAY wands */
473.  		    case WAN_MAGIC_MISSILE:
474.  			ptext = TRUE;
475.  			if (!Blind)
476.  			    post_engr_text =
477.  				"The ground is riddled by bullet holes!";
478.  			break;
479.  
480.  		    /* can't tell sleep from death - Eric Backus */
481.  		    case WAN_SLEEP:
482.  		    case WAN_DEATH:
483.  			if (!Blind)
484.  			    post_engr_text =
485.  				"The bugs on the ground stop moving!";
486.  			break;
487.  
488.  		    case WAN_COLD:
489.  			if (!Blind)
490.  			    post_engr_text =
491.  				"A few ice cubes drop from the wand.";
492.  			if(!oep || (oep->engr_type != BURN))
493.  			    break;
494.  		    case WAN_CANCELLATION:
495.  		    case WAN_MAKE_INVISIBLE:
496.  			if(oep) {
497.  			    if (!Blind)
498.  				pline("The engraving on the floor vanishes!");
499.  			    dengr = TRUE;
500.  			}
501.  			break;
502.  		    case WAN_TELEPORTATION:
503.  			if (oep) {
504.  			    if (!Blind)
505.  				pline("The engraving on the floor vanishes!");
506.  			    teleengr = TRUE;
507.  			}
508.  			break;
509.  
510.  		    /* type = ENGRAVE wands */
511.  		    case WAN_DIGGING:
512.  			ptext = TRUE;
513.  			type  = ENGRAVE;
514.  			if(!objects[otmp->otyp].oc_name_known) {
515.  	    		    if (flags.verbose)
516.  				pline("This %s is a wand of digging!",
517.  				xname(otmp));
518.  			    doknown = TRUE;
519.  			}
520.  			if (!Blind)
521.  			    post_engr_text = "Gravel flies up from the floor.";
522.  			else
523.  			    post_engr_text = "You hear drilling!";
524.  			break;
525.  
526.  		    /* type = BURN wands */
527.  		    case WAN_FIRE:
528.  			ptext = TRUE;
529.  			type  = BURN;
530.  			if(!objects[otmp->otyp].oc_name_known) {
531.  	    		if (flags.verbose)
532.  			    pline("This %s is a wand of fire!", xname(otmp));
533.  			    doknown = TRUE;
534.  			}
535.  			if (!Blind)
536.  			    post_engr_text = "Flames fly from the wand.";
537.  			else
538.  			    post_engr_text = "You feel the wand heat up.";
539.  			break;
540.  		    case WAN_LIGHTNING:
541.  			ptext = TRUE;
542.  			type  = BURN;
543.  			if(!objects[otmp->otyp].oc_name_known) {
544.  	    		    if (flags.verbose)
545.  				pline("This %s is a wand of lightning!",
546.  					xname(otmp));
547.  			    doknown = TRUE;
548.  			}
549.  			if (!Blind) {
550.  			    post_engr_text = "Lightning arcs from the wand.";
551.  			    doblind = TRUE;
552.  			} else
553.  			    post_engr_text = "You hear crackling!";
554.  			break;
555.  
556.  		    /* type = MARK wands */
557.  		    /* type = BLOOD wands */
558.  		    }
559.  		} else /* end if zappable */
560.  		    if (Levitation) {
561.  			You("can't reach the floor!");
562.  			return(0);
563.  		    }
564.  		break;
565.  
566.  	    case WEAPON_CLASS:
567.  		if(is_blade(otmp))
568.  		    if ((int)otmp->spe > -3)
569.  			type = ENGRAVE;
570.  		    else
571.  			Your("%s too dull for engraving.", aobjnam(otmp,"are"));
572.  		break;
573.  
574.  	    case TOOL_CLASS:
575.  		if(otmp == ublindf) {
576.  		    pline(
577.  		"That is a bit difficult to engrave with, don't you think?");
578.  		    return(0);
579.  		}
580.  		switch (otmp->otyp)  {
581.  		    case MAGIC_MARKER:
582.  			if (otmp->spe <= 0)
583.  			    Your("marker has dried out.");
584.  			else
585.  			    type = MARK;
586.  			break;
587.  		    case TOWEL:
588.   			/* Can't really engrave with a towel */
589.  			ptext = FALSE;
590.  			if (oep)
591.  			    if ((oep->engr_type == DUST ) ||
592.  				(oep->engr_type == BLOOD) ||
593.  				(oep->engr_type == MARK )) {
594.  				if (!Blind)
595.  				    You("wipe out the message here.");
596.  				else
597.  				    Your("%s gets dusty.", xname(otmp));
598.  				dengr = TRUE;
599.  			    } else
600.  				Your("%s can't wipe out this engraving.",
601.  				     xname(otmp));
602.  			else
603.  			    Your("%s gets dusty.", xname(otmp));
604.  			break;
605.  		    default:
606.  			break;
607.  		}
608.  		break;
609.  
610.  	    case VENOM_CLASS:
611.  #ifdef WIZARD
612.  		if (wizard) {
613.  		    pline("Writing a poison pen letter??");
614.  		    break;
615.  		}
616.  #endif
617.  	    case ILLOBJ_CLASS:
618.  		impossible("You're engraving with an illegal object!");
619.  		break;
620.  	}
621.  
622.  	/* End of implement setup */
623.  
624.  	/* Identify stylus */
625.  	if (doknown) {
626.  	    makeknown(otmp->otyp);
627.  	    more_experienced(0,10);
628.  	}
629.  
630.  	if (teleengr) {
631.  	    register int tx,ty;
632.  
633.  	    do  {
634.   		tx = rn1(COLNO-3,2);
635.  		ty = rn2(ROWNO);
636.  	    } while(!goodpos(tx,ty, (struct monst *)0, (struct permonst *)0));
637.  
638.  	    oep->engr_x = tx;
639.  	    oep->engr_y = ty;
640.  
641.  	    oep = (struct engr *)0;
642.  	}
643.  
644.  	if (dengr) {
645.  	    del_engr (oep);
646.  	    oep = (struct engr *)0;
647.  	}
648.  
649.  	/* Something has changed the engraving here */
650.  	if (*buf) {
651.  	    make_engr_at(u.ux, u.uy, buf, moves, type);
652.  	    pline("The engraving now reads: \"%s\".", buf);
653.  	    ptext = FALSE;
654.  	}
655.  
656.  	if (zapwand && (otmp->spe < 0)) {
657.  	    pline("%s %sturns to dust.",
658.  		  The(xname(otmp)), Blind ? "" : "glows violently, then ");
659.  You("are not going to get anywhere trying to write in the dust with your dust.");
660.  	    useup(otmp);
661.  	    ptext = FALSE;
662.  	}
663.  
664.  	if (!ptext) {		/* Early exit for some implements. */
665.  	    if (Levitation && (otmp->oclass == WAND_CLASS))
666.  		You("can't reach the floor!");
667.  	    return(1);
668.  	}
669.  
670.  	/* Special effects should have deleted the current engraving (if
671.  	 * possible) by now.
672.  	 */
673.  
674.  	if (oep) {
675.  	    register char c = 'n';
676.  
677.  	    /* Give player the choice to add to engraving. */
678.  
679.  	    if ( (type == oep->engr_type) && (!Blind ||
680.  		 (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) {
681.  	    	c = yn_function("Do you want to add to the current engraving?",
682.  				ynqchars, 'y');
683.  		if (c == 'q') {
684.  		    pline("Never mind.");
685.  		    return(0);
686.  		}
687.  	    }
688.  
689.  	    if (c == 'n' || Blind)
690.  
691.  		if( (oep->engr_type == DUST) || (oep->engr_type == BLOOD) ||
692.  		    (oep->engr_type == MARK) ) {
693.  		    if (!Blind) {
694.  			You("wipe out the message that was %s here.",
695.  			    ((oep->engr_type == DUST)  ? "written in the dust" :
696.  			    ((oep->engr_type == BLOOD) ? "scrawled in blood"   :
697.  							 "written")));
698.  			del_engr(oep);
699.  			oep = (struct engr *)0;
700.  		    } else
701.  		   /* Don't delete engr until after we *know* we're engraving */
702.  			eow = TRUE;
703.  		} else
704.  		    if ( (type == DUST) || (type == MARK) || (type == BLOOD) ) {
705.  			You(
706.  		       "cannot wipe out the message that is %s the floor here.",
707.  		            (oep->engr_type == BURN) ? "burned into" :
708.  			    "engraved in");
709.  			return(1);
710.  		    } else
711.  			if ( (type != oep->engr_type) || (c == 'n') ) {
712.  			    if (!Blind || !Levitation)
713.  				You("will overwrite the current message.");
714.  			    eow = TRUE;
715.  			}
716.  	}
717.  
718.  	switch(type){
719.  	    default:
720.  		everb = (oep && !eow ? "add to the weird writing on" :
721.  				       "write strangely on");
722.  		eloc  = "the floor";
723.  		break;
724.  	    case DUST:
725.  		everb = (oep && !eow ? "add to the writing in" :
726.  				       "write in");
727.  		eloc = "the dust";
728.  		break;
729.  	    case ENGRAVE:
730.  		everb = (oep && !eow ? "add to the engraving in" :
731.  				       "engrave in");
732.  		eloc = "the floor";
733.  		break;
734.  	    case BURN:
735.  		everb = (oep && !eow ? "add to the text burned into" :
736.  				       "burn into");
737.  		eloc = "the floor";
738.  		break;
739.  	    case MARK:
740.  		everb = (oep && !eow ? "add to the graffiti on" :
741.  				       "scribble on");
742.  		eloc = "the floor";
743.  		break;
744.  	    case BLOOD:
745.  		everb = (oep && !eow ? "add to the scrawl on" :
746.  				       "scrawl on");
747.  		eloc = "the floor";
748.  		break;
749.  	}
750.  
751.  	/* Tell adventurer what is going on */
752.  	if (otmp != &zeroobj)
753.  	    You("%s %s with %s.", everb, eloc, doname(otmp));
754.  	else
755.  	    You("%s %s with your %s.", everb, eloc,
756.  		makeplural(body_part(FINGER)));
757.  
758.  	/* Prompt for engraving! */
759.  	Sprintf(qbuf,"What do you want to %s %s here?", everb, eloc);
760.  	getlin(qbuf, ebuf);
761.  	clear_nhwindow(WIN_MESSAGE);
762.  
763.  	/* Mix up engraving if surface or state of mind is unsound.  */
764.  	/* Original kludge by stewr 870708.  modified by njm 910722. */
765.  	for (sp = ebuf; *sp; sp++)
766.  	    if ( ((type == DUST || type == BLOOD) && !rn2(25)) ||
767.  		 (Blind   && !rn2(9)) || (Confusion     && !rn2(12)) ||
768.  		 (Stunned && !rn2(4)) || (Hallucination && !rn2(1)) )
769.  		 *sp = '!' + rn2(93); /* ASCII-code only */
770.  
771.  	/* Count the actual # of chars engraved not including spaces */
772.  	len = strlen(ebuf);
773.  
774.  	for (sp = ebuf, spct = 0; *sp; sp++) if (isspace(*sp)) spct++;
775.  
776.  	if ( (len == spct) || index(ebuf, '\033') ) {
777.  	    if (zapwand) {
778.  		if (!Blind)
779.  		    pline("%s glows, then fades.", The(xname(otmp)));
780.  	    	return(1);
781.  	    } else {
782.  		pline("Never mind.");
783.  		return(0);
784.  	    }
785.  	}
786.  
787.  	len -= spct;
788.  
789.  	/* Previous engraving is overwritten */
790.  	if (eow) {
791.  	    del_engr(oep);
792.  	    oep = (struct engr *)0;
793.  	}
794.  
795.  	/* Figure out how long it took to engrave, and if player has
796.  	 * engraved too much.
797.  	 */
798.  	switch(type){
799.  	    default:
800.  		multi = -(len/10);
801.  		if (multi) nomovemsg = "You finish your weird engraving.";
802.  		break;
803.  	    case DUST:
804.  		multi = -(len/10);
805.  		if (multi) nomovemsg = "You finish writing in the dust.";
806.  		break;
807.  	    case ENGRAVE:
808.  		multi = -(len/10);
809.  		if ((otmp->oclass == WEAPON_CLASS) &&
810.  		    ((otmp->otyp != ATHAME) || otmp->cursed)) {
811.  		    multi = -len;
812.  		    maxelen = ((otmp->spe + 3) * 2) + 1;
813.  			/* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11
814.  			 * Note: this does not allow a +0 anything (except
815.  			 *	 an athame) to engrave "Elbereth" all at once.
816.  			 *	 However, you could now engrave "Elb", then
817.  			 *	 "ere", then "th".
818.  			 */
819.  		    Your("%s dull.", aobjnam(otmp, "get"));
820.  		    if (len > maxelen) {
821.  		    	multi = -maxelen;
822.  			otmp->spe = -3;
823.  		    } else
824.  			if (len > 1) otmp->spe -= len >> 1;
825.  			else otmp->spe -= 1; /* Prevent infinite engraving */
826.  		} else
827.  		    if ( (otmp->oclass == RING_CLASS) ||
828.  			 (otmp->oclass == GEM_CLASS) )
829.  			multi = -len;
830.  		if (multi) nomovemsg = "You finish engraving.";
831.  		break;
832.  	    case BURN:
833.  		multi = -(len/10);
834.  		if (multi)
835.  		    nomovemsg =
836.  			"You finish burning your message into the floor.";
837.  		break;
838.  	    case MARK:
839.  		multi = -(len/10);
840.  		if ((otmp->oclass == TOOL_CLASS) &&
841.  		    (otmp->otyp == MAGIC_MARKER)) {
842.  		    maxelen = (otmp->spe) * 2; /* one charge / 2 letters */
843.  		    if (len > maxelen) {
844.  			Your("marker dries out.");
845.  			otmp->spe = 0;
846.  			multi = -(maxelen/10);
847.  		    } else
848.  			if (len > 1) otmp->spe -= len >> 1;
849.  			else otmp->spe -= 1; /* Prevent infinite grafitti */
850.  		}
851.  		if (multi) nomovemsg = "You finish defacing the dungeon.";
852.  		break;
853.  	    case BLOOD:
854.  		multi = -(len/10);
855.  		if (multi) nomovemsg = "You finish scrawling.";
856.  		break;
857.  	}
858.  
859.  	/* Chop engraving down to size if necessary */
860.  	if (len > maxelen) {
861.  	    for (sp = ebuf; (maxelen && *sp); sp++)
862.  		if (!isspace(*sp)) maxelen--;
863.  	    if (!maxelen && *sp) {
864.  		*sp = (char)0;
865.  		if (multi) nomovemsg = "You cannot write any more.";
866.  		You("only are able to write \"%s\"", ebuf);
867.  	    }
868.  	}
869.  
870.  	/* Add to existing engraving */
871.  	if (oep) Strcpy(buf, oep->engr_txt);	
872.  
873.  	(void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1));
874.  
875.  	make_engr_at(u.ux, u.uy, buf, (moves - multi), type);
876.  
877.  	if (post_engr_text) pline(post_engr_text);
878.  
879.  	if (doblind) {
880.  	    You("are blinded by the flash!");
881.  	    make_blinded((long)rnd(50),FALSE);
882.  	}
883.  
884.  	return(1);
885.  }
886.  
887.  void
888.  save_engravings(fd, mode)
889.  int fd, mode;
890.  {
891.  	register struct engr *ep = head_engr;
892.  	register struct engr *ep2;
893.  #ifdef GCC_WARN
894.  	static long nulls[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
895.  #endif
896.  	while(ep) {
897.  	    ep2 = ep->nxt_engr;
898.  	    if(ep->engr_lth && ep->engr_txt[0]){
899.  		bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
900.  		bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
901.  	    }
902.  	    if (mode & FREE_SAVE)
903.  		dealloc_engr(ep);
904.  	    ep = ep2;
905.  	}
906.  
907.  #ifdef GCC_WARN
908.  	bwrite(fd, (genericptr_t)nulls, sizeof(unsigned));
909.  #else
910.  	bwrite(fd, (genericptr_t)nul, sizeof(unsigned));
911.  #endif
912.  
913.  	if (mode & FREE_SAVE)
914.  	    head_engr = 0;
915.  }
916.  
917.  void
918.  rest_engravings(fd) int fd; {
919.  register struct engr *ep;
920.  unsigned lth;
921.  	head_engr = 0;
922.  	while(1) {
923.  		mread(fd, (genericptr_t) &lth, sizeof(unsigned));
924.  		if(lth == 0) return;
925.  		ep = newengr(lth);
926.  		mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth);
927.  		ep->nxt_engr = head_engr;
928.  		head_engr = ep;
929.  		ep->engr_txt = (char *) (ep + 1);	/* Andreas Bormann */
930.  		/* mark as finished for bones levels -- no problem for
931.  		 * normal levels as the player must have finished engraving
932.  		 * to be able to move again */
933.  		ep->engr_time = moves;
934.  	}
935.  }
936.  
937.  STATIC_OVL void
938.  del_engr(ep) register struct engr *ep; {
939.  register struct engr *ept;
940.  	if(ep == head_engr)
941.  		head_engr = ep->nxt_engr;
942.  	else {
943.  		for(ept = head_engr; ept; ept = ept->nxt_engr) {
944.  			if(ept->nxt_engr == ep) {
945.  				ept->nxt_engr = ep->nxt_engr;
946.  				goto fnd;
947.  			}
948.  		}
949.  		impossible("Error in del_engr?");
950.  		return;
951.  	fnd:	;
952.  	}
953.  	dealloc_engr(ep);
954.  }
955.  
956.  #endif /* OVLB */
957.  
958.  /*engrave.c*/