1/*	SCCS Id: @(#)wizard.c	3.4	2003/02/18	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5/* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */
6/*	       - heavily modified to give the wiz balls.  (genat!mike)   */
7/*	       - dewimped and given some maledictions. -3. */
8/*	       - generalized for 3.1 (mike@bullns.on01.bull.ca) */
9
10#include "hack.h"
11#include "qtext.h"
12#include "epri.h"
13
14extern const int monstr[];
15
16#ifdef OVLB
17
18STATIC_DCL short FDECL(which_arti, (int));
19STATIC_DCL boolean FDECL(mon_has_arti, (struct monst *,SHORT_P));
20STATIC_DCL struct monst *FDECL(other_mon_has_arti, (struct monst *,SHORT_P));
21STATIC_DCL struct obj *FDECL(on_ground, (SHORT_P));
22STATIC_DCL boolean FDECL(you_have, (int));
23STATIC_DCL long FDECL(target_on, (int,struct monst *));
24STATIC_DCL long FDECL(strategy, (struct monst *));
25
26static NEARDATA const int nasties[] = {
27	PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON,
28	PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM,
29	PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD,
30	PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON,
31	PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT,
32	PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER,
33	PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING,
34	PM_OLOG_HAI, PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME,
35	PM_DISENCHANTER
36	};
37
38static NEARDATA const unsigned wizapp[] = {
39	PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE,
40	PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK,
41	PM_XORN, PM_XAN, PM_COCKATRICE,
42	PM_FLOATING_EYE,
43	PM_GUARDIAN_NAGA,
44	PM_TRAPPER
45};
46
47#endif /* OVLB */
48#ifdef OVL0
49
50/* If you've found the Amulet, make the Wizard appear after some time */
51/* Also, give hints about portal locations, if amulet is worn/wielded -dlc */
52void
53amulet()
54{
55	struct monst *mtmp;
56	struct trap *ttmp;
57	struct obj *amu;
58
59#if 0		/* caller takes care of this check */
60	if (!u.uhave.amulet)
61		return;
62#endif
63	if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) ||
64	     ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR))
65	    && !rn2(15)) {
66	    for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
67		if(ttmp->ttyp == MAGIC_PORTAL) {
68		    int du = distu(ttmp->tx, ttmp->ty);
69		    if (du <= 9)
70			pline("%s hot!", Tobjnam(amu, "feel"));
71		    else if (du <= 64)
72			pline("%s very warm.", Tobjnam(amu, "feel"));
73		    else if (du <= 144)
74			pline("%s warm.", Tobjnam(amu, "feel"));
75		    /* else, the amulet feels normal */
76		    break;
77		}
78	    }
79	}
80
81	if (!flags.no_of_wizards)
82		return;
83	/* find Wizard, and wake him if necessary */
84	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
85	    if (!DEADMONSTER(mtmp) && mtmp->iswiz && mtmp->msleeping && !rn2(40)) {
86		mtmp->msleeping = 0;
87		if (distu(mtmp->mx,mtmp->my) > 2)
88		    You(
89    "get the creepy feeling that somebody noticed your taking the Amulet."
90		    );
91		return;
92	    }
93}
94
95#endif /* OVL0 */
96#ifdef OVLB
97
98int
99mon_has_amulet(mtmp)
100register struct monst *mtmp;
101{
102	register struct obj *otmp;
103
104	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
105		if(otmp->otyp == AMULET_OF_YENDOR) return(1);
106	return(0);
107}
108
109int
110mon_has_special(mtmp)
111register struct monst *mtmp;
112{
113	register struct obj *otmp;
114
115	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
116		if(otmp->otyp == AMULET_OF_YENDOR ||
117			is_quest_artifact(otmp) ||
118			otmp->otyp == BELL_OF_OPENING ||
119			otmp->otyp == CANDELABRUM_OF_INVOCATION ||
120			otmp->otyp == SPE_BOOK_OF_THE_DEAD) return(1);
121	return(0);
122}
123
124/*
125 *	New for 3.1  Strategy / Tactics for the wiz, as well as other
126 *	monsters that are "after" something (defined via mflag3).
127 *
128 *	The strategy section decides *what* the monster is going
129 *	to attempt, the tactics section implements the decision.
130 */
131#define STRAT(w, x, y, typ) (w | ((long)(x)<<16) | ((long)(y)<<8) | (long)typ)
132
133#define M_Wants(mask)	(mtmp->data->mflags3 & (mask))
134
135STATIC_OVL short
136which_arti(mask)
137	register int mask;
138{
139	switch(mask) {
140	    case M3_WANTSAMUL:	return(AMULET_OF_YENDOR);
141	    case M3_WANTSBELL:	return(BELL_OF_OPENING);
142	    case M3_WANTSCAND:	return(CANDELABRUM_OF_INVOCATION);
143	    case M3_WANTSBOOK:	return(SPE_BOOK_OF_THE_DEAD);
144	    default:		break;	/* 0 signifies quest artifact */
145	}
146	return(0);
147}
148
149/*
150 *	If "otyp" is zero, it triggers a check for the quest_artifact,
151 *	since bell, book, candle, and amulet are all objects, not really
152 *	artifacts right now.	[MRS]
153 */
154STATIC_OVL boolean
155mon_has_arti(mtmp, otyp)
156	register struct monst *mtmp;
157	register short	otyp;
158{
159	register struct obj *otmp;
160
161	for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) {
162	    if(otyp) {
163		if(otmp->otyp == otyp)
164			return(1);
165	    }
166	     else if(is_quest_artifact(otmp)) return(1);
167	}
168	return(0);
169
170}
171
172STATIC_OVL struct monst *
173other_mon_has_arti(mtmp, otyp)
174	register struct monst *mtmp;
175	register short	otyp;
176{
177	register struct monst *mtmp2;
178
179	for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon)
180	    /* no need for !DEADMONSTER check here since they have no inventory */
181	    if(mtmp2 != mtmp)
182		if(mon_has_arti(mtmp2, otyp)) return(mtmp2);
183
184	return((struct monst *)0);
185}
186
187STATIC_OVL struct obj *
188on_ground(otyp)
189	register short	otyp;
190{
191	register struct obj *otmp;
192
193	for (otmp = fobj; otmp; otmp = otmp->nobj)
194	    if (otyp) {
195		if (otmp->otyp == otyp)
196		    return(otmp);
197	    } else if (is_quest_artifact(otmp))
198		return(otmp);
199	return((struct obj *)0);
200}
201
202STATIC_OVL boolean
203you_have(mask)
204	register int mask;
205{
206	switch(mask) {
207	    case M3_WANTSAMUL:	return(boolean)(u.uhave.amulet);
208	    case M3_WANTSBELL:	return(boolean)(u.uhave.bell);
209	    case M3_WANTSCAND:	return(boolean)(u.uhave.menorah);
210	    case M3_WANTSBOOK:	return(boolean)(u.uhave.book);
211	    case M3_WANTSARTI:	return(boolean)(u.uhave.questart);
212	    default:		break;
213	}
214	return(0);
215}
216
217STATIC_OVL long
218target_on(mask, mtmp)
219	register int mask;
220	register struct monst *mtmp;
221{
222	register short	otyp;
223	register struct obj *otmp;
224	register struct monst *mtmp2;
225
226	if(!M_Wants(mask))	return(STRAT_NONE);
227
228	otyp = which_arti(mask);
229	if(!mon_has_arti(mtmp, otyp)) {
230	    if(you_have(mask))
231		return(STRAT(STRAT_PLAYER, u.ux, u.uy, mask));
232	    else if((otmp = on_ground(otyp)))
233		return(STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask));
234	    else if((mtmp2 = other_mon_has_arti(mtmp, otyp)))
235		return(STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask));
236	}
237	return(STRAT_NONE);
238}
239
240STATIC_OVL long
241strategy(mtmp)
242	register struct monst *mtmp;
243{
244	long strat, dstrat;
245
246	if (!is_covetous(mtmp->data) ||
247		/* perhaps a shopkeeper has been polymorphed into a master
248		   lich; we don't want it teleporting to the stairs to heal
249		   because that will leave its shop untended */
250		(mtmp->isshk && inhishop(mtmp)))
251	    return STRAT_NONE;
252
253	switch((mtmp->mhp*3)/mtmp->mhpmax) {	/* 0-3 */
254
255	   default:
256	    case 0:	/* panic time - mtmp is almost snuffed */
257			return(STRAT_HEAL);
258
259	    case 1:	/* the wiz is less cautious */
260			if(mtmp->data != &mons[PM_WIZARD_OF_YENDOR])
261			    return(STRAT_HEAL);
262			/* else fall through */
263
264	    case 2:	dstrat = STRAT_HEAL;
265			break;
266
267	    case 3:	dstrat = STRAT_NONE;
268			break;
269	}
270
271	if(flags.made_amulet)
272	    if((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE)
273		return(strat);
274
275	if(u.uevent.invoked) {		/* priorities change once gate opened */
276
277	    if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE)
278		return(strat);
279	    if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE)
280		return(strat);
281	    if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE)
282		return(strat);
283	    if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE)
284		return(strat);
285	} else {
286
287	    if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE)
288		return(strat);
289	    if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE)
290		return(strat);
291	    if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE)
292		return(strat);
293	    if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE)
294		return(strat);
295	}
296	return(dstrat);
297}
298
299int
300tactics(mtmp)
301	register struct monst *mtmp;
302{
303	long strat = strategy(mtmp);
304
305	mtmp->mstrategy = (mtmp->mstrategy & STRAT_WAITMASK) | strat;
306
307	switch (strat) {
308	    case STRAT_HEAL:	/* hide and recover */
309		/* if wounded, hole up on or near the stairs (to block them) */
310		/* unless, of course, there are no stairs (e.g. endlevel) */
311		mtmp->mavenge = 1; /* covetous monsters attack while fleeing */
312		if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) ||
313			(mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) {
314		    if (!rn2(3 + mtmp->mhp/10)) (void) rloc(mtmp, FALSE);
315		} else if (xupstair &&
316			 (mtmp->mx != xupstair || mtmp->my != yupstair)) {
317		    (void) mnearto(mtmp, xupstair, yupstair, TRUE);
318		}
319		/* if you're not around, cast healing spells */
320		if (distu(mtmp->mx,mtmp->my) > (BOLT_LIM * BOLT_LIM))
321		    if(mtmp->mhp <= mtmp->mhpmax - 8) {
322			mtmp->mhp += rnd(8);
323			return(1);
324		    }
325		/* fall through :-) */
326
327	    case STRAT_NONE:	/* harrass */
328		if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp);
329		return(0);
330
331	    default:		/* kill, maim, pillage! */
332	    {
333		long  where = (strat & STRAT_STRATMASK);
334		xchar tx = STRAT_GOALX(strat),
335		      ty = STRAT_GOALY(strat);
336		int   targ = strat & STRAT_GOAL;
337		struct obj *otmp;
338
339		if(!targ) { /* simply wants you to close */
340		    return(0);
341		}
342		if((u.ux == tx && u.uy == ty) || where == STRAT_PLAYER) {
343		    /* player is standing on it (or has it) */
344		    mnexto(mtmp);
345		    return(0);
346		}
347		if(where == STRAT_GROUND) {
348		    if(!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) {
349			/* teleport to it and pick it up */
350			rloc_to(mtmp, tx, ty);	/* clean old pos */
351
352			if ((otmp = on_ground(which_arti(targ))) != 0) {
353			    if (cansee(mtmp->mx, mtmp->my))
354				pline("%s picks up %s.",
355				    Monnam(mtmp),
356				    (distu(mtmp->mx, mtmp->my) <= 5) ?
357				     doname(otmp) : distant_name(otmp, doname));
358			    obj_extract_self(otmp);
359			    (void) mpickobj(mtmp, otmp);
360			    return(1);
361			} else return(0);
362		    } else {
363			/* a monster is standing on it - cause some trouble */
364			if (!rn2(5)) mnexto(mtmp);
365			return(0);
366		    }
367	        } else { /* a monster has it - 'port beside it. */
368		    (void) mnearto(mtmp, tx, ty, FALSE);
369		    return(0);
370		}
371	    }
372	}
373	/*NOTREACHED*/
374	return(0);
375}
376
377void
378aggravate()
379{
380	register struct monst *mtmp;
381
382	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
383	    if (!DEADMONSTER(mtmp)) {
384		mtmp->msleeping = 0;
385		if(!mtmp->mcanmove && !rn2(5)) {
386			mtmp->mfrozen = 0;
387			mtmp->mcanmove = 1;
388		}
389	    }
390}
391
392void
393clonewiz()
394{
395	register struct monst *mtmp2;
396
397	if ((mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR],
398				u.ux, u.uy, NO_MM_FLAGS)) != 0) {
399	    mtmp2->msleeping = mtmp2->mtame = mtmp2->mpeaceful = 0;
400	    if (!u.uhave.amulet && rn2(2)) {  /* give clone a fake */
401		(void) add_to_minv(mtmp2, mksobj(FAKE_AMULET_OF_YENDOR,
402					TRUE, FALSE));
403	    }
404	    mtmp2->m_ap_type = M_AP_MONSTER;
405	    mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))];
406	    newsym(mtmp2->mx,mtmp2->my);
407	}
408}
409
410/* also used by newcham() */
411int
412pick_nasty()
413{
414    /* To do?  Possibly should filter for appropriate forms when
415       in the elemental planes or surrounded by water or lava. */
416    return nasties[rn2(SIZE(nasties))];
417}
418
419/* create some nasty monsters, aligned or neutral with the caster */
420/* a null caster defaults to a chaotic caster (e.g. the wizard) */
421int
422nasty(mcast)
423	struct monst *mcast;
424{
425    register struct monst	*mtmp;
426    register int	i, j, tmp;
427    int castalign = (mcast ? mcast->data->maligntyp : -1);
428    coord bypos;
429    int count=0;
430
431    if(!rn2(10) && Inhell) {
432	msummon((struct monst *) 0);	/* summons like WoY */
433	count++;
434    } else {
435	tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */
436	/* if we don't have a casting monster, the nasties appear around you */
437	bypos.x = u.ux;
438	bypos.y = u.uy;
439	for(i = rnd(tmp); i > 0; --i)
440	    for(j=0; j<20; j++) {
441		int makeindex;
442
443		/* Don't create more spellcasters of the monsters' level or
444		 * higher--avoids chain summoners filling up the level.
445		 */
446		do {
447		    makeindex = pick_nasty();
448		} while(mcast && attacktype(&mons[makeindex], AT_MAGC) &&
449			monstr[makeindex] >= monstr[mcast->mnum]);
450		/* do this after picking the monster to place */
451		if (mcast &&
452		    !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex]))
453		    continue;
454		if ((mtmp = makemon(&mons[makeindex],
455				    bypos.x, bypos.y, NO_MM_FLAGS)) != 0) {
456		    mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0;
457		    set_malign(mtmp);
458		} else /* GENOD? */
459		    mtmp = makemon((struct permonst *)0,
460					bypos.x, bypos.y, NO_MM_FLAGS);
461		if(mtmp && (mtmp->data->maligntyp == 0 ||
462		            sgn(mtmp->data->maligntyp) == sgn(castalign)) ) {
463		    count++;
464		    break;
465		}
466	    }
467    }
468    return count;
469}
470
471/*	Let's resurrect the wizard, for some unexpected fun.	*/
472void
473resurrect()
474{
475	struct monst *mtmp, **mmtmp;
476	long elapsed;
477	const char *verb;
478
479	if (!flags.no_of_wizards) {
480	    /* make a new Wizard */
481	    verb = "kill";
482	    mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT);
483	} else {
484	    /* look for a migrating Wizard */
485	    verb = "elude";
486	    mmtmp = &migrating_mons;
487	    while ((mtmp = *mmtmp) != 0) {
488		if (mtmp->iswiz &&
489			/* if he has the Amulet, he won't bring it to you */
490			!mon_has_amulet(mtmp) &&
491			(elapsed = monstermoves - mtmp->mlstmv) > 0L) {
492		    mon_catchup_elapsed_time(mtmp, elapsed);
493		    if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1;
494		    elapsed /= 50L;
495		    if (mtmp->msleeping && rn2((int)elapsed + 1))
496			mtmp->msleeping = 0;
497		    if (mtmp->mfrozen == 1) /* would unfreeze on next move */
498			mtmp->mfrozen = 0,  mtmp->mcanmove = 1;
499		    if (mtmp->mcanmove && !mtmp->msleeping) {
500			*mmtmp = mtmp->nmon;
501			mon_arrive(mtmp, TRUE);
502			/* note: there might be a second Wizard; if so,
503			   he'll have to wait til the next resurrection */
504			break;
505		    }
506		}
507		mmtmp = &mtmp->nmon;
508	    }
509	}
510
511	if (mtmp) {
512		mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0;
513		set_malign(mtmp);
514		pline("A voice booms out...");
515		verbalize("So thou thought thou couldst %s me, fool.", verb);
516	}
517
518}
519
520/*	Here, we make trouble for the poor shmuck who actually	*/
521/*	managed to do in the Wizard.				*/
522void
523intervene()
524{
525	int which = Is_astralevel(&u.uz) ? rnd(4) : rn2(6);
526	/* cases 0 and 5 don't apply on the Astral level */
527	switch (which) {
528	    case 0:
529	    case 1:	You_feel("vaguely nervous.");
530			break;
531	    case 2:	if (!Blind)
532			    You("notice a %s glow surrounding you.",
533				  hcolor(NH_BLACK));
534			rndcurse();
535			break;
536	    case 3:	aggravate();
537			break;
538	    case 4:	(void)nasty((struct monst *)0);
539			break;
540	    case 5:	resurrect();
541			break;
542	}
543}
544
545void
546wizdead()
547{
548	flags.no_of_wizards--;
549	if (!u.uevent.udemigod) {
550		u.uevent.udemigod = TRUE;
551		u.udg_cnt = rn1(250, 50);
552	}
553}
554
555const char * const random_insult[] = {
556	"antic",
557	"blackguard",
558	"caitiff",
559	"chucklehead",
560	"coistrel",
561	"craven",
562	"cretin",
563	"cur",
564	"dastard",
565	"demon fodder",
566	"dimwit",
567	"dolt",
568	"fool",
569	"footpad",
570	"imbecile",
571	"knave",
572	"maledict",
573	"miscreant",
574	"niddering",
575	"poltroon",
576	"rattlepate",
577	"reprobate",
578	"scapegrace",
579	"varlet",
580	"villein",	/* (sic.) */
581	"wittol",
582	"worm",
583	"wretch",
584};
585
586const char * const random_malediction[] = {
587	"Hell shall soon claim thy remains,",
588	"I chortle at thee, thou pathetic",
589	"Prepare to die, thou",
590	"Resistance is useless,",
591	"Surrender or die, thou",
592	"There shall be no mercy, thou",
593	"Thou shalt repent of thy cunning,",
594	"Thou art as a flea to me,",
595	"Thou art doomed,",
596	"Thy fate is sealed,",
597	"Verily, thou shalt be one dead"
598};
599
600/* Insult or intimidate the player */
601void
602cuss(mtmp)
603register struct monst	*mtmp;
604{
605	if (mtmp->iswiz) {
606	    if (!rn2(5))  /* typical bad guy action */
607		pline("%s laughs fiendishly.", Monnam(mtmp));
608	    else
609		if (u.uhave.amulet && !rn2(SIZE(random_insult)))
610		    verbalize("Relinquish the amulet, %s!",
611			  random_insult[rn2(SIZE(random_insult))]);
612		else if (u.uhp < 5 && !rn2(2))	/* Panic */
613		    verbalize(rn2(2) ?
614			  "Even now thy life force ebbs, %s!" :
615			  "Savor thy breath, %s, it be thy last!",
616			  random_insult[rn2(SIZE(random_insult))]);
617		else if (mtmp->mhp < 5 && !rn2(2))	/* Parthian shot */
618		    verbalize(rn2(2) ?
619			      "I shall return." :
620			      "I'll be back.");
621		else
622		    verbalize("%s %s!",
623			  random_malediction[rn2(SIZE(random_malediction))],
624			  random_insult[rn2(SIZE(random_insult))]);
625	} else if(is_lminion(mtmp)) {
626		com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) +
627			      QT_ANGELIC);
628	} else {
629	    if (!rn2(5))
630		pline("%s casts aspersions on your ancestry.", Monnam(mtmp));
631	    else
632	        com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC);
633	}
634}
635
636#endif /* OVLB */
637
638/*wizard.c*/
639