1 | /* SCCS Id: @(#)muse.c 3.3 2000/06/02 */
2 | /* Copyright (C) 1990 by Ken Arromdee */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | /*
6 | * Monster item usage routines.
7 | */
8 |
9 | #include "hack.h"
10 | #include "edog.h"
11 |
12 | extern const int monstr[];
13 |
14 | boolean m_using = FALSE;
15 |
16 | /* Let monsters use magic items. Arbitrary assumptions: Monsters only use
17 | * scrolls when they can see, monsters know when wands have 0 charges, monsters
18 | * cannot recognize if items are cursed are not, monsters which are confused
19 | * don't know not to read scrolls, etc....
20 | */
21 |
22 | STATIC_DCL int FDECL(precheck, (struct monst *,struct obj *));
23 | STATIC_DCL void FDECL(mzapmsg, (struct monst *,struct obj *,BOOLEAN_P));
24 | STATIC_DCL void FDECL(mreadmsg, (struct monst *,struct obj *));
25 | STATIC_DCL void FDECL(mquaffmsg, (struct monst *,struct obj *));
26 | STATIC_PTR int FDECL(mbhitm, (struct monst *,struct obj *));
27 | STATIC_DCL void FDECL(mbhit,
28 | (struct monst *,int,int FDECL((*),(MONST_P,OBJ_P)),
29 | int FDECL((*),(OBJ_P,OBJ_P)),struct obj *));
30 | STATIC_DCL void FDECL(you_aggravate, (struct monst *));
31 |
32 | static struct musable {
33 | struct obj *offensive;
34 | struct obj *defensive;
35 | struct obj *misc;
36 | int has_offense, has_defense, has_misc;
37 | /* =0, no capability; otherwise, different numbers.
38 | * If it's an object, the object is also set (it's 0 otherwise).
39 | */
40 | } m;
41 | static int trapx, trapy;
42 | static boolean zap_oseen;
43 | /* for wands which use mbhitm and are zapped at players. We usually
44 | * want an oseen local to the function, but this is impossible since the
45 | * function mbhitm has to be compatible with the normal zap routines,
46 | * and those routines don't remember who zapped the wand.
47 | */
48 |
49 | /* Any preliminary checks which may result in the monster being unable to use
50 | * the item. Returns 0 if nothing happened, 2 if the monster can't do anything
51 | * (i.e. it teleported) and 1 if it's dead.
52 | */
53 | STATIC_OVL int
54 | precheck(mon, obj)
55 | struct monst *mon;
56 | struct obj *obj;
57 | {
58 | boolean vis;
59 |
60 | if (!obj) return 0;
61 | vis = cansee(mon->mx, mon->my);
62 |
63 | if (obj->oclass == POTION_CLASS) {
64 | coord cc;
65 | static const char *empty = "The potion turns out to be empty.";
66 | const char *potion_descr;
67 | struct monst *mtmp;
68 | #define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in potion.c */
69 |
70 | potion_descr = OBJ_DESCR(objects[obj->otyp]);
71 | if (potion_descr && !strcmp(potion_descr, "milky")) {
72 | if ( flags.ghost_count < MAXMONNO &&
73 | !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) {
74 | if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0;
75 | mquaffmsg(mon, obj);
76 | m_useup(mon, obj);
77 | mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS);
78 | if (!mtmp) {
79 | if (vis) pline(empty);
80 | } else {
81 | if (vis) {
82 | pline("As %s opens the bottle, an enormous %s emerges!",
83 | mon_nam(mon),
84 | Hallucination ? rndmonnam() : (const char *)"ghost");
85 | pline("%s is frightened to death, and unable to move.",
86 | Monnam(mon));
87 | }
88 | mon->mcanmove = 0;
89 | mon->mfrozen = 3;
90 | }
91 | return 2;
92 | }
93 | }
94 | if (potion_descr && !strcmp(potion_descr, "smoky") &&
95 | flags.djinni_count < MAXMONNO &&
96 | !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) {
97 | if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0;
98 | mquaffmsg(mon, obj);
99 | m_useup(mon, obj);
100 | mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS);
101 | if (!mtmp) {
102 | if (vis) pline(empty);
103 | } else {
104 | if (vis)
105 | pline("In a cloud of smoke, %s emerges!",
106 | a_monnam(mtmp));
107 | pline("%s speaks.", vis ? Monnam(mtmp) : Something);
108 | /* I suspect few players will be upset that monsters */
109 | /* can't wish for wands of death here.... */
110 | if (rn2(2)) {
111 | verbalize("You freed me!");
112 | mtmp->mpeaceful = 1;
113 | set_malign(mtmp);
114 | } else {
115 | verbalize("It is about time.");
116 | if (vis) pline("%s vanishes.", Monnam(mtmp));
117 | mongone(mtmp);
118 | }
119 | }
120 | return 2;
121 | }
122 | }
123 | if (obj->oclass == WAND_CLASS && obj->cursed && !rn2(100)) {
124 | int dam = d(obj->spe+2, 6);
125 |
126 | if (flags.soundok) {
127 | if (vis) pline("%s zaps %s, which suddenly explodes!",
128 | Monnam(mon), an(xname(obj)));
129 | else You_hear("a zap and an explosion in the distance.");
130 | }
131 | m_useup(mon, obj);
132 | if (mon->mhp <= dam) {
133 | monkilled(mon, "", AD_RBRE);
134 | return 1;
135 | }
136 | else mon->mhp -= dam;
137 | m.has_defense = m.has_offense = m.has_misc = 0;
138 | /* Only one needed to be set to 0 but the others are harmless */
139 | }
140 | return 0;
141 | }
142 |
143 | STATIC_OVL void
144 | mzapmsg(mtmp, otmp, self)
145 | struct monst *mtmp;
146 | struct obj *otmp;
147 | boolean self;
148 | {
149 | if (!canseemon(mtmp)) {
150 | if (flags.soundok)
151 | You_hear("a %s zap.",
152 | (distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1)) ?
153 | "nearby" : "distant");
154 | } else if (self)
155 | pline("%s zaps %sself with %s!",
156 | Monnam(mtmp), him[pronoun_gender(mtmp)], doname(otmp));
157 | else {
158 | pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp)));
159 | stop_occupation();
160 | }
161 | }
162 |
163 | STATIC_OVL void
164 | mreadmsg(mtmp, otmp)
165 | struct monst *mtmp;
166 | struct obj *otmp;
167 | {
168 | boolean vismon = canseemon(mtmp);
169 | char onambuf[BUFSZ];
170 | short saverole;
171 | unsigned savebknown;
172 |
173 | if (!vismon && !flags.soundok)
174 | return; /* no feedback */
175 |
176 | otmp->dknown = 1; /* seeing or hearing it read reveals its label */
177 | /* shouldn't be able to hear curse/bless status of unseen scrolls;
178 | for priest characters, bknown will always be set during naming */
179 | savebknown = otmp->bknown;
180 | saverole = Role_switch;
181 | if (!vismon) {
182 | otmp->bknown = 0;
183 | if (Role_if(PM_PRIEST)) Role_switch = 0;
184 | }
185 | Strcpy(onambuf, singular(otmp, doname));
186 | Role_switch = saverole;
187 | otmp->bknown = savebknown;
188 |
189 | if (vismon)
190 | pline("%s reads %s!", Monnam(mtmp), onambuf);
191 | else
192 | You_hear("%s reading %s.",
193 | x_monnam(mtmp, ARTICLE_A, (char *)0,
194 | (SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_SADDLE), FALSE),
195 | onambuf);
196 |
197 | if (mtmp->mconf)
198 | pline("Being confused, %s mispronounces the magic words...",
199 | vismon ? mon_nam(mtmp) : he[pronoun_gender(mtmp)]);
200 | }
201 |
202 | STATIC_OVL void
203 | mquaffmsg(mtmp, otmp)
204 | struct monst *mtmp;
205 | struct obj *otmp;
206 | {
207 | if (canseemon(mtmp)) {
208 | otmp->dknown = 1;
209 | pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname));
210 | } else
211 | if (flags.soundok)
212 | You_hear("a chugging sound.");
213 | }
214 |
215 | /* Defines for various types of stuff. The order in which monsters prefer
216 | * to use them is determined by the order of the code logic, not the
217 | * numerical order in which they are defined.
218 | */
219 | #define MUSE_SCR_TELEPORTATION 1
220 | #define MUSE_WAN_TELEPORTATION_SELF 2
221 | #define MUSE_POT_HEALING 3
222 | #define MUSE_POT_EXTRA_HEALING 4
223 | #define MUSE_WAN_DIGGING 5
224 | #define MUSE_TRAPDOOR 6
225 | #define MUSE_TELEPORT_TRAP 7
226 | #define MUSE_UPSTAIRS 8
227 | #define MUSE_DOWNSTAIRS 9
228 | #define MUSE_WAN_CREATE_MONSTER 10
229 | #define MUSE_SCR_CREATE_MONSTER 11
230 | #define MUSE_UP_LADDER 12
231 | #define MUSE_DN_LADDER 13
232 | #define MUSE_SSTAIRS 14
233 | #define MUSE_WAN_TELEPORTATION 15
234 | #define MUSE_BUGLE 16
235 | #define MUSE_UNICORN_HORN 17
236 | #define MUSE_POT_FULL_HEALING 18
237 | /*
238 | #define MUSE_INNATE_TPT 9999
239 | * We cannot use this. Since monsters get unlimited teleportation, if they
240 | * were allowed to teleport at will you could never catch them. Instead,
241 | * assume they only teleport at random times, despite the inconsistency that if
242 | * you polymorph into one you teleport at will.
243 | */
244 |
245 | /* Select a defensive item/action for a monster. Returns TRUE iff one is
246 | * found.
247 | */
248 | boolean
249 | find_defensive(mtmp)
250 | struct monst *mtmp;
251 | {
252 | register struct obj *obj = 0;
253 | struct trap *t;
254 | int x=mtmp->mx, y=mtmp->my;
255 | boolean stuck = (mtmp == u.ustuck);
256 | boolean immobile = (mtmp->data->mmove == 0);
257 | int fraction;
258 |
259 | if (is_animal(mtmp->data) || mindless(mtmp->data))
260 | return FALSE;
261 | if(dist2(x, y, mtmp->mux, mtmp->muy) > 25)
262 | return FALSE;
263 | if (u.uswallow && stuck) return FALSE;
264 |
265 | m.defensive = (struct obj *)0;
266 | m.has_defense = 0;
267 |
268 | /* since unicorn horns don't get used up, the monster would look
269 | * silly trying to use the same cursed horn round after round
270 | */
271 | if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) {
272 | if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) {
273 | for(obj = mtmp->minvent; obj; obj = obj->nobj)
274 | if (obj->otyp == UNICORN_HORN && !obj->cursed)
275 | break;
276 | }
277 | if (obj || is_unicorn(mtmp->data)) {
278 | m.defensive = obj;
279 | m.has_defense = MUSE_UNICORN_HORN;
280 | return TRUE;
281 | }
282 | }
283 |
284 | /* It so happens there are two unrelated cases when we might want to
285 | * check specifically for healing alone. The first is when the monster
286 | * is blind (healing cures blindness). The second is when the monster
287 | * is peaceful; then we don't want to flee the player, and by
288 | * coincidence healing is all there is that doesn't involve fleeing.
289 | * These would be hard to combine because of the control flow.
290 | * Pestilence won't use healing even when blind.
291 | */
292 | if (!mtmp->mcansee && !nohands(mtmp->data) &&
293 | mtmp->data != &mons[PM_PESTILENCE]) {
294 | if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
295 | m.defensive = obj;
296 | m.has_defense = MUSE_POT_FULL_HEALING;
297 | return TRUE;
298 | }
299 | if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
300 | m.defensive = obj;
301 | m.has_defense = MUSE_POT_EXTRA_HEALING;
302 | return TRUE;
303 | }
304 | if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
305 | m.defensive = obj;
306 | m.has_defense = MUSE_POT_HEALING;
307 | return TRUE;
308 | }
309 | }
310 |
311 | fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3;
312 | if(mtmp->mhp >= mtmp->mhpmax ||
313 | (mtmp->mhp >= 10 && mtmp->mhp*fraction >= mtmp->mhpmax))
314 | return FALSE;
315 |
316 | if (mtmp->mpeaceful) {
317 | if (!nohands(mtmp->data)) {
318 | if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
319 | m.defensive = obj;
320 | m.has_defense = MUSE_POT_FULL_HEALING;
321 | return TRUE;
322 | }
323 | if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
324 | m.defensive = obj;
325 | m.has_defense = MUSE_POT_EXTRA_HEALING;
326 | return TRUE;
327 | }
328 | if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
329 | m.defensive = obj;
330 | m.has_defense = MUSE_POT_HEALING;
331 | return TRUE;
332 | }
333 | }
334 | return FALSE;
335 | }
336 |
337 | if (levl[x][y].typ == STAIRS && !stuck && !immobile) {
338 | if (x == xdnstair && y == ydnstair && !is_floater(mtmp->data))
339 | m.has_defense = MUSE_DOWNSTAIRS;
340 | if (x == xupstair && y == yupstair && ledger_no(&u.uz) != 1)
341 | /* Unfair to let the monsters leave the dungeon with the Amulet */
342 | /* (or go to the endlevel since you also need it, to get there) */
343 | m.has_defense = MUSE_UPSTAIRS;
344 | } else if (levl[x][y].typ == LADDER && !stuck && !immobile) {
345 | if (x == xupladder && y == yupladder)
346 | m.has_defense = MUSE_UP_LADDER;
347 | if (x == xdnladder && y == ydnladder && !is_floater(mtmp->data))
348 | m.has_defense = MUSE_DN_LADDER;
349 | } else if (sstairs.sx && sstairs.sx == x && sstairs.sy == y) {
350 | m.has_defense = MUSE_SSTAIRS;
351 | } else if (!stuck && !immobile) {
352 | /* Note: trap doors take precedence over teleport traps. */
353 | int xx, yy;
354 |
355 | for(xx = x-1; xx <= x+1; xx++) for(yy = y-1; yy <= y+1; yy++)
356 | if (isok(xx,yy))
357 | if (xx != u.ux && yy != u.uy)
358 | if (mtmp->data != &mons[PM_GRID_BUG] || xx == x || yy == y)
359 | if ((xx==x && yy==y) || !level.monsters[xx][yy])
360 | if ((t = t_at(xx,yy)) != 0)
361 | if ((verysmall(mtmp->data) || throws_rocks(mtmp->data) ||
362 | passes_walls(mtmp->data)) || !sobj_at(BOULDER, xx, yy))
363 | if (!onscary(xx,yy,mtmp)) {
364 | if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE)
365 | && !is_floater(mtmp->data)
366 | && !mtmp->isshk && !mtmp->isgd
367 | && !mtmp->ispriest
368 | && Can_fall_thru(&u.uz)
369 | ) {
370 | trapx = xx;
371 | trapy = yy;
372 | m.has_defense = MUSE_TRAPDOOR;
373 | } else if (t->ttyp == TELEP_TRAP && m.has_defense != MUSE_TRAPDOOR) {
374 | trapx = xx;
375 | trapy = yy;
376 | m.has_defense = MUSE_TELEPORT_TRAP;
377 | }
378 | }
379 | }
380 |
381 | if (nohands(mtmp->data)) /* can't use objects */
382 | goto botm;
383 |
384 | if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE))) {
385 | int xx, yy;
386 | struct monst *mon;
387 |
388 | /* Distance is arbitrary. What we really want to do is
389 | * have the soldier play the bugle when it sees or
390 | * remembers soldiers nearby...
391 | */
392 | for(xx = x-3; xx <= x+3; xx++) for(yy = y-3; yy <= y+3; yy++)
393 | if (isok(xx,yy))
394 | if ((mon = m_at(xx,yy)) && is_mercenary(mon->data) &&
395 | mon->data != &mons[PM_GUARD] &&
396 | (mon->msleeping || (!mon->mcanmove))) {
397 | m.defensive = obj;
398 | m.has_defense = MUSE_BUGLE;
399 | }
400 | }
401 |
402 | /* use immediate physical escape prior to attempting magic */
403 | if (m.has_defense) /* stairs, trap door or tele-trap, bugle alert */
404 | goto botm;
405 |
406 | /* kludge to cut down on trap destruction (particularly portals) */
407 | t = t_at(x,y);
408 | if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
409 | t->ttyp == WEB || t->ttyp == BEAR_TRAP))
410 | t = 0; /* ok for monster to dig here */
411 |
412 | #define nomore(x) if(m.has_defense==x) continue;
413 | for (obj = mtmp->minvent; obj; obj = obj->nobj) {
414 | /* don't always use the same selection pattern */
415 | if (m.has_defense && !rn2(3)) break;
416 |
417 | /* nomore(MUSE_WAN_DIGGING); */
418 | if (m.has_defense == MUSE_WAN_DIGGING) break;
419 | if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t
420 | && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
421 | && !is_floater(mtmp->data)
422 | /* digging wouldn't be effective; assume they know that */
423 | && !(levl[x][y].wall_info & W_NONDIGGABLE)
424 | && !(Is_botlevel(&u.uz) || In_endgame(&u.uz))
425 | && !(is_ice(x,y) || is_pool(x,y) || is_lava(x,y))) {
426 | m.defensive = obj;
427 | m.has_defense = MUSE_WAN_DIGGING;
428 | }
429 | nomore(MUSE_WAN_TELEPORTATION_SELF);
430 | nomore(MUSE_WAN_TELEPORTATION);
431 | if(obj->otyp == WAN_TELEPORTATION && obj->spe > 0) {
432 | m.defensive = obj;
433 | m.has_defense = (mon_has_amulet(mtmp))
434 | ? MUSE_WAN_TELEPORTATION
435 | : MUSE_WAN_TELEPORTATION_SELF;
436 | }
437 | nomore(MUSE_SCR_TELEPORTATION);
438 | if(obj->otyp == SCR_TELEPORTATION && mtmp->mcansee
439 | && haseyes(mtmp->data)
440 | && (!obj->cursed ||
441 | (!(mtmp->isshk && inhishop(mtmp))
442 | && !mtmp->isgd && !mtmp->ispriest))) {
443 | m.defensive = obj;
444 | m.has_defense = MUSE_SCR_TELEPORTATION;
445 | }
446 |
447 | if (mtmp->data != &mons[PM_PESTILENCE]) {
448 | nomore(MUSE_POT_FULL_HEALING);
449 | if(obj->otyp == POT_FULL_HEALING) {
450 | m.defensive = obj;
451 | m.has_defense = MUSE_POT_FULL_HEALING;
452 | }
453 | nomore(MUSE_POT_EXTRA_HEALING);
454 | if(obj->otyp == POT_EXTRA_HEALING) {
455 | m.defensive = obj;
456 | m.has_defense = MUSE_POT_EXTRA_HEALING;
457 | }
458 | nomore(MUSE_WAN_CREATE_MONSTER);
459 | if(obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
460 | m.defensive = obj;
461 | m.has_defense = MUSE_WAN_CREATE_MONSTER;
462 | }
463 | nomore(MUSE_POT_HEALING);
464 | if(obj->otyp == POT_HEALING) {
465 | m.defensive = obj;
466 | m.has_defense = MUSE_POT_HEALING;
467 | }
468 | } else { /* Pestilence */
469 | nomore(MUSE_POT_FULL_HEALING);
470 | if (obj->otyp == POT_SICKNESS) {
471 | m.defensive = obj;
472 | m.has_defense = MUSE_POT_FULL_HEALING;
473 | }
474 | nomore(MUSE_WAN_CREATE_MONSTER);
475 | if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
476 | m.defensive = obj;
477 | m.has_defense = MUSE_WAN_CREATE_MONSTER;
478 | }
479 | }
480 | nomore(MUSE_SCR_CREATE_MONSTER);
481 | if(obj->otyp == SCR_CREATE_MONSTER) {
482 | m.defensive = obj;
483 | m.has_defense = MUSE_SCR_CREATE_MONSTER;
484 | }
485 | }
486 | botm: return((boolean)(!!m.has_defense));
487 | #undef nomore
488 | }
489 |
490 | /* Perform a defensive action for a monster. Must be called immediately
491 | * after find_defensive(). Return values are 0: did something, 1: died,
492 | * 2: did something and can't attack again (i.e. teleported).
493 | */
494 | int
495 | use_defensive(mtmp)
496 | struct monst *mtmp;
497 | {
498 | int i, fleetim, how = 0;
499 | struct obj *otmp = m.defensive;
500 | boolean vis, vismon, oseen;
501 | const char *mcsa = "%s can see again.";
502 |
503 | if ((i = precheck(mtmp, otmp)) != 0) return i;
504 | vis = cansee(mtmp->mx, mtmp->my);
505 | vismon = canseemon(mtmp);
506 | oseen = otmp && vismon;
507 |
508 | /* when using defensive choice to run away, we want monster to avoid
509 | rushing right straight back; don't override if already scared */
510 | fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0;
511 | #define m_flee(m) if (fleetim && !m->iswiz) \
512 | { m->mflee = 1; m->mfleetim = fleetim; }
513 |
514 | switch(m.has_defense) {
515 | case MUSE_UNICORN_HORN:
516 | if (vismon) {
517 | if (otmp)
518 | pline("%s uses a unicorn horn!", Monnam(mtmp));
519 | else
520 | pline_The("tip of %s's horn glows!", mon_nam(mtmp));
521 | }
522 | if (!mtmp->mcansee) {
523 | mtmp->mcansee = 1;
524 | mtmp->mblinded = 0;
525 | if (vismon) pline(mcsa, Monnam(mtmp));
526 | } else if (mtmp->mconf || mtmp->mstun) {
527 | mtmp->mconf = mtmp->mstun = 0;
528 | if (vismon)
529 | pline("%s seems steadier now.", Monnam(mtmp));
530 | } else impossible("No need for unicorn horn?");
531 | return 2;
532 | case MUSE_BUGLE:
533 | if (vismon)
534 | pline("%s plays %s!", Monnam(mtmp), doname(otmp));
535 | else if (flags.soundok)
536 | You_hear("a bugle playing reveille!");
537 | awaken_soldiers();
538 | return 2;
539 | case MUSE_WAN_TELEPORTATION_SELF:
540 | if ((mtmp->isshk && inhishop(mtmp))
541 | || mtmp->isgd || mtmp->ispriest) return 2;
542 | m_flee(mtmp);
543 | mzapmsg(mtmp, otmp, TRUE);
544 | otmp->spe--;
545 | how = WAN_TELEPORTATION;
546 | mon_tele:
547 | if (tele_restrict(mtmp)) { /* mysterious force... */
548 | if (vismon && how) /* mentions 'teleport' */
549 | makeknown(how);
550 | return 2;
551 | }
552 | if ((
553 | #if 0
554 | mon_has_amulet(mtmp) ||
555 | #endif
556 | On_W_tower_level(&u.uz)) && !rn2(3)) {
557 | if (vismon)
558 | pline("%s seems disoriented for a moment.",
559 | Monnam(mtmp));
560 | return 2;
561 | }
562 | if (oseen && how) makeknown(how);
563 | rloc(mtmp);
564 | return 2;
565 | case MUSE_WAN_TELEPORTATION:
566 | zap_oseen = oseen;
567 | mzapmsg(mtmp, otmp, FALSE);
568 | otmp->spe--;
569 | m_using = TRUE;
570 | mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp);
571 | m_using = FALSE;
572 | return 2;
573 | case MUSE_SCR_TELEPORTATION:
574 | {
575 | int obj_is_cursed = otmp->cursed;
576 |
577 | if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 2;
578 | m_flee(mtmp);
579 | mreadmsg(mtmp, otmp);
580 | m_useup(mtmp, otmp); /* otmp might be free'ed */
581 | how = SCR_TELEPORTATION;
582 | if (obj_is_cursed || mtmp->mconf) {
583 | int nlev;
584 | d_level flev;
585 |
586 | if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
587 | if (vismon)
588 | pline("%s seems very disoriented for a moment.",
589 | Monnam(mtmp));
590 | return 2;
591 | }
592 | nlev = random_teleport_level();
593 | if (nlev == depth(&u.uz)) {
594 | if (vismon)
595 | pline("%s shudders for a moment.",
596 | Monnam(mtmp));
597 | return 2;
598 | }
599 | get_level(&flev, nlev);
600 | migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM,
601 | (coord *)0);
602 | if (oseen) makeknown(SCR_TELEPORTATION);
603 | } else goto mon_tele;
604 | return 2;
605 | }
606 | case MUSE_WAN_DIGGING:
607 | { struct trap *ttmp;
608 |
609 | m_flee(mtmp);
610 | mzapmsg(mtmp, otmp, FALSE);
611 | otmp->spe--;
612 | if (oseen) makeknown(WAN_DIGGING);
613 | if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ) ||
614 | IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ) ||
615 | (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0) ||
616 | (sstairs.sx && sstairs.sx == mtmp->mx &&
617 | sstairs.sy == mtmp->my)) {
618 | pline_The("digging ray is ineffective.");
619 | return 2;
620 | }
621 | if (!Can_dig_down(&u.uz)) {
622 | if(canseemon(mtmp))
623 | pline_The("%s here is too hard to dig in.",
624 | surface(mtmp->mx, mtmp->my));
625 | return 2;
626 | }
627 | ttmp = maketrap(mtmp->mx, mtmp->my, HOLE);
628 | if (!ttmp) return 2;
629 | seetrap(ttmp);
630 | if (vis) {
631 | pline("%s has made a hole in the %s.", Monnam(mtmp),
632 | surface(mtmp->mx, mtmp->my));
633 | pline("%s %s through...", Monnam(mtmp),
634 | is_flyer(mtmp->data) ? "dives" : "falls");
635 | } else if (flags.soundok)
636 | You_hear("%s crash through the %s.", something,
637 | surface(mtmp->mx, mtmp->my));
638 | /* we made sure that there is a level for mtmp to go to */
639 | migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
640 | MIGR_RANDOM, (coord *)0);
641 | return 2;
642 | }
643 | case MUSE_WAN_CREATE_MONSTER:
644 | { coord cc;
645 | /* pm: 0 => random, eel => aquatic, croc => amphibious */
646 | struct permonst *pm = !is_pool(mtmp->mx, mtmp->my) ? 0 :
647 | &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
648 | struct monst *mon;
649 |
650 | if (!enexto(&cc, mtmp->mx, mtmp->my, pm)) return 0;
651 | mzapmsg(mtmp, otmp, FALSE);
652 | otmp->spe--;
653 | mon = makemon((struct permonst *)0, cc.x, cc.y, NO_MM_FLAGS);
654 | if (mon && canspotmon(mon) && oseen)
655 | makeknown(WAN_CREATE_MONSTER);
656 | return 2;
657 | }
658 | case MUSE_SCR_CREATE_MONSTER:
659 | { coord cc;
660 | struct permonst *pm = 0, *fish = 0;
661 | int cnt = 1;
662 | struct monst *mon;
663 | boolean known = FALSE;
664 |
665 | if (!rn2(73)) cnt += rnd(4);
666 | if (mtmp->mconf || otmp->cursed) cnt += 12;
667 | if (mtmp->mconf) pm = fish = &mons[PM_ACID_BLOB];
668 | else if (is_pool(mtmp->mx, mtmp->my))
669 | fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
670 | mreadmsg(mtmp, otmp);
671 | while(cnt--) {
672 | /* `fish' potentially gives bias towards water locations;
673 | `pm' is what to actually create (0 => random) */
674 | if (!enexto(&cc, mtmp->mx, mtmp->my, fish)) break;
675 | mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS);
676 | if (mon && canspotmon(mon)) known = TRUE;
677 | }
678 | /* The only case where we don't use oseen. For wands, you
679 | * have to be able to see the monster zap the wand to know
680 | * what type it is. For teleport scrolls, you have to see
681 | * the monster to know it teleported.
682 | */
683 | if (known)
684 | makeknown(SCR_CREATE_MONSTER);
685 | else if (!objects[SCR_CREATE_MONSTER].oc_name_known
686 | && !objects[SCR_CREATE_MONSTER].oc_uname)
687 | docall(otmp);
688 | m_useup(mtmp, otmp);
689 | return 2;
690 | }
691 | case MUSE_TRAPDOOR:
692 | /* trap doors on "bottom" levels of dungeons are rock-drop
693 | * trap doors, not holes in the floor. We check here for
694 | * safety.
695 | */
696 | if (Is_botlevel(&u.uz)) return 0;
697 | m_flee(mtmp);
698 | if (vis) {
699 | struct trap *t;
700 | t = t_at(trapx,trapy);
701 | pline("%s %s into a %s!", Monnam(mtmp),
702 | makeplural(locomotion(mtmp->data, "jump")),
703 | t->ttyp == TRAPDOOR ? "trap door" : "hole");
704 | seetrap(t_at(trapx,trapy));
705 | }
706 |
707 | /* don't use rloc_to() because worm tails must "move" */
708 | remove_monster(mtmp->mx, mtmp->my);
709 | newsym(mtmp->mx, mtmp->my); /* update old location */
710 | place_monster(mtmp, trapx, trapy);
711 | if (mtmp->wormno) worm_move(mtmp);
712 | newsym(trapx, trapy);
713 |
714 | migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
715 | MIGR_RANDOM, (coord *)0);
716 | return 2;
717 | case MUSE_UPSTAIRS:
718 | /* Monsters without amulets escape the dungeon and are
719 | * gone for good when they leave up the up stairs.
720 | * Monsters with amulets would reach the endlevel,
721 | * which we cannot allow since that would leave the
722 | * player stranded.
723 | */
724 | if (ledger_no(&u.uz) == 1) {
725 | if (mon_has_special(mtmp))
726 | return 0;
727 | if (vismon)
728 | pline("%s escapes the dungeon!", Monnam(mtmp));
729 | mongone(mtmp);
730 | return 2;
731 | }
732 | m_flee(mtmp);
733 | if (Inhell && mon_has_amulet(mtmp) && !rn2(4) &&
734 | (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
735 | if (vismon) pline(
736 | "As %s climbs the stairs, a mysterious force momentarily surrounds %s...",
737 | mon_nam(mtmp), him[pronoun_gender(mtmp)]);
738 | /* simpler than for the player; this will usually be
739 | the Wizard and he'll immediately go right to the
740 | upstairs, so there's not much point in having any
741 | chance for a random position on the current level */
742 | migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
743 | MIGR_RANDOM, (coord *)0);
744 | } else {
745 | if (vismon) pline("%s escapes upstairs!", Monnam(mtmp));
746 | migrate_to_level(mtmp, ledger_no(&u.uz) - 1,
747 | MIGR_STAIRS_DOWN, (coord *)0);
748 | }
749 | return 2;
750 | case MUSE_DOWNSTAIRS:
751 | m_flee(mtmp);
752 | if (vismon) pline("%s escapes downstairs!", Monnam(mtmp));
753 | migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
754 | MIGR_STAIRS_UP, (coord *)0);
755 | return 2;
756 | case MUSE_UP_LADDER:
757 | m_flee(mtmp);
758 | if (vismon) pline("%s escapes up the ladder!", Monnam(mtmp));
759 | migrate_to_level(mtmp, ledger_no(&u.uz) - 1,
760 | MIGR_LADDER_DOWN, (coord *)0);
761 | return 2;
762 | case MUSE_DN_LADDER:
763 | m_flee(mtmp);
764 | if (vismon) pline("%s escapes down the ladder!", Monnam(mtmp));
765 | migrate_to_level(mtmp, ledger_no(&u.uz) + 1,
766 | MIGR_LADDER_UP, (coord *)0);
767 | return 2;
768 | case MUSE_SSTAIRS:
769 | m_flee(mtmp);
770 | /* the stairs leading up from the 1st level are */
771 | /* regular stairs, not sstairs. */
772 | if (sstairs.up) {
773 | if (vismon)
774 | pline("%s escapes upstairs!", Monnam(mtmp));
775 | if(Inhell) {
776 | migrate_to_level(mtmp, ledger_no(&sstairs.tolev),
777 | MIGR_RANDOM, (coord *)0);
778 | return 2;
779 | }
780 | } else if (vismon)
781 | pline("%s escapes downstairs!", Monnam(mtmp));
782 | migrate_to_level(mtmp, ledger_no(&sstairs.tolev),
783 | MIGR_SSTAIRS, (coord *)0);
784 | return 2;
785 | case MUSE_TELEPORT_TRAP:
786 | m_flee(mtmp);
787 | if (vis) {
788 | pline("%s %s onto a teleport trap!", Monnam(mtmp),
789 | makeplural(locomotion(mtmp->data, "jump")));
790 | seetrap(t_at(trapx,trapy));
791 | }
792 | /* don't use rloc_to() because worm tails must "move" */
793 | remove_monster(mtmp->mx, mtmp->my);
794 | newsym(mtmp->mx, mtmp->my); /* update old location */
795 | place_monster(mtmp, trapx, trapy);
796 | if (mtmp->wormno) worm_move(mtmp);
797 | newsym(trapx, trapy);
798 |
799 | goto mon_tele;
800 | case MUSE_POT_HEALING:
801 | mquaffmsg(mtmp, otmp);
802 | i = d(6 + 2 * bcsign(otmp), 4);
803 | mtmp->mhp += i;
804 | if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = ++mtmp->mhpmax;
805 | if (!otmp->cursed && !mtmp->mcansee) {
806 | mtmp->mcansee = 1;
807 | mtmp->mblinded = 0;
808 | if (vismon) pline(mcsa, Monnam(mtmp));
809 | }
810 | if (vismon) pline("%s looks better.", Monnam(mtmp));
811 | if (oseen) makeknown(POT_HEALING);
812 | m_useup(mtmp, otmp);
813 | return 2;
814 | case MUSE_POT_EXTRA_HEALING:
815 | mquaffmsg(mtmp, otmp);
816 | i = d(6 + 2 * bcsign(otmp), 8);
817 | mtmp->mhp += i;
818 | if (mtmp->mhp > mtmp->mhpmax)
819 | mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2));
820 | if (!mtmp->mcansee) {
821 | mtmp->mcansee = 1;
822 | mtmp->mblinded = 0;
823 | if (vismon) pline(mcsa, Monnam(mtmp));
824 | }
825 | if (vismon) pline("%s looks much better.", Monnam(mtmp));
826 | if (oseen) makeknown(POT_EXTRA_HEALING);
827 | m_useup(mtmp, otmp);
828 | return 2;
829 | case MUSE_POT_FULL_HEALING:
830 | mquaffmsg(mtmp, otmp);
831 | if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */
832 | mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4));
833 | if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) {
834 | mtmp->mcansee = 1;
835 | mtmp->mblinded = 0;
836 | if (vismon) pline(mcsa, Monnam(mtmp));
837 | }
838 | if (vismon) pline("%s looks completely healed.", Monnam(mtmp));
839 | if (oseen) makeknown(otmp->otyp);
840 | m_useup(mtmp, otmp);
841 | return 2;
842 | case 0: return 0; /* i.e. an exploded wand */
843 | default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
844 | m.has_defense);
845 | break;
846 | }
847 | return 0;
848 | #undef m_flee
849 | }
850 |
851 | int
852 | rnd_defensive_item(mtmp)
853 | struct monst *mtmp;
854 | {
855 | struct permonst *pm = mtmp->data;
856 | int difficulty = monstr[(monsndx(pm))];
857 |
858 | if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
859 | || pm->mlet == S_GHOST
860 | # ifdef KOPS
861 | || pm->mlet == S_KOP
862 | # endif
863 | ) return 0;
864 | switch (rn2(8 + (difficulty > 3) + (difficulty > 6) +
865 | (difficulty > 8))) {
866 | case 6: case 9:
867 | if (!rn2(3)) return WAN_TELEPORTATION;
868 | /* else FALLTHRU */
869 | case 0: case 1:
870 | return SCR_TELEPORTATION;
871 | case 8: case 10:
872 | if (!rn2(3)) return WAN_CREATE_MONSTER;
873 | /* else FALLTHRU */
874 | case 2: return SCR_CREATE_MONSTER;
875 | case 3: return POT_HEALING;
876 | case 4: return POT_EXTRA_HEALING;
877 | case 5: return (mtmp->data != &mons[PM_PESTILENCE]) ?
878 | POT_FULL_HEALING : POT_SICKNESS;
879 | case 7: if (is_floater(pm) || mtmp->isshk || mtmp->isgd
880 | || mtmp->ispriest
881 | )
882 | return 0;
883 | else
884 | return WAN_DIGGING;
885 | }
886 | /*NOTREACHED*/
887 | return 0;
888 | }
889 |
890 | #define MUSE_WAN_DEATH 1
891 | #define MUSE_WAN_SLEEP 2
892 | #define MUSE_WAN_FIRE 3
893 | #define MUSE_WAN_COLD 4
894 | #define MUSE_WAN_LIGHTNING 5
895 | #define MUSE_WAN_MAGIC_MISSILE 6
896 | #define MUSE_WAN_STRIKING 7
897 | #define MUSE_SCR_FIRE 8
898 | #define MUSE_POT_PARALYSIS 9
899 | #define MUSE_POT_BLINDNESS 10
900 | #define MUSE_POT_CONFUSION 11
901 | #define MUSE_FROST_HORN 12
902 | #define MUSE_FIRE_HORN 13
903 | #define MUSE_POT_ACID 14
904 | /*#define MUSE_WAN_TELEPORTATION 15*/
905 | #define MUSE_POT_SLEEPING 16
906 | #define MUSE_SCR_EARTH 17
907 |
908 | /* Select an offensive item/action for a monster. Returns TRUE iff one is
909 | * found.
910 | */
911 | boolean
912 | find_offensive(mtmp)
913 | struct monst *mtmp;
914 | {
915 | register struct obj *obj;
916 | boolean ranged_stuff = lined_up(mtmp);
917 | boolean reflection_skip = (Reflecting && rn2(2));
918 | struct obj *helmet = which_armor(mtmp, W_ARMH);
919 |
920 | m.offensive = (struct obj *)0;
921 | m.has_offense = 0;
922 | if (mtmp->mpeaceful || is_animal(mtmp->data) ||
923 | mindless(mtmp->data) || nohands(mtmp->data))
924 | return FALSE;
925 | if (u.uswallow) return FALSE;
926 | if (in_your_sanctuary(mtmp, 0, 0)) return FALSE;
927 | if (dmgtype(mtmp->data, AD_HEAL) && !uwep
928 | #ifdef TOURIST
929 | && !uarmu
930 | #endif
931 | && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf)
932 | return FALSE;
933 |
934 | if (!ranged_stuff) return FALSE;
935 | #define nomore(x) if(m.has_offense==x) continue;
936 | for(obj=mtmp->minvent; obj; obj=obj->nobj) {
937 | /* nomore(MUSE_WAN_DEATH); */
938 | if (!reflection_skip) {
939 | if(obj->otyp == WAN_DEATH && obj->spe > 0) {
940 | m.offensive = obj;
941 | m.has_offense = MUSE_WAN_DEATH;
942 | }
943 | nomore(MUSE_WAN_SLEEP);
944 | if(obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) {
945 | m.offensive = obj;
946 | m.has_offense = MUSE_WAN_SLEEP;
947 | }
948 | nomore(MUSE_WAN_FIRE);
949 | if(obj->otyp == WAN_FIRE && obj->spe > 0) {
950 | m.offensive = obj;
951 | m.has_offense = MUSE_WAN_FIRE;
952 | }
953 | nomore(MUSE_FIRE_HORN);
954 | if(obj->otyp == FIRE_HORN && obj->spe > 0) {
955 | m.offensive = obj;
956 | m.has_offense = MUSE_FIRE_HORN;
957 | }
958 | nomore(MUSE_WAN_COLD);
959 | if(obj->otyp == WAN_COLD && obj->spe > 0) {
960 | m.offensive = obj;
961 | m.has_offense = MUSE_WAN_COLD;
962 | }
963 | nomore(MUSE_FROST_HORN);
964 | if(obj->otyp == FROST_HORN && obj->spe > 0) {
965 | m.offensive = obj;
966 | m.has_offense = MUSE_FROST_HORN;
967 | }
968 | nomore(MUSE_WAN_LIGHTNING);
969 | if(obj->otyp == WAN_LIGHTNING && obj->spe > 0) {
970 | m.offensive = obj;
971 | m.has_offense = MUSE_WAN_LIGHTNING;
972 | }
973 | nomore(MUSE_WAN_MAGIC_MISSILE);
974 | if(obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) {
975 | m.offensive = obj;
976 | m.has_offense = MUSE_WAN_MAGIC_MISSILE;
977 | }
978 | }
979 | nomore(MUSE_WAN_STRIKING);
980 | if(obj->otyp == WAN_STRIKING && obj->spe > 0) {
981 | m.offensive = obj;
982 | m.has_offense = MUSE_WAN_STRIKING;
983 | }
984 | nomore(MUSE_POT_PARALYSIS);
985 | if(obj->otyp == POT_PARALYSIS && multi >= 0) {
986 | m.offensive = obj;
987 | m.has_offense = MUSE_POT_PARALYSIS;
988 | }
989 | nomore(MUSE_POT_BLINDNESS);
990 | if(obj->otyp == POT_BLINDNESS) {
991 | m.offensive = obj;
992 | m.has_offense = MUSE_POT_BLINDNESS;
993 | }
994 | nomore(MUSE_POT_CONFUSION);
995 | if(obj->otyp == POT_CONFUSION) {
996 | m.offensive = obj;
997 | m.has_offense = MUSE_POT_CONFUSION;
998 | }
999 | nomore(MUSE_POT_SLEEPING);
1000 | if(obj->otyp == POT_SLEEPING) {
1001 | m.offensive = obj;
1002 | m.has_offense = MUSE_POT_SLEEPING;
1003 | }
1004 | nomore(MUSE_POT_ACID);
1005 | if(obj->otyp == POT_ACID) {
1006 | m.offensive = obj;
1007 | m.has_offense = MUSE_POT_ACID;
1008 | }
1009 | /* we can safely put this scroll here since the locations that
1010 | * are in a 1 square radius are a subset of the locations that
1011 | * are in wand range
1012 | */
1013 | nomore(MUSE_SCR_EARTH);
1014 | if (obj->otyp == SCR_EARTH
1015 | && ((helmet && is_metallic(helmet)) ||
1016 | mtmp->mconf || amorphous(mtmp->data) ||
1017 | passes_walls(mtmp->data) ||
1018 | noncorporeal(mtmp->data) ||
1019 | unsolid(mtmp->data) || !rn2(10))
1020 | && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2
1021 | && mtmp->mcansee && haseyes(mtmp->data)
1022 | #ifdef REINCARNATION
1023 | && !Is_rogue_level(&u.uz)
1024 | #endif
1025 | && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
1026 | m.offensive = obj;
1027 | m.has_offense = MUSE_SCR_EARTH;
1028 | }
1029 | #if 0
1030 | nomore(MUSE_SCR_FIRE);
1031 | if (obj->otyp == SCR_FIRE && resists_fire(mtmp)
1032 | && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2
1033 | && mtmp->mcansee && haseyes(mtmp->data)) {
1034 | m.offensive = obj;
1035 | m.has_offense = MUSE_SCR_FIRE;
1036 | }
1037 | #endif
1038 | }
1039 | return((boolean)(!!m.has_offense));
1040 | #undef nomore
1041 | }
1042 |
1043 | STATIC_PTR
1044 | int
1045 | mbhitm(mtmp, otmp)
1046 | register struct monst *mtmp;
1047 | register struct obj *otmp;
1048 | {
1049 | int tmp;
1050 |
1051 | boolean reveal_invis = FALSE;
1052 | if (mtmp != &youmonst) {
1053 | mtmp->msleeping = 0;
1054 | if (mtmp->m_ap_type) seemimic(mtmp);
1055 | }
1056 | switch(otmp->otyp) {
1057 | case WAN_STRIKING:
1058 | reveal_invis = TRUE;
1059 | if (mtmp == &youmonst) {
1060 | if (zap_oseen) makeknown(WAN_STRIKING);
1061 | if (Antimagic) {
1062 | shieldeff(u.ux, u.uy);
1063 | pline("Boing!");
1064 | } else if (rnd(20) < 10 + u.uac) {
1065 | pline_The("wand hits you!");
1066 | tmp = d(2,12);
1067 | if(Half_spell_damage) tmp = (tmp+1) / 2;
1068 | losehp(tmp, "wand", KILLED_BY_AN);
1069 | } else pline_The("wand misses you.");
1070 | stop_occupation();
1071 | nomul(0);
1072 | } else if (resists_magm(mtmp)) {
1073 | shieldeff(mtmp->mx, mtmp->my);
1074 | pline("Boing!");
1075 | } else if (rnd(20) < 10+find_mac(mtmp)) {
1076 | tmp = d(2,12);
1077 | hit("wand", mtmp, exclam(tmp));
1078 | (void) resist(mtmp, otmp->oclass, tmp, TELL);
1079 | if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
1080 | makeknown(WAN_STRIKING);
1081 | } else {
1082 | miss("wand", mtmp);
1083 | if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
1084 | makeknown(WAN_STRIKING);
1085 | }
1086 | break;
1087 | case WAN_TELEPORTATION:
1088 | if (mtmp == &youmonst) {
1089 | if (zap_oseen) makeknown(WAN_TELEPORTATION);
1090 | tele();
1091 | } else {
1092 | /* for consistency with zap.c, don't identify */
1093 | if (mtmp->ispriest &&
1094 | *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
1095 | if (cansee(mtmp->mx, mtmp->my))
1096 | pline("%s resists the magic!", Monnam(mtmp));
1097 | mtmp->msleeping = 0;
1098 | if(mtmp->m_ap_type) seemimic(mtmp);
1099 | } else if (!tele_restrict(mtmp))
1100 | rloc(mtmp);
1101 | }
1102 | break;
1103 | case WAN_CANCELLATION:
1104 | case SPE_CANCELLATION:
1105 | cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
1106 | break;
1107 | }
1108 | if (reveal_invis) {
1109 | if (mtmp->mhp > 0 && cansee(bhitpos.x,bhitpos.y)
1110 | && !canspotmon(mtmp))
1111 | map_invisible(bhitpos.x, bhitpos.y);
1112 | }
1113 | return 0;
1114 | }
1115 |
1116 | /* A modified bhit() for monsters. Based on bhit() in zap.c. Unlike
1117 | * buzz(), bhit() doesn't take into account the possibility of a monster
1118 | * zapping you, so we need a special function for it. (Unless someone wants
1119 | * to merge the two functions...)
1120 | */
1121 | STATIC_OVL void
1122 | mbhit(mon,range,fhitm,fhito,obj)
1123 | struct monst *mon; /* monster shooting the wand */
1124 | register int range; /* direction and range */
1125 | int FDECL((*fhitm),(MONST_P,OBJ_P));
1126 | int FDECL((*fhito),(OBJ_P,OBJ_P)); /* fns called when mon/obj hit */
1127 | struct obj *obj; /* 2nd arg to fhitm/fhito */
1128 | {
1129 | register struct monst *mtmp;
1130 | register struct obj *otmp;
1131 | register uchar typ;
1132 | int ddx, ddy;
1133 |
1134 | bhitpos.x = mon->mx;
1135 | bhitpos.y = mon->my;
1136 | ddx = sgn(mon->mux - mon->mx);
1137 | ddy = sgn(mon->muy - mon->my);
1138 |
1139 | while(range-- > 0) {
1140 | int x,y;
1141 |
1142 | bhitpos.x += ddx;
1143 | bhitpos.y += ddy;
1144 | x = bhitpos.x; y = bhitpos.y;
1145 |
1146 | if (!isok(x,y)) {
1147 | bhitpos.x -= ddx;
1148 | bhitpos.y -= ddy;
1149 | break;
1150 | }
1151 | if (find_drawbridge(&x,&y))
1152 | switch (obj->otyp) {
1153 | case WAN_STRIKING:
1154 | destroy_drawbridge(x,y);
1155 | }
1156 | if(bhitpos.x==u.ux && bhitpos.y==u.uy) {
1157 | (*fhitm)(&youmonst, obj);
1158 | range -= 3;
1159 | } else if(MON_AT(bhitpos.x, bhitpos.y)){
1160 | mtmp = m_at(bhitpos.x,bhitpos.y);
1161 | if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp))
1162 | map_invisible(bhitpos.x, bhitpos.y);
1163 | (*fhitm)(mtmp, obj);
1164 | range -= 3;
1165 | }
1166 | /* modified by GAN to hit all objects */
1167 | if(fhito){
1168 | int hitanything = 0;
1169 | register struct obj *next_obj;
1170 |
1171 | for(otmp = level.objects[bhitpos.x][bhitpos.y];
1172 | otmp; otmp = next_obj) {
1173 | /* Fix for polymorph bug, Tim Wright */
1174 | next_obj = otmp->nexthere;
1175 | hitanything += (*fhito)(otmp, obj);
1176 | }
1177 | if(hitanything) range--;
1178 | }
1179 | typ = levl[bhitpos.x][bhitpos.y].typ;
1180 | if(IS_DOOR(typ) || typ == SDOOR) {
1181 | switch (obj->otyp) {
1182 | /* note: monsters don't use opening or locking magic
1183 | at present, but keep these as placeholders */
1184 | case WAN_OPENING:
1185 | case WAN_LOCKING:
1186 | case WAN_STRIKING:
1187 | if (doorlock(obj, bhitpos.x, bhitpos.y)) {
1188 | makeknown(obj->otyp);
1189 | /* if a shop door gets broken, add it to
1190 | the shk's fix list (no cost to player) */
1191 | if (levl[bhitpos.x][bhitpos.y].doormask ==
1192 | D_BROKEN &&
1193 | *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE))
1194 | add_damage(bhitpos.x, bhitpos.y, 0L);
1195 | }
1196 | break;
1197 | }
1198 | }
1199 | if(!ZAP_POS(typ) || (IS_DOOR(typ) &&
1200 | (levl[bhitpos.x][bhitpos.y].doormask & (D_LOCKED | D_CLOSED)))
1201 | ) {
1202 | bhitpos.x -= ddx;
1203 | bhitpos.y -= ddy;
1204 | break;
1205 | }
1206 | }
1207 | }
1208 |
1209 | /* Perform an offensive action for a monster. Must be called immediately
1210 | * after find_offensive(). Return values are same as use_defensive().
1211 | */
1212 | int
1213 | use_offensive(mtmp)
1214 | struct monst *mtmp;
1215 | {
1216 | int i;
1217 | struct obj *otmp = m.offensive;
1218 | boolean oseen;
1219 |
1220 | /* offensive potions are not drunk, they're thrown */
1221 | if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0)
1222 | return i;
1223 | oseen = otmp && canseemon(mtmp);
1224 |
1225 | switch(m.has_offense) {
1226 | case MUSE_WAN_DEATH:
1227 | case MUSE_WAN_SLEEP:
1228 | case MUSE_WAN_FIRE:
1229 | case MUSE_WAN_COLD:
1230 | case MUSE_WAN_LIGHTNING:
1231 | case MUSE_WAN_MAGIC_MISSILE:
1232 | mzapmsg(mtmp, otmp, FALSE);
1233 | otmp->spe--;
1234 | if (oseen) makeknown(otmp->otyp);
1235 | m_using = TRUE;
1236 | buzz((int)(-30 - (otmp->otyp - WAN_MAGIC_MISSILE)),
1237 | (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
1238 | mtmp->mx, mtmp->my,
1239 | sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my));
1240 | m_using = FALSE;
1241 | return (mtmp->mhp <= 0) ? 1 : 2;
1242 | case MUSE_FIRE_HORN:
1243 | case MUSE_FROST_HORN:
1244 | if (oseen) {
1245 | makeknown(otmp->otyp);
1246 | pline("%s plays a %s!", Monnam(mtmp), xname(otmp));
1247 | } else
1248 | You_hear("a horn being played.");
1249 | otmp->spe--;
1250 | m_using = TRUE;
1251 | buzz(-30 - ((otmp->otyp==FROST_HORN) ? AD_COLD-1 : AD_FIRE-1),
1252 | rn1(6,6), mtmp->mx, mtmp->my,
1253 | sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my));
1254 | m_using = FALSE;
1255 | return (mtmp->mhp <= 0) ? 1 : 2;
1256 | case MUSE_WAN_TELEPORTATION:
1257 | case MUSE_WAN_STRIKING:
1258 | zap_oseen = oseen;
1259 | mzapmsg(mtmp, otmp, FALSE);
1260 | otmp->spe--;
1261 | m_using = TRUE;
1262 | mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp);
1263 | m_using = FALSE;
1264 | return 2;
1265 | case MUSE_SCR_EARTH:
1266 | {
1267 | /* TODO: handle steeds */
1268 | register int x, y;
1269 | /* don't use monster fields after killing it */
1270 | boolean confused = (mtmp->mconf ? TRUE : FALSE);
1271 | int mmx = mtmp->mx, mmy = mtmp->my;
1272 |
1273 | mreadmsg(mtmp, otmp);
1274 | /* Identify the scroll */
1275 | if (canspotmon(mtmp)) {
1276 | pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my),
1277 | otmp->blessed ? "around" : "above",
1278 | mon_nam(mtmp));
1279 | if (oseen) makeknown(otmp->otyp);
1280 | } else if (cansee(mtmp->mx, mtmp->my)) {
1281 | pline_The("%s rumbles in the middle of nowhere!",
1282 | ceiling(mtmp->mx, mtmp->my));
1283 | if (mtmp->minvis)
1284 | map_invisible(mtmp->mx, mtmp->my);
1285 | if (oseen) makeknown(otmp->otyp);
1286 | }
1287 |
1288 | /* Loop through the surrounding squares */
1289 | for (x = mmx-1; x <= mmx+1; x++) {
1290 | for (y = mmy-1; y <= mmy+1; y++) {
1291 | /* Is this a suitable spot? */
1292 | if (isok(x, y) && !closed_door(x, y) &&
1293 | !IS_ROCK(levl[x][y].typ) &&
1294 | !IS_AIR(levl[x][y].typ) &&
1295 | (((x == mmx) && (y == mmy)) ?
1296 | !otmp->blessed : !otmp->cursed) &&
1297 | (x != u.ux || y != u.uy)) {
1298 | register struct obj *otmp2;
1299 | register struct monst *mtmp2;
1300 |
1301 | /* Make the object(s) */
1302 | otmp2 = mksobj(confused ? ROCK : BOULDER,
1303 | FALSE, FALSE);
1304 | if (!otmp2) continue; /* Shouldn't happen */
1305 | otmp2->quan = confused ? rn1(5,2) : 1;
1306 | otmp2->owt = weight(otmp2);
1307 |
1308 | /* Find the monster here (might be same as mtmp) */
1309 | mtmp2 = m_at(x, y);
1310 | if (mtmp2 && !amorphous(mtmp2->data) &&
1311 | !passes_walls(mtmp2->data) &&
1312 | !noncorporeal(mtmp2->data) &&
1313 | !unsolid(mtmp2->data)) {
1314 | struct obj *helmet = which_armor(mtmp2, W_ARMH);
1315 | int mdmg;
1316 |
1317 | if (cansee(mtmp2->mx, mtmp2->my)) {
1318 | pline("%s is hit by %s!", Monnam(mtmp2),
1319 | doname(otmp2));
1320 | if (mtmp2->minvis && !canspotmon(mtmp2))
1321 | map_invisible(mtmp2->mx, mtmp2->my);
1322 | }
1323 | mdmg = dmgval(otmp2, mtmp2) * otmp2->quan;
1324 | if (helmet) {
1325 | if(is_metallic(helmet)) {
1326 | if (canspotmon(mtmp2))
1327 | pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp2));
1328 | else if (flags.soundok)
1329 | You_hear("a clanging sound.");
1330 | if (mdmg > 2) mdmg = 2;
1331 | } else {
1332 | if (canspotmon(mtmp2))
1333 | pline("%s's %s does not protect %s.",
1334 | Monnam(mtmp2), xname(helmet),
1335 | him[pronoun_gender(mtmp2)]);
1336 | }
1337 | }
1338 | mtmp2->mhp -= mdmg;
1339 | if (mtmp2->mhp <= 0) {
1340 | pline("%s is killed.", Monnam(mtmp2));
1341 | mondied(mtmp2);
1342 | }
1343 | }
1344 | /* Drop the rock/boulder to the floor */
1345 | if (!flooreffects(otmp2, x, y, "fall")) {
1346 | place_object(otmp2, x, y);
1347 | stackobj(otmp2);
1348 | newsym(x, y); /* map the rock */
1349 | }
1350 | }
1351 | }
1352 | }
1353 | m_useup(mtmp, otmp);
1354 | /* Attack the player */
1355 | if (dist2(mmx, mmy, u.ux, u.uy) == 1 && !otmp->cursed) {
1356 | int dmg;
1357 | struct obj *otmp2;
1358 |
1359 | /* Okay, _you_ write this without repeating the code */
1360 | otmp2 = mksobj(confused ? ROCK : BOULDER,
1361 | FALSE, FALSE);
1362 | if (!otmp2) goto xxx_noobj; /* Shouldn't happen */
1363 | otmp2->quan = confused ? rn1(5,2) : 1;
1364 | otmp2->owt = weight(otmp2);
1365 | if (!amorphous(youmonst.data) &&
1366 | !Passes_walls &&
1367 | !noncorporeal(youmonst.data) &&
1368 | !unsolid(youmonst.data)) {
1369 | You("are hit by %s!", doname(otmp2));
1370 | dmg = dmgval(otmp2, &youmonst) * otmp2->quan;
1371 | if (uarmh) {
1372 | if(is_metallic(uarmh)) {
1373 | pline("Fortunately, you are wearing a hard helmet.");
1374 | if (dmg > 2) dmg = 2;
1375 | } else if (flags.verbose) {
1376 | Your("%s does not protect you.",
1377 | xname(uarmh));
1378 | }
1379 | }
1380 | } else
1381 | dmg = 0;
1382 | if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
1383 | place_object(otmp2, u.ux, u.uy);
1384 | stackobj(otmp2);
1385 | newsym(u.ux, u.uy);
1386 | }
1387 | if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN);
1388 | }
1389 | xxx_noobj:
1390 |
1391 | return (mtmp->mhp <= 0) ? 1 : 2;
1392 | }
1393 | #if 0
1394 | case MUSE_SCR_FIRE:
1395 | {
1396 | boolean vis = cansee(mtmp->mx, mtmp->my);
1397 |
1398 | mreadmsg(mtmp, otmp);
1399 | if (mtmp->mconf) {
1400 | if (vis)
1401 | pline("Oh, what a pretty fire!");
1402 | } else {
1403 | struct monst *mtmp2;
1404 | int num;
1405 |
1406 | if (vis)
1407 | pline_The("scroll erupts in a tower of flame!");
1408 | shieldeff(mtmp->mx, mtmp->my);
1409 | pline("%s is uninjured.", Monnam(mtmp));
1410 | (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
1411 | (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
1412 | (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
1413 | num = (2*(rn1(3, 3) + 2 * bcsign(otmp)) + 1)/3;
1414 | if (Fire_resistance)
1415 | You("are not harmed.");
1416 | burn_away_slime();
1417 | if (Half_spell_damage) num = (num+1) / 2;
1418 | else losehp(num, "scroll of fire", KILLED_BY_AN);
1419 | for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) {
1420 | if(DEADMONSTER(mtmp2)) continue;
1421 | if(mtmp == mtmp2) continue;
1422 | if(dist2(mtmp2->mx,mtmp2->my,mtmp->mx,mtmp->my) < 3){
1423 | if (resists_fire(mtmp2)) continue;
1424 | mtmp2->mhp -= num;
1425 | if (resists_cold(mtmp2))
1426 | mtmp2->mhp -= 3*num;
1427 | if(mtmp2->mhp < 1) {
1428 | mondied(mtmp2);
1429 | break;
1430 | }
1431 | }
1432 | }
1433 | }
1434 | return 2;
1435 | }
1436 | #endif /* 0 */
1437 | case MUSE_POT_PARALYSIS:
1438 | case MUSE_POT_BLINDNESS:
1439 | case MUSE_POT_CONFUSION:
1440 | case MUSE_POT_SLEEPING:
1441 | case MUSE_POT_ACID:
1442 | /* Note: this setting of dknown doesn't suffice. A monster
1443 | * which is out of sight might throw and it hits something _in_
1444 | * sight, a problem not existing with wands because wand rays
1445 | * are not objects. Also set dknown in mthrowu.c.
1446 | */
1447 | if (cansee(mtmp->mx, mtmp->my)) {
1448 | otmp->dknown = 1;
1449 | pline("%s hurls %s!", Monnam(mtmp),
1450 | singular(otmp, doname));
1451 | }
1452 | m_throw(mtmp, mtmp->mx, mtmp->my, sgn(mtmp->mux-mtmp->mx),
1453 | sgn(mtmp->muy-mtmp->my),
1454 | distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp);
1455 | return 2;
1456 | case 0: return 0; /* i.e. an exploded wand */
1457 | default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
1458 | m.has_offense);
1459 | break;
1460 | }
1461 | return 0;
1462 | }
1463 |
1464 | int
1465 | rnd_offensive_item(mtmp)
1466 | struct monst *mtmp;
1467 | {
1468 | struct permonst *pm = mtmp->data;
1469 | int difficulty = monstr[(monsndx(pm))];
1470 |
1471 | if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
1472 | || pm->mlet == S_GHOST
1473 | # ifdef KOPS
1474 | || pm->mlet == S_KOP
1475 | # endif
1476 | ) return 0;
1477 | if (difficulty > 7 && !rn2(35)) return WAN_DEATH;
1478 | switch (rn2(9 - (difficulty < 4) + 4 * (difficulty > 6))) {
1479 | case 0: {
1480 | struct obj *helmet = which_armor(mtmp, W_ARMH);
1481 |
1482 | if ((helmet && is_metallic(helmet)) || amorphous(pm) || passes_walls(pm) || noncorporeal(pm) || unsolid(pm))
1483 | return SCR_EARTH;
1484 | } /* fall through */
1485 | case 1: return WAN_STRIKING;
1486 | case 2: return POT_ACID;
1487 | case 3: return POT_CONFUSION;
1488 | case 4: return POT_BLINDNESS;
1489 | case 5: return POT_SLEEPING;
1490 | case 6: return POT_PARALYSIS;
1491 | case 7: case 8:
1492 | return WAN_MAGIC_MISSILE;
1493 | case 9: return WAN_SLEEP;
1494 | case 10: return WAN_FIRE;
1495 | case 11: return WAN_COLD;
1496 | case 12: return WAN_LIGHTNING;
1497 | }
1498 | /*NOTREACHED*/
1499 | return 0;
1500 | }
1501 |
1502 | #define MUSE_POT_GAIN_LEVEL 1
1503 | #define MUSE_WAN_MAKE_INVISIBLE 2
1504 | #define MUSE_POT_INVISIBILITY 3
1505 | #define MUSE_POLY_TRAP 4
1506 | #define MUSE_WAN_POLYMORPH 5
1507 | #define MUSE_POT_SPEED 6
1508 | #define MUSE_WAN_SPEED_MONSTER 7
1509 | #define MUSE_BULLWHIP 8
1510 | #define MUSE_POT_POLYMORPH 9
1511 |
1512 | boolean
1513 | find_misc(mtmp)
1514 | struct monst *mtmp;
1515 | {
1516 | register struct obj *obj;
1517 | struct permonst *mdat = mtmp->data;
1518 | int x = mtmp->mx, y = mtmp->my;
1519 | struct trap *t;
1520 | int xx, yy;
1521 | boolean immobile = (mdat->mmove == 0);
1522 | boolean stuck = (mtmp == u.ustuck);
1523 |
1524 | m.misc = (struct obj *)0;
1525 | m.has_misc = 0;
1526 | if (is_animal(mdat) || mindless(mdat))
1527 | return 0;
1528 | if (u.uswallow && stuck) return FALSE;
1529 |
1530 | /* We arbitrarily limit to times when a player is nearby for the
1531 | * same reason as Junior Pac-Man doesn't have energizers eaten until
1532 | * you can see them...
1533 | */
1534 | if(dist2(x, y, mtmp->mux, mtmp->muy) > 36)
1535 | return FALSE;
1536 |
1537 | if (!stuck && !immobile && !mtmp->cham && monstr[monsndx(mdat)] < 6) {
1538 | boolean ignore_boulders = (verysmall(mdat) ||
1539 | throws_rocks(mdat) ||
1540 | passes_walls(mdat));
1541 | for(xx = x-1; xx <= x+1; xx++)
1542 | for(yy = y-1; yy <= y+1; yy++)
1543 | if (isok(xx,yy) && (xx != u.ux || yy != u.uy))
1544 | if (mdat != &mons[PM_GRID_BUG] || xx == x || yy == y)
1545 | if (/* (xx==x && yy==y) || */ !level.monsters[xx][yy])
1546 | if ((t = t_at(xx, yy)) != 0 &&
1547 | (ignore_boulders || !sobj_at(BOULDER, xx, yy))
1548 | && !onscary(xx, yy, mtmp)) {
1549 | if (t->ttyp == POLY_TRAP) {
1550 | trapx = xx;
1551 | trapy = yy;
1552 | m.has_misc = MUSE_POLY_TRAP;
1553 | return TRUE;
1554 | }
1555 | }
1556 | }
1557 | if (nohands(mdat))
1558 | return 0;
1559 |
1560 | #define nomore(x) if(m.has_misc==x) continue;
1561 | for(obj=mtmp->minvent; obj; obj=obj->nobj) {
1562 | /* Monsters shouldn't recognize cursed items; this kludge is */
1563 | /* necessary to prevent serious problems though... */
1564 | if(obj->otyp == POT_GAIN_LEVEL && (!obj->cursed ||
1565 | (!mtmp->isgd && !mtmp->isshk && !mtmp->ispriest))) {
1566 | m.misc = obj;
1567 | m.has_misc = MUSE_POT_GAIN_LEVEL;
1568 | }
1569 | nomore(MUSE_BULLWHIP);
1570 | if(obj->otyp == BULLWHIP && (MON_WEP(mtmp) == obj) &&
1571 | distu(mtmp->mx,mtmp->my)==1 && uwep && !mtmp->mpeaceful) {
1572 | m.misc = obj;
1573 | m.has_misc = MUSE_BULLWHIP;
1574 | }
1575 | /* Note: peaceful/tame monsters won't make themselves
1576 | * invisible unless you can see them. Not really right, but...
1577 | */
1578 | nomore(MUSE_WAN_MAKE_INVISIBLE);
1579 | if(obj->otyp == WAN_MAKE_INVISIBLE && obj->spe > 0 &&
1580 | !mtmp->minvis && !mtmp->invis_blkd &&
1581 | (!mtmp->mpeaceful || See_invisible) &&
1582 | (mdat != &mons[PM_MEDUSA] || mtmp->mcan)) {
1583 | m.misc = obj;
1584 | m.has_misc = MUSE_WAN_MAKE_INVISIBLE;
1585 | }
1586 | nomore(MUSE_POT_INVISIBILITY);
1587 | if(obj->otyp == POT_INVISIBILITY &&
1588 | !mtmp->minvis && !mtmp->invis_blkd &&
1589 | (!mtmp->mpeaceful || See_invisible) &&
1590 | (mdat != &mons[PM_MEDUSA] || mtmp->mcan)) {
1591 | m.misc = obj;
1592 | m.has_misc = MUSE_POT_INVISIBILITY;
1593 | }
1594 | nomore(MUSE_WAN_SPEED_MONSTER);
1595 | if(obj->otyp == WAN_SPEED_MONSTER && obj->spe > 0
1596 | && mtmp->mspeed != MFAST && !mtmp->isgd) {
1597 | m.misc = obj;
1598 | m.has_misc = MUSE_WAN_SPEED_MONSTER;
1599 | }
1600 | nomore(MUSE_POT_SPEED);
1601 | if(obj->otyp == POT_SPEED && mtmp->mspeed != MFAST
1602 | && !mtmp->isgd) {
1603 | m.misc = obj;
1604 | m.has_misc = MUSE_POT_SPEED;
1605 | }
1606 | nomore(MUSE_WAN_POLYMORPH);
1607 | if(obj->otyp == WAN_POLYMORPH && obj->spe > 0 && !mtmp->cham
1608 | && monstr[monsndx(mdat)] < 6) {
1609 | m.misc = obj;
1610 | m.has_misc = MUSE_WAN_POLYMORPH;
1611 | }
1612 | nomore(MUSE_POT_POLYMORPH);
1613 | if(obj->otyp == POT_POLYMORPH && !mtmp->cham
1614 | && monstr[monsndx(mdat)] < 6) {
1615 | m.misc = obj;
1616 | m.has_misc = MUSE_POT_POLYMORPH;
1617 | }
1618 | }
1619 | return((boolean)(!!m.has_misc));
1620 | #undef nomore
1621 | }
1622 |
1623 | int
1624 | use_misc(mtmp)
1625 | struct monst *mtmp;
1626 | {
1627 | int i;
1628 | struct obj *otmp = m.misc;
1629 | boolean vis, vismon, oseen;
1630 | char nambuf[BUFSZ];
1631 |
1632 | if ((i = precheck(mtmp, otmp)) != 0) return i;
1633 | vis = cansee(mtmp->mx, mtmp->my);
1634 | vismon = canseemon(mtmp);
1635 | oseen = otmp && vismon;
1636 |
1637 | switch(m.has_misc) {
1638 | case MUSE_POT_GAIN_LEVEL:
1639 | mquaffmsg(mtmp, otmp);
1640 | if (otmp->cursed) {
1641 | if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) {
1642 | register int tolev = depth(&u.uz)-1;
1643 | d_level tolevel;
1644 |
1645 | get_level(&tolevel, tolev);
1646 | /* insurance against future changes... */
1647 | if(on_level(&tolevel, &u.uz)) goto skipmsg;
1648 | if (vismon) {
1649 | pline("%s rises up, through the %s!",
1650 | Monnam(mtmp), ceiling(mtmp->mx, mtmp->my));
1651 | if(!objects[POT_GAIN_LEVEL].oc_name_known
1652 | && !objects[POT_GAIN_LEVEL].oc_uname)
1653 | docall(otmp);
1654 | }
1655 | m_useup(mtmp, otmp);
1656 | migrate_to_level(mtmp, ledger_no(&tolevel),
1657 | MIGR_RANDOM, (coord *)0);
1658 | return 2;
1659 | } else {
1660 | skipmsg:
1661 | if (vismon) {
1662 | pline("%s looks uneasy.", Monnam(mtmp));
1663 | if(!objects[POT_GAIN_LEVEL].oc_name_known
1664 | && !objects[POT_GAIN_LEVEL].oc_uname)
1665 | docall(otmp);
1666 | }
1667 | m_useup(mtmp, otmp);
1668 | return 2;
1669 | }
1670 | }
1671 | if (vismon) pline("%s seems more experienced.", Monnam(mtmp));
1672 | if (oseen) makeknown(POT_GAIN_LEVEL);
1673 | m_useup(mtmp, otmp);
1674 | if (!grow_up(mtmp,(struct monst *)0)) return 1;
1675 | /* grew into genocided monster */
1676 | return 2;
1677 | case MUSE_WAN_MAKE_INVISIBLE:
1678 | case MUSE_POT_INVISIBILITY:
1679 | if (otmp->otyp == WAN_MAKE_INVISIBLE) {
1680 | mzapmsg(mtmp, otmp, TRUE);
1681 | otmp->spe--;
1682 | } else
1683 | mquaffmsg(mtmp, otmp);
1684 | /* format monster's name before altering its visibility */
1685 | Strcpy(nambuf, See_invisible ? Monnam(mtmp) : mon_nam(mtmp));
1686 | mon_set_minvis(mtmp);
1687 | if (vismon && mtmp->minvis) { /* was seen, now invisible */
1688 | if (See_invisible)
1689 | pline("%s body takes on a %s transparency.",
1690 | s_suffix(nambuf),
1691 | Hallucination ? "normal" : "strange");
1692 | else
1693 | pline("Suddenly you cannot see %s.", nambuf);
1694 | if (oseen) makeknown(otmp->otyp);
1695 | }
1696 | if (otmp->otyp == POT_INVISIBILITY) {
1697 | if (otmp->cursed) you_aggravate(mtmp);
1698 | m_useup(mtmp, otmp);
1699 | }
1700 | return 2;
1701 | case MUSE_WAN_SPEED_MONSTER:
1702 | mzapmsg(mtmp, otmp, TRUE);
1703 | otmp->spe--;
1704 | mon_adjust_speed(mtmp, 1);
1705 | return 2;
1706 | case MUSE_POT_SPEED:
1707 | mquaffmsg(mtmp, otmp);
1708 | /* note difference in potion effect due to substantially
1709 | different methods of maintaining speed ratings:
1710 | player's character becomes "very fast" temporarily;
1711 | monster becomes "one stage faster" permanently */
1712 | if (vismon)
1713 | pline("%s is suddenly moving faster.", Monnam(mtmp));
1714 | if (oseen) makeknown(POT_SPEED);
1715 | mon_adjust_speed(mtmp, 1);
1716 | m_useup(mtmp, otmp);
1717 | return 2;
1718 | case MUSE_WAN_POLYMORPH:
1719 | mzapmsg(mtmp, otmp, TRUE);
1720 | otmp->spe--;
1721 | (void) newcham(mtmp, rndmonst());
1722 | if (oseen) makeknown(WAN_POLYMORPH);
1723 | return 2;
1724 | case MUSE_POT_POLYMORPH:
1725 | mquaffmsg(mtmp, otmp);
1726 | if (vismon) pline("%s suddenly mutates!", Monnam(mtmp));
1727 | (void) newcham(mtmp, rndmonst());
1728 | if (oseen) makeknown(POT_POLYMORPH);
1729 | m_useup(mtmp, otmp);
1730 | return 2;
1731 | case MUSE_POLY_TRAP:
1732 | if (vismon)
1733 | pline("%s deliberately %s onto a polymorph trap!",
1734 | Monnam(mtmp),
1735 | makeplural(locomotion(mtmp->data, "jump")));
1736 | if (vis) seetrap(t_at(trapx,trapy));
1737 |
1738 | /* don't use rloc() due to worms */
1739 | remove_monster(mtmp->mx, mtmp->my);
1740 | newsym(mtmp->mx, mtmp->my);
1741 | place_monster(mtmp, trapx, trapy);
1742 | if (mtmp->wormno) worm_move(mtmp);
1743 | newsym(trapx, trapy);
1744 |
1745 | (void) newcham(mtmp, (struct permonst *)0);
1746 | return 2;
1747 | case MUSE_BULLWHIP:
1748 | /* attempt to disarm hero */
1749 | if (uwep && !rn2(5)) {
1750 | const char *The_whip = vismon ? "The bullwhip" : "A whip";
1751 | int where_to = rn2(4);
1752 | struct obj *obj = uwep;
1753 | const char *hand;
1754 | char the_weapon[BUFSZ];
1755 |
1756 | Strcpy(the_weapon, the(xname(obj)));
1757 | hand = body_part(HAND);
1758 | if (bimanual(obj)) hand = makeplural(hand);
1759 |
1760 | if (vismon)
1761 | pline("%s flicks a bullwhip towards your %s!",
1762 | Monnam(mtmp), hand);
1763 | if (obj->otyp == HEAVY_IRON_BALL) {
1764 | pline("%s fails to wrap around %s.",
1765 | The_whip, the_weapon);
1766 | return 1;
1767 | }
1768 | pline("%s wraps around %s you're wielding!",
1769 | The_whip, the_weapon);
1770 | if (obj->cursed) {
1771 | pline("%s is welded to your %s%c",
1772 | (obj->quan == 1L) ? "It" : "They",
1773 | hand, !obj->bknown ? '!' : '.');
1774 | obj->bknown = 1;
1775 | where_to = 0;
1776 | }
1777 | if (!where_to) {
1778 | pline_The("whip slips free."); /* not `The_whip' */
1779 | return 1;
1780 | }
1781 | freeinv(obj);
1782 | uwepgone();
1783 | switch (where_to) {
1784 | case 1: /* onto floor beneath mon */
1785 | pline("%s yanks %s from your %s!", Monnam(mtmp),
1786 | the_weapon, hand);
1787 | if (obj->otyp == CRYSKNIFE && (!obj->oerodeproof || !rn2(10))) {
1788 | obj->otyp = WORM_TOOTH;
1789 | obj->oerodeproof = 0;
1790 | }
1791 | place_object(obj, mtmp->mx, mtmp->my);
1792 | break;
1793 | case 2: /* onto floor beneath you */
1794 | pline("%s yanks %s to the %s!", Monnam(mtmp),
1795 | the_weapon, surface(u.ux, u.uy));
1796 | dropy(obj);
1797 | break;
1798 | case 3: /* into mon's inventory */
1799 | pline("%s snatches %s!", Monnam(mtmp),
1800 | the_weapon);
1801 | (void) mpickobj(mtmp,obj);
1802 | break;
1803 | }
1804 | return 1;
1805 | }
1806 | return 0;
1807 | case 0: return 0; /* i.e. an exploded wand */
1808 | default: impossible("%s wanted to perform action %d?", Monnam(mtmp),
1809 | m.has_misc);
1810 | break;
1811 | }
1812 | return 0;
1813 | }
1814 |
1815 | STATIC_OVL void
1816 | you_aggravate(mtmp)
1817 | struct monst *mtmp;
1818 | {
1819 | pline("For some reason, %s presence is known to you.",
1820 | s_suffix(noit_mon_nam(mtmp)));
1821 | cls();
1822 | #ifdef CLIPPING
1823 | cliparound(mtmp->mx, mtmp->my);
1824 | #endif
1825 | show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp));
1826 | display_self();
1827 | You_feel("aggravated at %s.", noit_mon_nam(mtmp));
1828 | display_nhwindow(WIN_MAP, TRUE);
1829 | docrt();
1830 | if (unconscious()) {
1831 | multi = -1;
1832 | nomovemsg =
1833 | "Aggravated, you are jolted into full consciousness.";
1834 | }
1835 | newsym(mtmp->mx,mtmp->my);
1836 | if (!canspotmon(mtmp))
1837 | map_invisible(mtmp->mx, mtmp->my);
1838 | }
1839 |
1840 | int
1841 | rnd_misc_item(mtmp)
1842 | struct monst *mtmp;
1843 | {
1844 | struct permonst *pm = mtmp->data;
1845 | int difficulty = monstr[(monsndx(pm))];
1846 |
1847 | if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
1848 | || pm->mlet == S_GHOST
1849 | # ifdef KOPS
1850 | || pm->mlet == S_KOP
1851 | # endif
1852 | ) return 0;
1853 | /* Unlike other rnd_item functions, we only allow _weak_ monsters
1854 | * to have this item; after all, the item will be used to strengthen
1855 | * the monster and strong monsters won't use it at all...
1856 | */
1857 | if (difficulty < 6 && !rn2(30))
1858 | return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH;
1859 |
1860 | if (!rn2(40) && !nonliving(pm)) return AMULET_OF_LIFE_SAVING;
1861 |
1862 | switch (rn2(3)) {
1863 | case 0:
1864 | if (mtmp->isgd) return 0;
1865 | return rn2(6) ? POT_SPEED : WAN_SPEED_MONSTER;
1866 | case 1:
1867 | if (mtmp->mpeaceful && !See_invisible) return 0;
1868 | return rn2(6) ? POT_INVISIBILITY : WAN_MAKE_INVISIBLE;
1869 | case 2:
1870 | return POT_GAIN_LEVEL;
1871 | }
1872 | /*NOTREACHED*/
1873 | return 0;
1874 | }
1875 |
1876 | boolean
1877 | searches_for_item(mon, obj)
1878 | struct monst *mon;
1879 | struct obj *obj;
1880 | {
1881 | int typ = obj->otyp;
1882 |
1883 | if (is_animal(mon->data) ||
1884 | mindless(mon->data) ||
1885 | mon->data == &mons[PM_GHOST]) /* don't loot bones piles */
1886 | return FALSE;
1887 |
1888 | if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY)
1889 | return (boolean)(!mon->minvis && !mon->invis_blkd);
1890 | if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED)
1891 | return (boolean)(mon->mspeed != MFAST);
1892 |
1893 | switch (obj->oclass) {
1894 | case WAND_CLASS:
1895 | if (typ == WAN_DIGGING)
1896 | return (boolean)(!is_floater(mon->data));
1897 | if (typ == WAN_POLYMORPH)
1898 | return (boolean)(monstr[monsndx(mon->data)] < 6);
1899 | if (objects[typ].oc_dir == RAY ||
1900 | typ == WAN_STRIKING ||
1901 | typ == WAN_TELEPORTATION ||
1902 | typ == WAN_CREATE_MONSTER)
1903 | return TRUE;
1904 | break;
1905 | case POTION_CLASS:
1906 | if (typ == POT_HEALING ||
1907 | typ == POT_EXTRA_HEALING ||
1908 | typ == POT_FULL_HEALING ||
1909 | typ == POT_POLYMORPH ||
1910 | typ == POT_GAIN_LEVEL ||
1911 | typ == POT_PARALYSIS ||
1912 | typ == POT_SLEEPING ||
1913 | typ == POT_ACID ||
1914 | typ == POT_BLINDNESS ||
1915 | typ == POT_CONFUSION)
1916 | return TRUE;
1917 | break;
1918 | case SCROLL_CLASS:
1919 | if (typ == SCR_TELEPORTATION || typ == SCR_CREATE_MONSTER
1920 | || typ == SCR_EARTH)
1921 | return TRUE;
1922 | break;
1923 | case AMULET_CLASS:
1924 | if (typ == AMULET_OF_LIFE_SAVING)
1925 | return (boolean)(!nonliving(mon->data));
1926 | if (typ == AMULET_OF_REFLECTION)
1927 | return TRUE;
1928 | break;
1929 | case TOOL_CLASS:
1930 | if (typ == PICK_AXE)
1931 | return (boolean)needspick(mon->data);
1932 | if (typ == UNICORN_HORN)
1933 | return (boolean)(!obj->cursed && !is_unicorn(mon->data));
1934 | if (typ == FROST_HORN || typ == FIRE_HORN)
1935 | return TRUE;
1936 | break;
1937 | case FOOD_CLASS:
1938 | if (typ == CORPSE)
1939 | return (boolean)(((mon->misc_worn_check & W_ARMG) &&
1940 | touch_petrifies(&mons[obj->corpsenm])) ||
1941 | (!resists_ston(mon) &&
1942 | (obj->corpsenm == PM_LIZARD ||
1943 | acidic(&mons[obj->corpsenm]))));
1944 | if (typ == EGG)
1945 | return (boolean)(touch_petrifies(&mons[obj->corpsenm]));
1946 | break;
1947 | default:
1948 | break;
1949 | }
1950 |
1951 | return FALSE;
1952 | }
1953 |
1954 | boolean
1955 | mon_reflects(mon,str)
1956 | struct monst *mon;
1957 | const char *str;
1958 | {
1959 | struct obj *orefl = which_armor(mon, W_ARMS);
1960 |
1961 | if (orefl && orefl->otyp == SHIELD_OF_REFLECTION) {
1962 | if (str) {
1963 | pline(str, s_suffix(mon_nam(mon)), "shield");
1964 | makeknown(SHIELD_OF_REFLECTION);
1965 | }
1966 | return TRUE;
1967 | } else if ((orefl = which_armor(mon, W_AMUL)) &&
1968 | orefl->otyp == AMULET_OF_REFLECTION) {
1969 | if (str) {
1970 | pline(str, s_suffix(mon_nam(mon)), "amulet");
1971 | makeknown(AMULET_OF_REFLECTION);
1972 | }
1973 | return TRUE;
1974 | } else if ((orefl = which_armor(mon, W_ARM)) &&
1975 | (orefl->otyp == SILVER_DRAGON_SCALES || orefl->otyp == SILVER_DRAGON_SCALE_MAIL)) {
1976 | if (str)
1977 | pline(str, s_suffix(mon_nam(mon)), "armor");
1978 | return TRUE;
1979 | } else if (mon->data == &mons[PM_SILVER_DRAGON]) {
1980 | /* Silver dragons only reflect when mature; babies do not */
1981 | if (str)
1982 | pline(str, s_suffix(mon_nam(mon)), "scales");
1983 | return TRUE;
1984 | }
1985 | return FALSE;
1986 | }
1987 |
1988 | boolean
1989 | ureflects (fmt, str)
1990 | const char *fmt, *str;
1991 | {
1992 | /* Check from outermost to innermost objects */
1993 | if (EReflecting & W_ARMS) {
1994 | if (fmt && str) {
1995 | pline(fmt, str, "shield");
1996 | makeknown(SHIELD_OF_REFLECTION);
1997 | }
1998 | return TRUE;
1999 | } else if (EReflecting & W_WEP) {
2000 | /* Due to wielded artifact weapon */
2001 | if (fmt && str)
2002 | pline(fmt, str, "weapon");
2003 | return TRUE;
2004 | } else if (EReflecting & W_AMUL) {
2005 | if (fmt && str) {
2006 | pline(fmt, str, "medallion");
2007 | makeknown(AMULET_OF_REFLECTION);
2008 | }
2009 | return TRUE;
2010 | } else if (EReflecting & W_ARM) {
2011 | if (fmt && str)
2012 | pline(fmt, str, "armor");
2013 | return TRUE;
2014 | } else if (youmonst.data == &mons[PM_SILVER_DRAGON]) {
2015 | if (fmt && str)
2016 | pline(fmt, str, "scales");
2017 | return TRUE;
2018 | }
2019 | return FALSE;
2020 | }
2021 |
2022 |
2023 | /* TRUE if the monster ate something */
2024 | boolean
2025 | munstone(mon, by_you)
2026 | struct monst *mon;
2027 | boolean by_you;
2028 | {
2029 | struct obj *obj;
2030 |
2031 | if (resists_ston(mon)) return FALSE;
2032 | if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE;
2033 |
2034 | for(obj = mon->minvent; obj; obj = obj->nobj) {
2035 | /* Monsters can also use potions of acid */
2036 | if ((obj->otyp == POT_ACID) || (obj->otyp == CORPSE &&
2037 | (obj->corpsenm == PM_LIZARD || acidic(&mons[obj->corpsenm])))) {
2038 | int nutrit = dog_nutrition(mon, obj); /* also sets meating */
2039 |
2040 | if (canseemon(mon)) {
2041 | long save_quan = obj->quan;
2042 |
2043 | obj->quan = 1L;
2044 | pline("%s %ss %s.", Monnam(mon),
2045 | (obj->otyp == POT_ACID) ? "quaff" : "eat",
2046 | distant_name(obj,doname));
2047 | obj->quan = save_quan;
2048 | } else if (flags.soundok)
2049 | You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing");
2050 | m_useup(mon, obj);
2051 | if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) &&
2052 | !resists_acid(mon)) {
2053 | mon->mhp -= rnd(15);
2054 | pline("%s has a very bad case of stomach acid.",
2055 | Monnam(mon));
2056 | }
2057 | if (mon->mhp <= 0) {
2058 | pline("%s dies!", Monnam(mon));
2059 | if (by_you) xkilled(mon, 0);
2060 | else mondead(mon);
2061 | return TRUE;
2062 | }
2063 | if (canseemon(mon)) {
2064 | if (Hallucination)
2065 | pline("What a pity - %s just ruined a future piece of art!",
2066 | mon_nam(mon));
2067 | else
2068 | pline("%s seems limber!", Monnam(mon));
2069 | }
2070 | if (mon->mtame && !mon->isminion) {
2071 | struct edog *edog = EDOG(mon);
2072 |
2073 | if (edog->hungrytime < moves) edog->hungrytime = moves;
2074 | edog->hungrytime += nutrit;
2075 | mon->mconf = 0;
2076 | }
2077 | mon->mlstmv = monstermoves; /* it takes a turn */
2078 | return TRUE;
2079 | }
2080 | }
2081 | return FALSE;
2082 | }
2083 |
2084 | /*muse.c*/