Source:NetHack 3.2.0/engrave.c

Below is the full text to engrave.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.0/engrave.c#line123 ]], for example.

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

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