1    | /*	SCCS Id: @(#)priest.c	3.3	2000/02/19	*/
2    | /* Copyright (c) Izchak Miller, Steve Linhart, 1989.		  */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | #include "mfndpos.h"
7    | #include "eshk.h"
8    | #include "epri.h"
9    | #include "emin.h"
10   | 
11   | #ifdef OVLB
12   | 
13   | STATIC_DCL boolean FDECL(histemple_at,(struct monst *,XCHAR_P,XCHAR_P));
14   | STATIC_DCL boolean FDECL(has_shrine,(struct monst *));
15   | 
16   | /*
17   |  * Move for priests and shopkeepers.  Called from shk_move() and pri_move().
18   |  * Valid returns are  1: moved  0: didn't  -1: let m_move do it  -2: died.
19   |  */
20   | int
21   | move_special(mtmp,in_his_shop,appr,uondoor,avoid,omx,omy,gx,gy)
22   | register struct monst *mtmp;
23   | boolean in_his_shop;
24   | schar appr;
25   | boolean uondoor,avoid;
26   | register xchar omx,omy,gx,gy;
27   | {
28   | 	register xchar nx,ny,nix,niy;
29   | 	register schar i;
30   | 	schar chcnt,cnt;
31   | 	coord poss[9];
32   | 	long info[9];
33   | 	long allowflags;
34   | 	struct obj *ib = (struct obj *)0;
35   | 
36   | 	if(omx == gx && omy == gy)
37   | 		return(0);
38   | 	if(mtmp->mconf) {
39   | 		avoid = FALSE;
40   | 		appr = 0;
41   | 	}
42   | 
43   | 	nix = omx;
44   | 	niy = omy;
45   | 	if (mtmp->isshk) allowflags = ALLOW_SSM;
46   | 	else allowflags = ALLOW_SSM | ALLOW_SANCT;
47   | 	if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL);
48   | 	if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK;
49   | 	if (tunnels(mtmp->data) &&
50   | 		    (!needspick(mtmp->data) || m_carrying(mtmp, PICK_AXE) ||
51   | 		     m_carrying(mtmp, DWARVISH_MATTOCK)))
52   | 		allowflags |= ALLOW_DIG;
53   | 	if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
54   | 		allowflags |= OPENDOOR;
55   | 		if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR;
56   | 	}
57   | 	if (is_giant(mtmp->data)) allowflags |= BUSTDOOR;
58   | 	cnt = mfndpos(mtmp, poss, info, allowflags);
59   | 
60   | 	if(mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */
61   | 		for(i=0; i<cnt; i++)
62   | 		    if(!(info[i] & NOTONL)) goto pick_move;
63   | 		avoid = FALSE;
64   | 	}
65   | 
66   | #define GDIST(x,y)	(dist2(x,y,gx,gy))
67   | pick_move:
68   | 	chcnt = 0;
69   | 	for(i=0; i<cnt; i++) {
70   | 		nx = poss[i].x;
71   | 		ny = poss[i].y;
72   | 		if(levl[nx][ny].typ == ROOM ||
73   | 			(mtmp->ispriest &&
74   | 			    levl[nx][ny].typ == ALTAR) ||
75   | 			(mtmp->isshk &&
76   | 			    (!in_his_shop || ESHK(mtmp)->following))) {
77   | 		    if(avoid && (info[i] & NOTONL))
78   | 			continue;
79   | 		    if((!appr && !rn2(++chcnt)) ||
80   | 			(appr && GDIST(nx,ny) < GDIST(nix,niy))) {
81   | 			    nix = nx;
82   | 			    niy = ny;
83   | 		    }
84   | 		}
85   | 	}
86   | 	if(mtmp->ispriest && avoid &&
87   | 			nix == omx && niy == omy && onlineu(omx,omy)) {
88   | 		/* might as well move closer as long it's going to stay
89   | 		 * lined up */
90   | 		avoid = FALSE;
91   | 		goto pick_move;
92   | 	}
93   | 
94   | 	if(nix != omx || niy != omy) {
95   | 		remove_monster(omx, omy);
96   | 		place_monster(mtmp, nix, niy);
97   | 		newsym(nix,niy);
98   | 		if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
99   | 		    check_special_room(FALSE);
100  | 		if(ib) {
101  | 			if (cansee(mtmp->mx,mtmp->my))
102  | 			    pline("%s picks up %s.", Monnam(mtmp),
103  | 				distant_name(ib,doname));
104  | 			obj_extract_self(ib);
105  | 			(void) mpickobj(mtmp, ib);
106  | 		}
107  | 		return(1);
108  | 	}
109  | 	return(0);
110  | }
111  | 
112  | #endif /* OVLB */
113  | 
114  | #ifdef OVL0
115  | 
116  | char
117  | temple_occupied(array)
118  | register char *array;
119  | {
120  | 	register char *ptr;
121  | 
122  | 	for (ptr = array; *ptr; ptr++)
123  | 		if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE)
124  | 			return(*ptr);
125  | 	return('\0');
126  | }
127  | 
128  | #endif /* OVL0 */
129  | #ifdef OVLB
130  | 
131  | STATIC_OVL boolean
132  | histemple_at(priest, x, y)
133  | register struct monst *priest;
134  | register xchar x, y;
135  | {
136  | 	return((boolean)((EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE)) &&
137  | 	       on_level(&(EPRI(priest)->shrlevel), &u.uz)));
138  | }
139  | 
140  | /*
141  |  * pri_move: return 1: moved  0: didn't  -1: let m_move do it  -2: died
142  |  */
143  | int
144  | pri_move(priest)
145  | register struct monst *priest;
146  | {
147  | 	register xchar gx,gy,omx,omy;
148  | 	schar temple;
149  | 	boolean avoid = TRUE;
150  | 
151  | 	omx = priest->mx;
152  | 	omy = priest->my;
153  | 
154  | 	if(!histemple_at(priest, omx, omy)) return(-1);
155  | 
156  | 	temple = EPRI(priest)->shroom;
157  | 
158  | 	gx = EPRI(priest)->shrpos.x;
159  | 	gy = EPRI(priest)->shrpos.y;
160  | 
161  | 	gx += rn1(3,-1);	/* mill around the altar */
162  | 	gy += rn1(3,-1);
163  | 
164  | 	if(!priest->mpeaceful ||
165  | 	   (Conflict && !resist(priest, RING_CLASS, 0, 0))) {
166  | 		if(monnear(priest, u.ux, u.uy)) {
167  | 			if(Displaced)
168  | 				Your("displaced image doesn't fool %s!",
169  | 					mon_nam(priest));
170  | 			(void) mattacku(priest);
171  | 			return(0);
172  | 		} else if(index(u.urooms, temple)) {
173  | 			/* chase player if inside temple & can see him */
174  | 			if(priest->mcansee && m_canseeu(priest)) {
175  | 				gx = u.ux;
176  | 				gy = u.uy;
177  | 			}
178  | 			avoid = FALSE;
179  | 		}
180  | 	} else if(Invis) avoid = FALSE;
181  | 
182  | 	return(move_special(priest,FALSE,TRUE,FALSE,avoid,omx,omy,gx,gy));
183  | }
184  | 
185  | /* exclusively for mktemple() */
186  | void
187  | priestini(lvl, sroom, sx, sy, sanctum)
188  | d_level	*lvl;
189  | struct mkroom *sroom;
190  | int sx, sy;
191  | boolean sanctum;   /* is it the seat of the high priest? */
192  | {
193  | 	register struct monst *priest;
194  | 	register struct obj *otmp;
195  | 	register int cnt;
196  | 
197  | 	if(MON_AT(sx+1, sy))
198  | 		rloc(m_at(sx+1, sy)); /* insurance */
199  | 
200  | 	priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST],
201  | 			 sx + 1, sy, NO_MM_FLAGS);
202  | 	if (priest) {
203  | 		EPRI(priest)->shroom = (sroom - rooms) + ROOMOFFSET;
204  | 		EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask);
205  | 		EPRI(priest)->shrpos.x = sx;
206  | 		EPRI(priest)->shrpos.y = sy;
207  | 		assign_level(&(EPRI(priest)->shrlevel), lvl);
208  | 		priest->mtrapseen = ~0;	/* traps are known */
209  | 		priest->mpeaceful = 1;
210  | 		priest->ispriest = 1;
211  | 		priest->msleeping = 0;
212  | 		set_malign(priest); /* mpeaceful may have changed */
213  | 
214  | 		/* now his/her goodies... */
215  | 		if(sanctum && EPRI(priest)->shralign == A_NONE &&
216  | 		     on_level(&sanctum_level, &u.uz)) {
217  | 			(void) mongets(priest, AMULET_OF_YENDOR);
218  | 		}
219  | 		/* Do NOT put the rest in m_initinv.    */
220  | 		/* Priests created elsewhere than in a  */
221  | 		/* temple should not carry these items, */
222  | 		cnt = rn1(2,3);
223  | 		while(cnt) {
224  | 		    otmp = mkobj(SPBOOK_CLASS, FALSE);
225  | 		    if(otmp) (void) mpickobj(priest, otmp);
226  | 		    cnt--;
227  | 		}
228  | 		if(p_coaligned(priest))
229  | 		    (void) mongets(priest, ROBE);
230  | 		else {
231  | 		    otmp = mksobj(ROBE, TRUE, FALSE);
232  | 		    if(otmp) {
233  | 			if(!rn2(2)) curse(otmp);
234  | 			(void) mpickobj(priest, otmp);
235  | 		    }
236  | 		}
237  | 		m_dowear(priest, TRUE);
238  | 	}
239  | }
240  | 
241  | /*
242  |  * Specially aligned monsters are named specially.
243  |  *	- aligned priests with ispriest and high priests have shrines
244  |  *		they retain ispriest and epri when polymorphed
245  |  *	- aligned priests without ispriest and Angels are roamers
246  |  *		they retain isminion and access epri as emin when polymorphed
247  |  *		(coaligned Angels are also created as minions, but they
248  |  *		use the same naming convention)
249  |  *	- minions do not have ispriest but have isminion and emin
250  |  *	- caller needs to inhibit Hallucination if it wants to force
251  |  *		the true name even when under that influence
252  |  */
253  | char *
254  | priestname(mon, pname)
255  | register struct monst *mon;
256  | char *pname;		/* caller-supplied output buffer */
257  | {
258  | 	const char *what = Hallucination ? rndmonnam() : mon->data->mname;
259  | 
260  | 	Strcpy(pname, "the ");
261  | 	if (mon->minvis) Strcat(pname, "invisible ");
262  | 	if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] ||
263  | 					mon->data == &mons[PM_ANGEL]) {
264  | 		/* use epri */
265  | 		if (mon->mtame && mon->data == &mons[PM_ANGEL])
266  | 			Strcat(pname, "guardian ");
267  | 		if (mon->data != &mons[PM_ALIGNED_PRIEST] &&
268  | 				mon->data != &mons[PM_HIGH_PRIEST]) {
269  | 			Strcat(pname, what);
270  | 			Strcat(pname, " ");
271  | 		}
272  | 		if (mon->data != &mons[PM_ANGEL]) {
273  | 			if (!mon->ispriest && EPRI(mon)->renegade)
274  | 				Strcat(pname, "renegade ");
275  | 			if (mon->data == &mons[PM_HIGH_PRIEST])
276  | 				Strcat(pname, "high ");
277  | 			if (Hallucination)
278  | 				Strcat(pname, "poohbah ");
279  | 			else if (mon->female)
280  | 				Strcat(pname, "priestess ");
281  | 			else
282  | 				Strcat(pname, "priest ");
283  | 		}
284  | 		Strcat(pname, "of ");
285  | 		Strcat(pname, halu_gname((int)EPRI(mon)->shralign));
286  | 		return(pname);
287  | 	}
288  | 	/* use emin instead of epri */
289  | 	Strcat(pname, what);
290  | 	Strcat(pname, " of ");
291  | 	Strcat(pname, halu_gname(EMIN(mon)->min_align));
292  | 	return(pname);
293  | }
294  | 
295  | boolean
296  | p_coaligned(priest)
297  | struct monst *priest;
298  | {
299  | 	return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign)));
300  | }
301  | 
302  | STATIC_OVL boolean
303  | has_shrine(pri)
304  | struct monst *pri;
305  | {
306  | 	struct rm *lev;
307  | 
308  | 	if(!pri)
309  | 		return(FALSE);
310  | 	lev = &levl[EPRI(pri)->shrpos.x][EPRI(pri)->shrpos.y];
311  | 	if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE))
312  | 		return(FALSE);
313  | 	return((boolean)(EPRI(pri)->shralign == Amask2align(lev->altarmask & ~AM_SHRINE)));
314  | }
315  | 
316  | struct monst *
317  | findpriest(roomno)
318  | char roomno;
319  | {
320  | 	register struct monst *mtmp;
321  | 
322  | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
323  | 	    if (DEADMONSTER(mtmp)) continue;
324  | 	    if(mtmp->ispriest && (EPRI(mtmp)->shroom == roomno) &&
325  | 	       histemple_at(mtmp,mtmp->mx,mtmp->my))
326  | 		return(mtmp);
327  | 	}
328  | 	return (struct monst *)0;
329  | }
330  | 
331  | /* called from check_special_room() when the player enters the temple room */
332  | void
333  | intemple(roomno)
334  | register int roomno;
335  | {
336  | 	register struct monst *priest = findpriest((char)roomno);
337  | 	boolean tended = (priest != (struct monst *)0);
338  | 	boolean shrined, sanctum, can_speak;
339  | 	const char *msg1, *msg2;
340  | 	char buf[BUFSZ];
341  | 
342  | 	if(!temple_occupied(u.urooms0)) {
343  | 	    if(tended) {
344  | 		shrined = has_shrine(priest);
345  | 		sanctum = (priest->data == &mons[PM_HIGH_PRIEST] &&
346  | 			   (Is_sanctum(&u.uz) || In_endgame(&u.uz)));
347  | 		can_speak = (priest->mcanmove && !priest->msleeping);
348  | 		if (can_speak)
349  | 		    pline("%s intones:",
350  | 			  (!Blind ? Monnam(priest) : "A nearby voice"));
351  | 		msg2 = 0;
352  | 		if(sanctum && Is_sanctum(&u.uz)) {
353  | 		    if(priest->mpeaceful) {
354  | 			msg1 = "Infidel, you entered Moloch's Sanctum!";
355  | 			msg2 = "Be gone!";
356  | 			priest->mpeaceful = 0;
357  | 			set_malign(priest);
358  | 		    } else
359  | 			msg1 = "You desecrate this place by your presence!";
360  | 		} else {
361  | 		    Sprintf(buf, "Pilgrim, you enter a %s place!",
362  | 			    !shrined ? "desecrated" : "sacred");
363  | 		    msg1 = buf;
364  | 		}
365  | 		if (can_speak) {
366  | 		    verbalize(msg1);
367  | 		    if (msg2) verbalize(msg2);
368  | 		}
369  | 		if(!sanctum) {
370  | 		    /* !tended -> !shrined */
371  | 		    if(!shrined || !p_coaligned(priest) ||
372  | 						   u.ualign.record < -5)
373  | 			You("have a%s forbidding feeling...",
374  | 				(!shrined) ? "" : " strange");
375  | 		    else You("experience a strange sense of peace.");
376  | 		}
377  | 	    } else {
378  | 		switch(rn2(3)) {
379  | 		  case 0: You("have an eerie feeling..."); break;
380  | 		  case 1: You_feel("like you are being watched."); break;
381  | 		  default: pline("A shiver runs down your %s.",
382  | 			body_part(SPINE)); break;
383  | 		}
384  | 		if(!rn2(5)) {
385  | 		    struct monst *mtmp;
386  | 
387  | 		    if(!(mtmp = makemon(&mons[PM_GHOST],u.ux,u.uy,NO_MM_FLAGS)))
388  | 			return;
389  | 		    pline("An enormous ghost appears next to you!");
390  | 		    mtmp->mpeaceful = 0;
391  | 		    set_malign(mtmp);
392  | 		    if(flags.verbose)
393  | 			You("are frightened to death, and unable to move.");
394  | 		    nomul(-3);
395  | 		    nomovemsg = "You regain your composure.";
396  | 	       }
397  | 	   }
398  |        }
399  | }
400  | 
401  | void
402  | priest_talk(priest)
403  | register struct monst *priest;
404  | {
405  | 	boolean coaligned = p_coaligned(priest);
406  | 	boolean strayed = (u.ualign.record < 0);
407  | 
408  | 
409  | 	/* KMH, conduct */
410  | 	u.uconduct.gnostic++;
411  | 
412  | 	if(priest->mflee || (!priest->ispriest && coaligned && strayed)) {
413  | 	    pline("%s doesn't want anything to do with you!",
414  | 				Monnam(priest));
415  | 	    priest->mpeaceful = 0;
416  | 	    return;
417  | 	}
418  | 
419  | 	/* priests don't chat unless peaceful and in their own temple */
420  | 	if(!histemple_at(priest,priest->mx,priest->my) ||
421  | 		 !priest->mpeaceful || !priest->mcanmove || priest->msleeping) {
422  | 	    static const char *cranky_msg[3] = {
423  | 		"Thou wouldst have words, eh?  I'll give thee a word or two!",
424  | 		"Talk?  Here is what I have to say!",
425  | 		"Pilgrim, I would speak no longer with thee."
426  | 	    };
427  | 
428  | 	    if(!priest->mcanmove || priest->msleeping) {
429  | 		pline("%s breaks out of %s reverie!",
430  | 		      Monnam(priest), his[pronoun_gender(priest)]);
431  | 		priest->mfrozen = priest->msleeping = 0;
432  | 		priest->mcanmove = 1;
433  | 	    }
434  | 	    priest->mpeaceful = 0;
435  | 	    verbalize(cranky_msg[rn2(3)]);
436  | 	    return;
437  | 	}
438  | 
439  | 	/* you desecrated the temple and now you want to chat? */
440  | 	if(priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE) &&
441  | 		  !has_shrine(priest)) {
442  | 	    verbalize("Begone!  Thou desecratest this holy place with thy presence.");
443  | 	    priest->mpeaceful = 0;
444  | 	    return;
445  | 	}
446  | 
447  | 	if(!u.ugold) {
448  | 	    if(coaligned && !strayed) {
449  | 		if (priest->mgold > 0L) {
450  | 		    /* Note: two bits is actually 25 cents.  Hmm. */
451  | 		    pline("%s gives you %s for an ale.", Monnam(priest),
452  | 			(priest->mgold == 1L) ? "one bit" : "two bits");
453  | 		    if (priest->mgold > 1L)
454  | 			u.ugold = 2L;
455  | 		    else
456  | 			u.ugold = 1L;
457  | 		    priest->mgold -= u.ugold;
458  | 		    flags.botl = 1;
459  | 		} else
460  | 		    pline("%s preaches the virtues of poverty.", Monnam(priest));
461  | 		exercise(A_WIS, TRUE);
462  | 	    } else
463  | 		pline("%s is not interested.", Monnam(priest));
464  | 	    return;
465  | 	} else {
466  | 	    long offer;
467  | 
468  | 	    pline("%s asks you for a contribution for the temple.",
469  | 			Monnam(priest));
470  | 	    if((offer = bribe(priest)) == 0) {
471  | 		verbalize("Thou shalt regret thine action!");
472  | 		if(coaligned) adjalign(-1);
473  | 	    } else if(offer < (u.ulevel * 200)) {
474  | 		if(u.ugold > (offer * 2L)) verbalize("Cheapskate.");
475  | 		else {
476  | 		    verbalize("I thank thee for thy contribution.");
477  | 		    /*  give player some token  */
478  | 		    exercise(A_WIS, TRUE);
479  | 		}
480  | 	    } else if(offer < (u.ulevel * 400)) {
481  | 		verbalize("Thou art indeed a pious individual.");
482  | 		if(u.ugold < (offer * 2L)) {
483  | 		    if(coaligned && u.ualign.record < -5) adjalign(1);
484  | 		    verbalize("I bestow upon thee a blessing.");
485  | 		    incr_itimeout(&HClairvoyant, rn1(500,500));
486  | 		}
487  | 	    } else if(offer < (u.ulevel * 600) &&
488  | 		      u.ublessed < 20 &&
489  | 		      (u.ublessed < 9 || !rn2(u.ublessed))) {
490  | 		verbalize("Thy devotion has been rewarded.");
491  | 		if (!(HProtection & INTRINSIC))  {
492  | 			HProtection |= FROMOUTSIDE;
493  | 			if (!u.ublessed)  u.ublessed = rn1(3, 2);
494  | 		} else u.ublessed++;
495  | 	    } else {
496  | 		verbalize("Thy selfless generosity is deeply appreciated.");
497  | 		if(u.ugold < (offer * 2L) && coaligned) {
498  | 		    if(strayed && (moves - u.ucleansed) > 5000L) {
499  | 			u.ualign.record = 0; /* cleanse thee */
500  | 			u.ucleansed = moves;
501  | 		    } else {
502  | 			adjalign(2);
503  | 		    }
504  | 		}
505  | 	    }
506  | 	}
507  | }
508  | 
509  | struct monst *
510  | mk_roamer(ptr, alignment, x, y, peaceful)
511  | register struct permonst *ptr;
512  | aligntyp alignment;
513  | xchar x, y;
514  | boolean peaceful;
515  | {
516  | 	register struct monst *roamer;
517  | 	register boolean coaligned = (u.ualign.type == alignment);
518  | 
519  | 	if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL])
520  | 		return((struct monst *)0);
521  | 	
522  | 	if (MON_AT(x, y)) rloc(m_at(x, y));	/* insurance */
523  | 
524  | 	if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS)))
525  | 		return((struct monst *)0);
526  | 
527  | 	EPRI(roamer)->shralign = alignment;
528  | 	if (coaligned && !peaceful)
529  | 		EPRI(roamer)->renegade = TRUE;
530  | 	/* roamer->ispriest == FALSE naturally */
531  | 	roamer->isminion = TRUE;	/* borrowing this bit */
532  | 	roamer->mtrapseen = ~0;		/* traps are known */
533  | 	roamer->mpeaceful = peaceful;
534  | 	roamer->msleeping = 0;
535  | 	set_malign(roamer); /* peaceful may have changed */
536  | 
537  | 	/* MORE TO COME */
538  | 	return(roamer);
539  | }
540  | 
541  | void
542  | reset_hostility(roamer)
543  | register struct monst *roamer;
544  | {
545  | 	if(!(roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] ||
546  | 				  roamer->data == &mons[PM_ANGEL])))
547  | 	        return;
548  | 
549  | 	if(EPRI(roamer)->shralign != u.ualign.type) {
550  | 	    roamer->mpeaceful = roamer->mtame = 0;
551  | 	    set_malign(roamer);
552  | 	}
553  | 	newsym(roamer->mx, roamer->my);
554  | }
555  | 
556  | boolean
557  | in_your_sanctuary(mon, x, y)
558  | struct monst *mon;	/* if non-null, <mx,my> overrides <x,y> */
559  | xchar x, y;
560  | {
561  | 	register char roomno;
562  | 	register struct monst *priest;
563  | 
564  | 	if (mon) {
565  | 	    if (is_minion(mon->data) || is_rider(mon->data)) return FALSE;
566  | 	    x = mon->mx, y = mon->my;
567  | 	}
568  | 	if (u.ualign.record < -3)		/* sinned or worse */
569  | 	    return FALSE;
570  | 	if ((roomno = temple_occupied(u.urooms)) == 0 ||
571  | 		roomno != *in_rooms(x, y, TEMPLE))
572  | 	    return FALSE;
573  | 	if ((priest = findpriest(roomno)) == 0)
574  | 	    return FALSE;
575  | 	return (boolean)(has_shrine(priest) &&
576  | 			 p_coaligned(priest) &&
577  | 			 priest->mpeaceful);
578  | }
579  | 
580  | void
581  | ghod_hitsu(priest)	/* when attacking "priest" in his temple */
582  | struct monst *priest;
583  | {
584  | 	int x, y, ax, ay, roomno = (int)temple_occupied(u.urooms);
585  | 	struct mkroom *troom;
586  | 
587  | 	if (!roomno || !has_shrine(priest))
588  | 		return;
589  | 
590  | 	ax = x = EPRI(priest)->shrpos.x;
591  | 	ay = y = EPRI(priest)->shrpos.y;
592  | 	troom = &rooms[roomno - ROOMOFFSET];
593  | 
594  | 	if((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y)) {
595  | 	    if(IS_DOOR(levl[u.ux][u.uy].typ)) {
596  | 
597  | 		if(u.ux == troom->lx - 1) {
598  | 		    x = troom->hx;
599  | 		    y = u.uy;
600  | 		} else if(u.ux == troom->hx + 1) {
601  | 		    x = troom->lx;
602  | 		    y = u.uy;
603  | 		} else if(u.uy == troom->ly - 1) {
604  | 		    x = u.ux;
605  | 		    y = troom->hy;
606  | 		} else if(u.uy == troom->hy + 1) {
607  | 		    x = u.ux;
608  | 		    y = troom->ly;
609  | 		}
610  | 	    } else {
611  | 		switch(rn2(4)) {
612  | 		case 0:  x = u.ux; y = troom->ly; break;
613  | 		case 1:  x = u.ux; y = troom->hy; break;
614  | 		case 2:  x = troom->lx; y = u.uy; break;
615  | 		default: x = troom->hx; y = u.uy; break;
616  | 		}
617  | 	    }
618  | 	    if(!linedup(u.ux, u.uy, x, y)) return;
619  | 	}
620  | 
621  | 	switch(rn2(3)) {
622  | 	case 0:
623  | 	    pline("%s roars in anger:  \"Thou shalt suffer!\"",
624  | 			a_gname_at(ax, ay));
625  | 	    break;
626  | 	case 1:
627  | 	    pline("%s voice booms:  \"How darest thou harm my servant!\"",
628  | 			s_suffix(a_gname_at(ax, ay)));
629  | 	    break;
630  | 	default:
631  | 	    pline("%s roars:  \"Thou dost profane my shrine!\"",
632  | 			a_gname_at(ax, ay));
633  | 	    break;
634  | 	}
635  | 
636  | 	buzz(-10-(AD_ELEC-1), 6, x, y, sgn(tbx), sgn(tby)); /* bolt of lightning */
637  | 	exercise(A_WIS, FALSE);
638  | }
639  | 
640  | void
641  | angry_priest()
642  | {
643  | 	register struct monst *priest;
644  | 	struct rm *lev;
645  | 
646  | 	if ((priest = findpriest(temple_occupied(u.urooms))) != 0) {
647  | 	    wakeup(priest);
648  | 	    /*
649  | 	     * If the altar has been destroyed or converted, let the
650  | 	     * priest run loose.
651  | 	     * (When it's just a conversion and there happens to be
652  | 	     *	a fresh corpse nearby, the priest ought to have an
653  | 	     *	opportunity to try converting it back; maybe someday...)
654  | 	     */
655  | 	    lev = &levl[EPRI(priest)->shrpos.x][EPRI(priest)->shrpos.y];
656  | 	    if (!IS_ALTAR(lev->typ) ||
657  | 		((aligntyp)Amask2align(lev->altarmask & AM_MASK) !=
658  | 			EPRI(priest)->shralign)) {
659  | 		priest->ispriest = 0;		/* now a roamer */
660  | 		priest->isminion = 1;		/* but still aligned */
661  | 		/* this overloads the `shroom' field, which is now clobbered */
662  | 		EPRI(priest)->renegade = 0;
663  | 	    }
664  | 	}
665  | }
666  | 
667  | /*
668  |  * When saving bones, find priests that aren't on their shrine level,
669  |  * and remove them.   This avoids big problems when restoring bones.
670  |  */
671  | void
672  | clearpriests()
673  | {
674  |     register struct monst *mtmp, *mtmp2;
675  | 
676  |     for(mtmp = fmon; mtmp; mtmp = mtmp2) {
677  | 	mtmp2 = mtmp->nmon;
678  | 	if (!DEADMONSTER(mtmp) && mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz))
679  | 	    mongone(mtmp);
680  |     }
681  | }
682  | 
683  | /* munge priest-specific structure when restoring -dlc */
684  | void
685  | restpriest(mtmp, ghostly)
686  | register struct monst *mtmp;
687  | boolean ghostly;
688  | {
689  |     if(u.uz.dlevel) {
690  | 	if (ghostly)
691  | 	    assign_level(&(EPRI(mtmp)->shrlevel), &u.uz);
692  |     }
693  | }
694  | 
695  | #endif /* OVLB */
696  | 
697  | /*priest.c*/