1 /* SCCS Id: @(#)mon.c 3.3 2000/07/24 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /* If you're using precompiled headers, you don't want this either */
6 #ifdef MICROPORT_BUG
7 #define MKROOM_H
8 #endif
9
10 #include "hack.h"
11 #include "mfndpos.h"
12 #include "edog.h"
13 #include <ctype.h>
14
15 STATIC_DCL boolean FDECL(corpse_chance,(struct monst *));
16 STATIC_DCL boolean FDECL(restrap,(struct monst *));
17 STATIC_DCL long FDECL(mm_aggression, (struct monst *,struct monst *));
18 #ifdef OVL2
19 STATIC_DCL int NDECL(pick_animal);
20 STATIC_DCL int FDECL(select_newcham_form, (struct monst *));
21 STATIC_DCL void FDECL(kill_eggs, (struct obj *));
22 #endif
23
24 #if 0
25 /* part of the original warning code which was replaced in 3.3.1 */
26 #ifdef OVL1
27 #define warnDelay 10
28 long lastwarntime;
29 int lastwarnlev;
30
31 const char *warnings[] = {
32 "white", "pink", "red", "ruby", "purple", "black"
33 };
34
35 STATIC_DCL void NDECL(warn_effects);
36 #endif /* OVL1 */
37 #endif /* 0 */
38
39 #ifndef OVLB
40 STATIC_VAR short cham_to_pm[];
41 #else
42 STATIC_DCL struct obj *FDECL(make_corpse,(struct monst *));
43 STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *));
44 STATIC_DCL void FDECL(lifesaved_monster, (struct monst *));
45
46 /* convert the monster index of an undead to its living counterpart */
47 int
undead_to_corpse(mndx)48 undead_to_corpse(mndx)
49 int mndx;
50 {
51 switch (mndx) {
52 case PM_KOBOLD_ZOMBIE:
53 case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break;
54 case PM_DWARF_ZOMBIE:
55 case PM_DWARF_MUMMY: mndx = PM_DWARF; break;
56 case PM_GNOME_ZOMBIE:
57 case PM_GNOME_MUMMY: mndx = PM_GNOME; break;
58 case PM_ORC_ZOMBIE:
59 case PM_ORC_MUMMY: mndx = PM_ORC; break;
60 case PM_ELF_ZOMBIE:
61 case PM_ELF_MUMMY: mndx = PM_ELF; break;
62 case PM_VAMPIRE:
63 case PM_VAMPIRE_LORD:
64 #if 0 /* DEFERRED */
65 case PM_VAMPIRE_MAGE:
66 #endif
67 case PM_HUMAN_ZOMBIE:
68 case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break;
69 case PM_GIANT_ZOMBIE:
70 case PM_GIANT_MUMMY: mndx = PM_GIANT; break;
71 case PM_ETTIN_ZOMBIE:
72 case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break;
73 default: break;
74 }
75 return mndx;
76 }
77
78 /* convert monster index to chameleon index */
79 int
pm_to_cham(mndx)80 pm_to_cham(mndx)
81 int mndx;
82 {
83 int mcham;
84
85 switch (mndx) {
86 case PM_CHAMELEON: mcham = CHAM_CHAMELEON; break;
87 case PM_DOPPELGANGER: mcham = CHAM_DOPPELGANGER; break;
88 case PM_SANDESTIN: mcham = CHAM_SANDESTIN; break;
89 default: mcham = CHAM_ORDINARY; break;
90 }
91 return mcham;
92 }
93
94 /* convert chameleon index to monster index */
95 STATIC_VAR short cham_to_pm[] = {
96 NON_PM, /* placeholder for CHAM_ORDINARY */
97 PM_CHAMELEON,
98 PM_DOPPELGANGER,
99 PM_SANDESTIN,
100 };
101
102 /* return TRUE if the monster tends to revive */
103 #define REVIVER(ptr) (is_rider(ptr) || ptr->mlet == S_TROLL)
104
105 #define KEEPTRAITS(mon) (mon->isshk || mon->mtame || \
106 (mon->data->geno & G_UNIQ) || REVIVER(mon->data))
107
108 /* Creates a monster corpse, a "special" corpse, or nothing if it doesn't
109 * leave corpses. Monsters which leave "special" corpses should have
110 * G_NOCORPSE set in order to prevent wishing for one, finding tins of one,
111 * etc....
112 */
113 STATIC_OVL struct obj *
make_corpse(mtmp)114 make_corpse(mtmp)
115 register struct monst *mtmp;
116 {
117 register struct permonst *mdat = mtmp->data;
118 int num;
119 struct obj *obj = (struct obj *)0;
120 int x = mtmp->mx, y = mtmp->my;
121 int mndx = monsndx(mdat);
122
123 switch(mndx) {
124 case PM_GRAY_DRAGON:
125 case PM_SILVER_DRAGON:
126 #if 0 /* DEFERRED */
127 case PM_SHIMMERING_DRAGON:
128 #endif
129 case PM_RED_DRAGON:
130 case PM_ORANGE_DRAGON:
131 case PM_WHITE_DRAGON:
132 case PM_BLACK_DRAGON:
133 case PM_BLUE_DRAGON:
134 case PM_GREEN_DRAGON:
135 case PM_YELLOW_DRAGON:
136 /* Make dragon scales. This assumes that the order of the */
137 /* dragons is the same as the order of the scales. */
138 if (!rn2(mtmp->mrevived ? 20 : 3)) {
139 obj = mksobj_at(GRAY_DRAGON_SCALES +
140 monsndx(mdat)-PM_GRAY_DRAGON, x, y, FALSE);
141 obj->spe = 0;
142 obj->cursed = obj->blessed = FALSE;
143 }
144 goto default_1;
145
146 case PM_WHITE_UNICORN:
147 case PM_GRAY_UNICORN:
148 case PM_BLACK_UNICORN:
149 (void) mksobj_at(UNICORN_HORN, x, y, TRUE);
150 goto default_1;
151 case PM_LONG_WORM:
152 (void) mksobj_at(WORM_TOOTH, x, y, TRUE);
153 goto default_1;
154 case PM_VAMPIRE:
155 case PM_VAMPIRE_LORD:
156 /* include mtmp in the mkcorpstat() call */
157 num = undead_to_corpse(mndx);
158 obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE);
159 obj->age -= 100; /* this is an *OLD* corpse */
160 break;
161 case PM_KOBOLD_MUMMY:
162 case PM_DWARF_MUMMY:
163 case PM_GNOME_MUMMY:
164 case PM_ORC_MUMMY:
165 case PM_ELF_MUMMY:
166 case PM_HUMAN_MUMMY:
167 case PM_GIANT_MUMMY:
168 case PM_ETTIN_MUMMY:
169 case PM_KOBOLD_ZOMBIE:
170 case PM_DWARF_ZOMBIE:
171 case PM_GNOME_ZOMBIE:
172 case PM_ORC_ZOMBIE:
173 case PM_ELF_ZOMBIE:
174 case PM_HUMAN_ZOMBIE:
175 case PM_GIANT_ZOMBIE:
176 case PM_ETTIN_ZOMBIE:
177 num = undead_to_corpse(mndx);
178 obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE);
179 obj->age -= 100; /* this is an *OLD* corpse */
180 break;
181 case PM_IRON_GOLEM:
182 num = d(2,6);
183 while (num--)
184 obj = mksobj_at(IRON_CHAIN, x, y, TRUE);
185 mtmp->mnamelth = 0;
186 break;
187 case PM_GLASS_GOLEM:
188 num = d(2,4); /* very low chance of creating all glass gems */
189 while (num--)
190 obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE);
191 mtmp->mnamelth = 0;
192 break;
193 case PM_CLAY_GOLEM:
194 obj = mksobj_at(ROCK, x, y, FALSE);
195 obj->quan = (long)(rn2(20) + 50);
196 obj->owt = weight(obj);
197 mtmp->mnamelth = 0;
198 break;
199 case PM_STONE_GOLEM:
200 obj = mkcorpstat(STATUE, (struct monst *)0,
201 mdat, x, y, FALSE);
202 break;
203 case PM_WOOD_GOLEM:
204 num = d(2,4);
205 while(num--) {
206 obj = mksobj_at(QUARTERSTAFF, x, y, TRUE);
207 if (obj && obj->oartifact) { /* don't allow this */
208 artifact_exists(obj, ONAME(obj), FALSE);
209 Strcpy(ONAME(obj), ""); obj->onamelth = 0;
210 }
211 }
212 mtmp->mnamelth = 0;
213 break;
214 case PM_LEATHER_GOLEM:
215 num = d(2,4);
216 while(num--)
217 obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE);
218 mtmp->mnamelth = 0;
219 break;
220 case PM_GOLD_GOLEM:
221 /* Good luck gives more coins */
222 obj = mkgold((long)(200 - rnl(101)), x, y);
223 mtmp->mnamelth = 0;
224 break;
225 case PM_PAPER_GOLEM:
226 num = d(2,3);
227 while (num--)
228 obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE);
229 mtmp->mnamelth = 0;
230 break;
231 default_1:
232 default:
233 if (mvitals[mndx].mvflags & G_NOCORPSE)
234 return (struct obj *)0;
235 else /* preserve the unique traits of some creatures */
236 obj = mkcorpstat(CORPSE, KEEPTRAITS(mtmp) ? mtmp : 0,
237 mdat, x, y, TRUE);
238 break;
239 }
240 /* All special cases should precede the G_NOCORPSE check */
241
242 if (mtmp->mnamelth)
243 obj = oname(obj, NAME(mtmp));
244
245 #ifdef INVISIBLE_OBJECTS
246 /* Invisible monster ==> invisible corpse */
247 obj->oinvis = mtmp->minvis;
248 #endif
249
250 stackobj(obj);
251 newsym(x, y);
252 return obj;
253 }
254
255 #endif /* OVLB */
256 #ifdef OVL1
257
258 #if 0
259 /* part of the original warning code which was replaced in 3.3.1 */
260 STATIC_OVL void
261 warn_effects()
262 {
263 if (warnlevel == 100) {
264 if(!Blind && uwep &&
265 (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) {
266 Your("%s %s!", aobjnam(uwep, "glow"),
267 hcolor(light_blue));
268 lastwarnlev = warnlevel;
269 lastwarntime = moves;
270 }
271 warnlevel = 0;
272 return;
273 }
274
275 if (warnlevel >= SIZE(warnings))
276 warnlevel = SIZE(warnings)-1;
277 if (!Blind &&
278 (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) {
279 const char *which, *what, *how;
280 long rings = (EWarning & (LEFT_RING|RIGHT_RING));
281
282 if (rings) {
283 what = Hallucination ? "mood ring" : "ring";
284 how = "glows"; /* singular verb */
285 if (rings == LEFT_RING) {
286 which = "left ";
287 } else if (rings == RIGHT_RING) {
288 which = "right ";
289 } else { /* both */
290 which = "";
291 what = (const char *) makeplural(what);
292 how = "glow"; /* plural verb */
293 }
294 Your("%s%s %s %s!", which, what, how, hcolor(warnings[warnlevel]));
295 } else {
296 if (Hallucination)
297 Your("spider-sense is tingling...");
298 else
299 You_feel("apprehensive as you sense a %s flash.",
300 warnings[warnlevel]);
301 }
302
303 lastwarntime = moves;
304 lastwarnlev = warnlevel;
305 }
306 }
307 #endif /* 0 */
308
309 /* check mtmp and water for compatibility, 0 (survived), 1 (drowned) */
310 int
minwater(mtmp)311 minwater(mtmp)
312 register struct monst *mtmp;
313 {
314 boolean inpool, infountain;
315
316 inpool = is_pool(mtmp->mx,mtmp->my) &&
317 !is_flyer(mtmp->data) && !is_floater(mtmp->data);
318 infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ);
319
320 #ifdef STEED
321 /* Flying and levitation keeps our steed out of the water */
322 /* (but not water-walking or swimming) */
323 if (mtmp == u.usteed && (Flying || Levitation))
324 return (0);
325 #endif
326
327 /* Gremlin multiplying won't go on forever since the hit points
328 * keep going down, and when it gets to 1 hit point the clone
329 * function will fail.
330 */
331 if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) {
332 if (split_mon(mtmp, (struct monst *)0))
333 dryup(mtmp->mx, mtmp->my, FALSE);
334 if (inpool) water_damage(mtmp->minvent, FALSE, FALSE);
335 return (0);
336 } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) {
337 int dam = d(2,6);
338 if (cansee(mtmp->mx,mtmp->my))
339 pline("%s rusts.", Monnam(mtmp));
340 mtmp->mhp -= dam;
341 if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam;
342 if (mtmp->mhp < 1) {
343 mondead(mtmp);
344 if (mtmp->mhp < 1) return (1);
345 }
346 water_damage(mtmp->minvent, FALSE, FALSE);
347 return (0);
348 }
349
350 if (inpool) {
351 /* Most monsters drown in pools. flooreffects() will take care of
352 * water damage to dead monsters' inventory, but survivors need to
353 * be handled here. Swimmers are able to protect their stuff...
354 */
355 if (!is_clinger(mtmp->data)
356 && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) {
357 if (cansee(mtmp->mx,mtmp->my)) {
358 pline("%s drowns.", Monnam(mtmp));
359 }
360 mondead(mtmp);
361 if (mtmp->mhp > 0) {
362 rloc(mtmp);
363 water_damage(mtmp->minvent, FALSE, FALSE);
364 return 0;
365 }
366 return (1);
367 }
368 } else {
369 /* but eels have a difficult time outside */
370 if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) {
371 if(mtmp->mhp > 1) mtmp->mhp--;
372 mtmp->mflee = 1;
373 mtmp->mfleetim += 2;
374 }
375 }
376 return (0);
377 }
378
379
380 int
mcalcmove(mon)381 mcalcmove(mon)
382 struct monst *mon;
383 {
384 int mmove = mon->data->mmove;
385
386 /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
387 * MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
388 * both adjustments have negligible effect on higher speeds.
389 */
390 if (mon->mspeed == MSLOW)
391 mmove = (2 * mmove + 1) / 3;
392 else if (mon->mspeed == MFAST)
393 mmove = (4 * mmove + 2) / 3;
394
395 #ifdef STEED
396 if (mon == u.usteed) {
397 if (u.ugallop && flags.mv) {
398 /* average movement is 1.50 times normal */
399 mmove = ((rn2(2) ? 4 : 5) * mmove) / 3;
400 }
401 }
402 #endif
403
404 return mmove;
405 }
406
407 /* actions that happen once per ``turn'', regardless of each
408 individual monster's metabolism; some of these might need to
409 be reclassified to occur more in proportion with movement rate */
410 void
mcalcdistress()411 mcalcdistress()
412 {
413 struct monst *mtmp;
414
415 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
416 if (DEADMONSTER(mtmp)) continue;
417
418 /* regenerate hit points */
419 mon_regen(mtmp, FALSE);
420
421 /* possibly polymorph shapechangers and lycanthropes */
422 if (mtmp->cham && !rn2(6))
423 (void) newcham(mtmp, (struct permonst *)0);
424 were_change(mtmp);
425
426 /* gradually time out temporary problems */
427 if (mtmp->mblinded && !--mtmp->mblinded)
428 mtmp->mcansee = 1;
429 if (mtmp->mfrozen && !--mtmp->mfrozen)
430 mtmp->mcanmove = 1;
431 if (mtmp->mfleetim && !--mtmp->mfleetim)
432 mtmp->mflee = 0;
433
434 /* FIXME: mtmp->mlstmv ought to be updated here */
435 }
436 }
437
438 int
movemon()439 movemon()
440 {
441 register struct monst *mtmp, *nmtmp;
442 register boolean somebody_can_move = FALSE;
443 #if 0
444 /* part of the original warning code which was replaced in 3.3.1 */
445 warnlevel = 0;
446 #endif
447
448 /*
449 Some of you may remember the former assertion here that
450 because of deaths and other actions, a simple one-pass
451 algorithm wasn't possible for movemon. Deaths are no longer
452 removed to the separate list fdmon; they are simply left in
453 the chain with hit points <= 0, to be cleaned up at the end
454 of the pass.
455
456 The only other actions which cause monsters to be removed from
457 the chain are level migrations and losedogs(). I believe losedogs()
458 is a cleanup routine not associated with monster movements, and
459 monsters can only affect level migrations on themselves, not others
460 (hence the fetching of nmon before moving the monster). Currently,
461 monsters can jump into traps, read cursed scrolls of teleportation,
462 and drink cursed potions of raise level to change levels. These are
463 all reflexive at this point. Should one monster be able to level
464 teleport another, this scheme would have problems.
465 */
466
467 for(mtmp = fmon; mtmp; mtmp = nmtmp) {
468 nmtmp = mtmp->nmon;
469
470 /* Find a monster that we have not treated yet. */
471 if(DEADMONSTER(mtmp))
472 continue;
473 if(mtmp->movement < NORMAL_SPEED)
474 continue;
475
476 mtmp->movement -= NORMAL_SPEED;
477 if (mtmp->movement >= NORMAL_SPEED)
478 somebody_can_move = TRUE;
479
480 if (minwater(mtmp)) continue;
481
482 if (is_hider(mtmp->data)) {
483 /* unwatched mimics and piercers may hide again [MRS] */
484 if(restrap(mtmp)) continue;
485 if(mtmp->m_ap_type == M_AP_FURNITURE ||
486 mtmp->m_ap_type == M_AP_OBJECT)
487 continue;
488 if(mtmp->mundetected) continue;
489 }
490
491 /* continue if the monster died fighting */
492 if (Conflict && !mtmp->iswiz && mtmp->mcansee) {
493 /* Note:
494 * Conflict does not take effect in the first round.
495 * Therefore, A monster when stepping into the area will
496 * get to swing at you.
497 *
498 * The call to fightm() must be _last_. The monster might
499 * have died if it returns 1.
500 */
501 if (couldsee(mtmp->mx,mtmp->my) &&
502 (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) &&
503 fightm(mtmp))
504 continue; /* mon might have died */
505 }
506 if(dochugw(mtmp)) /* otherwise just move the monster */
507 continue;
508 }
509 #if 0
510 /* part of the original warning code which was replaced in 3.3.1 */
511 if(warnlevel > 0)
512 warn_effects();
513 #endif
514
515 if (any_light_source())
516 vision_full_recalc = 1; /* in case a mon moved with a light source */
517 dmonsfree(); /* remove all dead monsters */
518
519 /* a monster may have levteleported player -dlc */
520 if (u.utotype) {
521 deferred_goto();
522 /* changed levels, so these monsters are dormant */
523 somebody_can_move = FALSE;
524 }
525
526 return somebody_can_move;
527 }
528
529 #endif /* OVL1 */
530 #ifdef OVLB
531
532 #define mstoning(obj) (ofood(obj) && \
533 (touch_petrifies(&mons[(obj)->corpsenm]) || \
534 (obj)->corpsenm == PM_MEDUSA))
535
536 /*
537 * Maybe eat a metallic object (not just gold).
538 * Return value: 0 => nothing happened, 1 => monster ate something,
539 * 2 => monster died (it must have grown into a genocided form, but
540 * that can't happen at present because nothing which eats objects
541 * has young and old forms).
542 */
543 int
meatgold(mtmp)544 meatgold(mtmp)
545 register struct monst *mtmp;
546 {
547 register struct obj *otmp;
548 struct permonst *ptr;
549 int poly, grow, heal, mstone;
550
551 /* If a pet, eating is handled separately, in dog.c */
552 if (mtmp->mtame) return 0;
553
554 /* Eats topmost metal object if it is there */
555 for (otmp = level.objects[mtmp->mx][mtmp->my];
556 otmp; otmp = otmp->nexthere)
557 if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) &&
558 touch_artifact(otmp,mtmp)) {
559 if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) {
560 if (canseemon(mtmp) && flags.verbose) {
561 pline("%s eats %s!",
562 Monnam(mtmp),
563 distant_name(otmp,doname));
564 }
565 /* The object's rustproofing is gone now */
566 otmp->oerodeproof = 0;
567 mtmp->mstun = 1;
568 if (canseemon(mtmp) && flags.verbose) {
569 pline("%s spits %s out in disgust!",
570 Monnam(mtmp), distant_name(otmp,doname));
571 }
572 /* KMH -- Don't eat undigestable/choking objects */
573 } else if (otmp->otyp != AMULET_OF_STRANGULATION &&
574 otmp->otyp != RIN_SLOW_DIGESTION) {
575 if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
576 pline("%s eats %s!", Monnam(mtmp),
577 distant_name(otmp,doname));
578 else if (flags.soundok && flags.verbose)
579 You_hear("a crunching sound.");
580 mtmp->meating = otmp->owt/2 + 1;
581 /* Heal up to the object's weight in hp */
582 if (mtmp->mhp < mtmp->mhpmax) {
583 mtmp->mhp += objects[otmp->otyp].oc_weight;
584 if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
585 }
586 if(otmp == uball) {
587 unpunish();
588 delobj(otmp);
589 } else if (otmp == uchain) {
590 unpunish(); /* frees uchain */
591 } else {
592 poly = polyfodder(otmp);
593 grow = mlevelgain(otmp);
594 heal = mhealup(otmp);
595 mstone = mstoning(otmp);
596 delobj(otmp);
597 ptr = mtmp->data;
598 if (poly) {
599 if (newcham(mtmp, (struct permonst *)0))
600 ptr = mtmp->data;
601 } else if (grow) {
602 ptr = grow_up(mtmp, (struct monst *)0);
603 } else if (mstone) {
604 if (poly_when_stoned(ptr)) {
605 mon_to_stone(mtmp);
606 ptr = mtmp->data;
607 } else if (!resists_ston(mtmp)) {
608 if (canseemon(mtmp))
609 pline("%s turns to stone!", Monnam(mtmp));
610 monstone(mtmp);
611 ptr = (struct permonst *)0;
612 }
613 } else if (heal) {
614 mtmp->mhp = mtmp->mhpmax;
615 }
616 if (!ptr) return 2; /* it died */
617 }
618 /* Left behind a pile? */
619 if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE);
620 newsym(mtmp->mx, mtmp->my);
621 return 1;
622 }
623 }
624 return 0;
625 }
626
627 int
meatobj(mtmp)628 meatobj(mtmp) /* for gelatinous cubes */
629 register struct monst *mtmp;
630 {
631 register struct obj *otmp, *otmp2;
632 struct permonst *ptr;
633 int poly, grow, heal, count = 0, ecount = 0;
634 char buf[BUFSZ];
635
636 buf[0] = '\0';
637 /* If a pet, eating is handled separately, in dog.c */
638 if (mtmp->mtame) return 0;
639
640 /* Eats organic objects, including cloth and wood, if there */
641 /* Engulfs others, except huge rocks and metal attached to player */
642 for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
643 otmp2 = otmp->nexthere;
644 if (is_organic(otmp) && !obj_resists(otmp, 5, 95) &&
645 touch_artifact(otmp,mtmp)) {
646 if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) &&
647 !resists_ston(mtmp))
648 continue;
649 if (otmp->otyp == AMULET_OF_STRANGULATION ||
650 otmp->otyp == RIN_SLOW_DIGESTION)
651 continue;
652 ++count;
653 if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
654 pline("%s eats %s!", Monnam(mtmp),
655 distant_name(otmp, doname));
656 else if (flags.soundok && flags.verbose)
657 You_hear("a slurping sound.");
658 /* Heal up to the object's weight in hp */
659 if (mtmp->mhp < mtmp->mhpmax) {
660 mtmp->mhp += objects[otmp->otyp].oc_weight;
661 if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
662 }
663 if (Has_contents(otmp)) {
664 register struct obj *otmp3;
665 /* contents of eaten containers become engulfed; this
666 is arbitrary, but otherwise g.cubes are too powerful */
667 while ((otmp3 = otmp->cobj) != 0) {
668 obj_extract_self(otmp3);
669 if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) {
670 otmp3->age = monstermoves - otmp3->age;
671 start_corpse_timeout(otmp3);
672 }
673 (void) mpickobj(mtmp, otmp3);
674 }
675 }
676 poly = polyfodder(otmp);
677 grow = mlevelgain(otmp);
678 heal = mhealup(otmp);
679 delobj(otmp); /* munch */
680 ptr = mtmp->data;
681 if (poly) {
682 if (newcham(mtmp, (struct permonst *)0)) ptr = mtmp->data;
683 } else if (grow) {
684 ptr = grow_up(mtmp, (struct monst *)0);
685 } else if (heal) {
686 mtmp->mhp = mtmp->mhpmax;
687 }
688 /* in case it polymorphed or died */
689 if (ptr != &mons[PM_GELATINOUS_CUBE])
690 return !ptr ? 2 : 1;
691 } else if (otmp->oclass != ROCK_CLASS &&
692 otmp != uball && otmp != uchain) {
693 ++ecount;
694 if (ecount == 1) {
695 Sprintf(buf, "%s engulfs %s.", Monnam(mtmp),
696 distant_name(otmp,doname));
697 } else if (ecount == 2)
698 Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp));
699 obj_extract_self(otmp);
700 (void) mpickobj(mtmp, otmp); /* slurp */
701 }
702 /* Engulf & devour is instant, so don't set meating */
703 if (mtmp->minvis) newsym(mtmp->mx, mtmp->my);
704 }
705 if (ecount > 0) {
706 if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0])
707 pline("%s", buf);
708 else if (flags.soundok && flags.verbose)
709 You_hear("%s slurping sound%s.",
710 ecount == 1 ? "a" : "several",
711 ecount == 1 ? "" : "s");
712 }
713 return ((count > 0) || (ecount > 0)) ? 1 : 0;
714 }
715
716 void
mpickgold(mtmp)717 mpickgold(mtmp)
718 register struct monst *mtmp;
719 {
720 register struct obj *gold;
721
722 if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) {
723 mtmp->mgold += gold->quan;
724 delobj(gold);
725 if (cansee(mtmp->mx, mtmp->my) ) {
726 if (flags.verbose && !mtmp->isgd)
727 pline("%s picks up some gold.", Monnam(mtmp));
728 newsym(mtmp->mx, mtmp->my);
729 }
730 }
731 }
732 #endif /* OVLB */
733 #ifdef OVL2
734
735 boolean
mpickstuff(mtmp,str)736 mpickstuff(mtmp, str)
737 register struct monst *mtmp;
738 register const char *str;
739 {
740 register struct obj *otmp, *otmp2;
741
742 /* prevent shopkeepers from leaving the door of their shop */
743 if(mtmp->isshk && inhishop(mtmp)) return FALSE;
744
745 for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) {
746 otmp2 = otmp->nexthere;
747 /* Nymphs take everything. Most monsters don't pick up corpses. */
748 if (!str ? searches_for_item(mtmp,otmp) :
749 !!(index(str, otmp->oclass))) {
750 if (otmp->otyp == CORPSE && (
751 is_rider(&mons[otmp->corpsenm]) ||
752 (touch_petrifies(&mons[otmp->corpsenm])
753 && !(mtmp->misc_worn_check & W_ARMG)) ||
754 (mtmp->data->mlet != S_NYMPH
755 && !touch_petrifies(&mons[otmp->corpsenm])
756 && otmp->corpsenm != PM_LIZARD
757 && !acidic(&mons[otmp->corpsenm]))
758 ))
759 continue;
760 if (!touch_artifact(otmp,mtmp)) continue;
761 if (!can_carry(mtmp,otmp)) continue;
762 if (is_pool(mtmp->mx,mtmp->my)) continue;
763 #ifdef INVISIBLE_OBJECTS
764 if (otmp->oinvis && !perceives(mtmp->data)) continue;
765 #endif
766 if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
767 pline("%s picks up %s.", Monnam(mtmp),
768 (distu(mtmp->my, mtmp->my) <= 5) ?
769 doname(otmp) : distant_name(otmp, doname));
770 obj_extract_self(otmp);
771 /* unblock point after extract, before pickup */
772 if (otmp->otyp == BOULDER)
773 unblock_point(otmp->ox,otmp->oy); /* vision */
774 (void) mpickobj(mtmp, otmp); /* may merge and free otmp */
775 m_dowear(mtmp, FALSE);
776 newsym(mtmp->mx, mtmp->my);
777 return TRUE; /* pick only one object */
778 }
779 }
780 return FALSE;
781 }
782
783 #endif /* OVL2 */
784 #ifdef OVL0
785
786 int
curr_mon_load(mtmp)787 curr_mon_load(mtmp)
788 register struct monst *mtmp;
789 {
790 register int curload = 0;
791 register struct obj *obj;
792
793 for(obj = mtmp->minvent; obj; obj = obj->nobj) {
794 if(obj->otyp != BOULDER || !throws_rocks(mtmp->data))
795 curload += obj->owt;
796 }
797
798 return curload;
799 }
800
801 int
max_mon_load(mtmp)802 max_mon_load(mtmp)
803 register struct monst *mtmp;
804 {
805 register long maxload;
806
807 /* Base monster carrying capacity is equal to human maximum
808 * carrying capacity, or half human maximum if not strong.
809 * (for a polymorphed player, the value used would be the
810 * non-polymorphed carrying capacity instead of max/half max).
811 * This is then modified by the ratio between the monster weights
812 * and human weights. Corpseless monsters are given a capacity
813 * proportional to their size instead of weight.
814 */
815 if (!mtmp->data->cwt)
816 maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN;
817 else if (!strongmonst(mtmp->data)
818 || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN)))
819 maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN;
820 else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/
821
822 if (!strongmonst(mtmp->data)) maxload /= 2;
823
824 if (maxload < 1) maxload = 1;
825
826 return (int) maxload;
827 }
828
829 /* for restricting monsters' object-pickup */
830 boolean
can_carry(mtmp,otmp)831 can_carry(mtmp,otmp)
832 struct monst *mtmp;
833 struct obj *otmp;
834 {
835 int otyp = otmp->otyp, newload = otmp->owt;
836 struct permonst *mdat = mtmp->data;
837
838 if (notake(mdat)) return FALSE; /* can't carry anything */
839
840 if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) &&
841 !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp))
842 return FALSE;
843 if (objects[otyp].oc_material == SILVER && hates_silver(mdat) &&
844 (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
845 return FALSE;
846
847 #ifdef STEED
848 /* Steeds don't pick up stuff (to avoid shop abuse) */
849 if (mtmp == u.usteed) return (FALSE);
850 #endif
851 if (mtmp->isshk) return(TRUE); /* no limit */
852 if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE);
853 /* otherwise players might find themselves obligated to violate
854 * their alignment if the monster takes something they need
855 */
856
857 /* special--boulder throwers carry unlimited amounts of boulders */
858 if (throws_rocks(mdat) && otyp == BOULDER)
859 return(TRUE);
860
861 /* nymphs deal in stolen merchandise, but not boulders or statues */
862 if (mdat->mlet == S_NYMPH)
863 return (boolean)(otmp->oclass != ROCK_CLASS);
864
865 if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE;
866
867 return(TRUE);
868 }
869
870 /* return number of acceptable neighbour positions */
871 int
mfndpos(mon,poss,info,flag)872 mfndpos(mon, poss, info, flag)
873 register struct monst *mon;
874 coord *poss; /* coord poss[9] */
875 long *info; /* long info[9] */
876 long flag;
877 {
878 struct permonst *mdat = mon->data;
879 register xchar x,y,nx,ny;
880 register int cnt = 0;
881 register uchar ntyp;
882 uchar nowtyp;
883 boolean wantpool,poolok,lavaok,nodiag;
884 int maxx, maxy;
885
886 x = mon->mx;
887 y = mon->my;
888 nowtyp = levl[x][y].typ;
889
890 nodiag = (mdat == &mons[PM_GRID_BUG]);
891 wantpool = mdat->mlet == S_EEL;
892 poolok = is_flyer(mdat) || is_clinger(mdat) ||
893 (is_swimmer(mdat) && !wantpool);
894 lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat);
895
896 nexttry: /* eels prefer the water, but if there is no water nearby,
897 they will crawl over land */
898 if(mon->mconf) {
899 flag |= ALLOW_ALL;
900 flag &= ~NOTONL;
901 }
902 if(!mon->mcansee)
903 flag |= ALLOW_SSM;
904 maxx = min(x+1,COLNO-1);
905 maxy = min(y+1,ROWNO-1);
906 for(nx = max(1,x-1); nx <= maxx; nx++)
907 for(ny = max(0,y-1); ny <= maxy; ny++) {
908 if(nx == x && ny == y) continue;
909 if(IS_ROCK(ntyp = levl[nx][ny].typ) &&
910 !((flag & ALLOW_WALL) && may_passwall(nx,ny)) &&
911 !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue;
912 /* KMH -- Added iron bars */
913 if (ntyp == IRONBARS &&
914 !((flag & ALLOW_WALL) && may_passwall(nx,ny))) continue;
915 if(IS_DOOR(ntyp) && !amorphous(mdat) &&
916 ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
917 (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))
918 ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue;
919 if(nx != x && ny != y && (nodiag ||
920 #ifdef REINCARNATION
921 ((IS_DOOR(nowtyp) &&
922 ((levl[x][y].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))) ||
923 (IS_DOOR(ntyp) &&
924 ((levl[nx][ny].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))))
925 #else
926 ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) ||
927 (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN)))
928 #endif
929 ))
930 continue;
931 if((is_pool(nx,ny) == wantpool || poolok) &&
932 (lavaok || !is_lava(nx,ny))) {
933 int dispx, dispy;
934 boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat)));
935 boolean checkobj = OBJ_AT(nx,ny);
936
937 /* Displacement also displaces the Elbereth/scare monster,
938 * as long as you are visible.
939 */
940 if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) {
941 dispx = u.ux;
942 dispy = u.uy;
943 } else {
944 dispx = nx;
945 dispy = ny;
946 }
947
948 info[cnt] = 0;
949 if ((checkobj || Displaced) && onscary(dispx, dispy, mon)) {
950 if(!(flag & ALLOW_SSM)) continue;
951 info[cnt] |= ALLOW_SSM;
952 }
953 if((nx == u.ux && ny == u.uy) ||
954 (nx == mon->mux && ny == mon->muy)) {
955 if (nx == u.ux && ny == u.uy) {
956 /* If it's right next to you, it found you,
957 * displaced or no. We must set mux and muy
958 * right now, so when we return we can tell
959 * that the ALLOW_U means to attack _you_ and
960 * not the image.
961 */
962 mon->mux = u.ux;
963 mon->muy = u.uy;
964 }
965 if(!(flag & ALLOW_U)) continue;
966 info[cnt] |= ALLOW_U;
967 } else {
968 if(MON_AT(nx, ny)) {
969 struct monst *mtmp2 = m_at(nx, ny);
970 long mmflag = flag | mm_aggression(mon, mtmp2);
971
972 if (!(mmflag & ALLOW_M)) continue;
973 info[cnt] |= ALLOW_M;
974 if (mtmp2->mtame) {
975 if (!(mmflag & ALLOW_TM)) continue;
976 info[cnt] |= ALLOW_TM;
977 }
978 }
979 /* Note: ALLOW_SANCT only prevents movement, not */
980 /* attack, into a temple. */
981 if(level.flags.has_temple &&
982 *in_rooms(nx, ny, TEMPLE) &&
983 !*in_rooms(x, y, TEMPLE) &&
984 in_your_sanctuary((struct monst *)0, nx, ny)) {
985 if(!(flag & ALLOW_SANCT)) continue;
986 info[cnt] |= ALLOW_SANCT;
987 }
988 }
989 if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
990 if(flag & NOGARLIC) continue;
991 info[cnt] |= NOGARLIC;
992 }
993 if(checkobj && sobj_at(BOULDER, nx, ny)) {
994 if(!(flag & ALLOW_ROCK)) continue;
995 info[cnt] |= ALLOW_ROCK;
996 }
997 if (monseeu && onlineu(nx,ny)) {
998 if(flag & NOTONL) continue;
999 info[cnt] |= NOTONL;
1000 }
1001 if (nx != x && ny != y && bad_rock(mdat, x, ny)
1002 && bad_rock(mdat, nx, y)
1003 && (bigmonst(mdat) || (curr_mon_load(mon) > 600)))
1004 continue;
1005 /* The monster avoids a particular type of trap if it's familiar
1006 * with the trap type. Pets get ALLOW_TRAPS and checking is
1007 * done in dogmove.c. In either case, "harmless" traps are
1008 * neither avoided nor marked in info[].
1009 */
1010 { register struct trap *ttmp = t_at(nx, ny);
1011 if(ttmp) {
1012 if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) {
1013 impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp);
1014 continue;
1015 }
1016 if ((ttmp->ttyp != RUST_TRAP
1017 || mdat == &mons[PM_IRON_GOLEM])
1018 && ttmp->ttyp != STATUE_TRAP
1019 && ((ttmp->ttyp != PIT
1020 && ttmp->ttyp != SPIKED_PIT
1021 && ttmp->ttyp != TRAPDOOR
1022 && ttmp->ttyp != HOLE)
1023 || (!is_flyer(mdat)
1024 && !is_floater(mdat)
1025 && !is_clinger(mdat))
1026 || In_sokoban(&u.uz))
1027 && (ttmp->ttyp != SLP_GAS_TRAP ||
1028 !resists_sleep(mon))
1029 && (ttmp->ttyp != BEAR_TRAP ||
1030 (mdat->msize > MZ_SMALL &&
1031 !amorphous(mdat) && !is_flyer(mdat)))
1032 && (ttmp->ttyp != FIRE_TRAP ||
1033 !resists_fire(mon))
1034 && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat))
1035 && (ttmp->ttyp != WEB || (!amorphous(mdat) &&
1036 !webmaker(mdat)))
1037 ) {
1038 if (!(flag & ALLOW_TRAPS)) {
1039 if (mon->mtrapseen & (1L << (ttmp->ttyp - 1)))
1040 continue;
1041 }
1042 info[cnt] |= ALLOW_TRAPS;
1043 }
1044 }
1045 }
1046 poss[cnt].x = nx;
1047 poss[cnt].y = ny;
1048 cnt++;
1049 }
1050 }
1051 if(!cnt && wantpool && !is_pool(x,y)) {
1052 wantpool = FALSE;
1053 goto nexttry;
1054 }
1055 return(cnt);
1056 }
1057
1058 #endif /* OVL0 */
1059 #ifdef OVL1
1060
1061 /* Monster against monster special attacks; for the specified monster
1062 combinations, this allows one monster to attack another adjacent one
1063 in the absence of Conflict. There is no provision for targetting
1064 other monsters; just hand to hand fighting when they happen to be
1065 next to each other. */
1066 STATIC_OVL long
mm_aggression(magr,mdef)1067 mm_aggression(magr, mdef)
1068 struct monst *magr, /* monster that is currently deciding where to move */
1069 *mdef; /* another monster which is next to it */
1070 {
1071 /* supposedly purple worms are attracted to shrieking because they
1072 like to eat shriekers, so attack the latter when feasible */
1073 if (magr->data == &mons[PM_PURPLE_WORM] &&
1074 mdef->data == &mons[PM_SHRIEKER])
1075 return ALLOW_M|ALLOW_TM;
1076 /* Various other combinations such as dog vs cat, cat vs rat, and
1077 elf vs orc have been suggested. For the time being we don't
1078 support those. */
1079 return 0L;
1080 }
1081
1082 boolean
monnear(mon,x,y)1083 monnear(mon, x, y)
1084 register struct monst *mon;
1085 register int x,y;
1086 /* Is the square close enough for the monster to move or attack into? */
1087 {
1088 register int distance = dist2(mon->mx, mon->my, x, y);
1089 if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0;
1090 return((boolean)(distance < 3));
1091 }
1092
1093 /* really free dead monsters */
1094 void
dmonsfree()1095 dmonsfree()
1096 {
1097 struct monst **mtmp;
1098 int count = 0;
1099
1100 for (mtmp = &fmon; *mtmp;) {
1101 if ((*mtmp)->mhp <= 0) {
1102 struct monst *freetmp = *mtmp;
1103 *mtmp = (*mtmp)->nmon;
1104 dealloc_monst(freetmp);
1105 count++;
1106 } else
1107 mtmp = &(*mtmp)->nmon;
1108 }
1109
1110 if (count != iflags.purge_monsters)
1111 impossible("dmonsfree: %d removed doesn't match %d pending",
1112 count, iflags.purge_monsters);
1113 iflags.purge_monsters = 0;
1114 }
1115
1116 #endif /* OVL1 */
1117 #ifdef OVLB
1118
1119 /* called when monster is moved to larger structure */
1120 void
replmon(mtmp,mtmp2)1121 replmon(mtmp, mtmp2)
1122 register struct monst *mtmp, *mtmp2;
1123 {
1124 struct obj *otmp;
1125
1126 /* transfer the monster's inventory */
1127 for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) {
1128 #ifdef DEBUG
1129 if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp)
1130 panic("replmon: minvent inconsistency");
1131 #endif
1132 otmp->ocarry = mtmp2;
1133 }
1134 mtmp->minvent = 0;
1135
1136 /* remove the old monster from the map and from `fmon' list */
1137 relmon(mtmp);
1138
1139 /* finish adding its replacement */
1140 #ifdef STEED
1141 if (mtmp == u.usteed) ; else /* don't place steed onto the map */
1142 #endif
1143 place_monster(mtmp2, mtmp2->mx, mtmp2->my);
1144 if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */
1145 place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */
1146 if (emits_light(mtmp2->data)) {
1147 /* since this is so rare, we don't have any `mon_move_light_source' */
1148 new_light_source(mtmp2->mx, mtmp2->my,
1149 emits_light(mtmp2->data),
1150 LS_MONSTER, (genericptr_t)mtmp2);
1151 /* here we rely on the fact that `mtmp' hasn't actually been deleted */
1152 del_light_source(LS_MONSTER, (genericptr_t)mtmp);
1153 }
1154 mtmp2->nmon = fmon;
1155 fmon = mtmp2;
1156 if (u.ustuck == mtmp) u.ustuck = mtmp2;
1157 #ifdef STEED
1158 if (u.usteed == mtmp) u.usteed = mtmp2;
1159 #endif
1160 if (mtmp2->isshk) replshk(mtmp,mtmp2);
1161
1162 /* discard the old monster */
1163 dealloc_monst(mtmp);
1164 }
1165
1166 /* release mon from display and monster list */
1167 void
relmon(mon)1168 relmon(mon)
1169 register struct monst *mon;
1170 {
1171 register struct monst *mtmp;
1172
1173 if (fmon == (struct monst *)0) panic ("relmon: no fmon available.");
1174
1175 remove_monster(mon->mx, mon->my);
1176
1177 if(mon == fmon) fmon = fmon->nmon;
1178 else {
1179 for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ;
1180 if(mtmp) mtmp->nmon = mon->nmon;
1181 else panic("relmon: mon not in list.");
1182 }
1183 }
1184
1185 /* remove effects of mtmp from other data structures */
1186 STATIC_OVL void
m_detach(mtmp,mptr)1187 m_detach(mtmp, mptr)
1188 struct monst *mtmp;
1189 struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */
1190 {
1191 if(mtmp->mleashed) m_unleash(mtmp);
1192 /* to prevent an infinite relobj-flooreffects-hmon-killed loop */
1193 mtmp->mtrapped = 0;
1194 mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */
1195 relobj(mtmp, 0, FALSE);
1196 remove_monster(mtmp->mx, mtmp->my);
1197 if (emits_light(mptr))
1198 del_light_source(LS_MONSTER, (genericptr_t)mtmp);
1199 newsym(mtmp->mx,mtmp->my);
1200 unstuck(mtmp);
1201 fill_pit(mtmp->mx, mtmp->my);
1202
1203 if(mtmp->isshk) shkgone(mtmp);
1204 if(mtmp->wormno) wormgone(mtmp);
1205 iflags.purge_monsters++;
1206 }
1207
1208 /* find the worn amulet of life saving which will save a monster */
1209 struct obj *
mlifesaver(mon)1210 mlifesaver(mon)
1211 struct monst *mon;
1212 {
1213 if (!nonliving(mon->data)) {
1214 struct obj *otmp = which_armor(mon, W_AMUL);
1215
1216 if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING)
1217 return otmp;
1218 }
1219 return (struct obj *)0;
1220 }
1221
1222 STATIC_OVL void
lifesaved_monster(mtmp)1223 lifesaved_monster(mtmp)
1224 struct monst *mtmp;
1225 {
1226 struct obj *lifesave = mlifesaver(mtmp);
1227
1228 if (lifesave) {
1229 /* not canseemon; amulets are on the head, so you don't want */
1230 /* to show this for a long worm with only a tail visible. */
1231 /* Nor do you check invisibility, because glowing and disinte- */
1232 /* grating amulets are always visible. */
1233 if (cansee(mtmp->mx, mtmp->my)) {
1234 pline("But wait...");
1235 pline("%s medallion begins to glow!",
1236 s_suffix(Monnam(mtmp)));
1237 makeknown(AMULET_OF_LIFE_SAVING);
1238 pline("%s looks much better!", Monnam(mtmp));
1239 pline_The("medallion crumbles to dust!");
1240 }
1241 m_useup(mtmp, lifesave);
1242 mtmp->mcanmove = 1;
1243 mtmp->mfrozen = 0;
1244 if (mtmp->mtame && !mtmp->isminion) {
1245 struct edog *edog = EDOG(mtmp);
1246 if (edog->hungrytime < moves+500)
1247 edog->hungrytime = moves+500;
1248 if (edog->mhpmax_penalty) {
1249 /* was starving */
1250 mtmp->mhpmax += edog->mhpmax_penalty;
1251 edog->mhpmax_penalty = 0;
1252 }
1253 wary_dog(mtmp, FALSE);
1254 }
1255 if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10;
1256 mtmp->mhp = mtmp->mhpmax;
1257 if (mvitals[monsndx(mtmp->data)].mvflags & G_GENOD) {
1258 if (cansee(mtmp->mx, mtmp->my))
1259 pline("Unfortunately %s is still genocided...",
1260 mon_nam(mtmp));
1261 } else
1262 return;
1263 }
1264 mtmp->mhp = 0;
1265 }
1266
1267 void
mondead(mtmp)1268 mondead(mtmp)
1269 register struct monst *mtmp;
1270 {
1271 struct permonst *mptr;
1272 int tmp;
1273
1274 if(mtmp->isgd) {
1275 /* if we're going to abort the death, it *must* be before
1276 * the m_detach or there will be relmon problems later */
1277 if(!grddead(mtmp)) return;
1278 }
1279 lifesaved_monster(mtmp);
1280 if (mtmp->mhp > 0) return;
1281
1282 #ifdef STEED
1283 /* Player is thrown from his steed when it dies */
1284 if (mtmp == u.usteed)
1285 dismount_steed(DISMOUNT_GENERIC);
1286 #endif
1287
1288 mptr = mtmp->data; /* save this for m_detach() */
1289 /* restore chameleon, lycanthropes to true form at death */
1290 if (mtmp->cham)
1291 set_mon_data(mtmp, &mons[cham_to_pm[mtmp->cham]], -1);
1292 else if (mtmp->data == &mons[PM_WEREJACKAL])
1293 set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1);
1294 else if (mtmp->data == &mons[PM_WEREWOLF])
1295 set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1);
1296 else if (mtmp->data == &mons[PM_WERERAT])
1297 set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1);
1298
1299 /* if MAXMONNO monsters of a given type have died, and it
1300 * can be done, extinguish that monster.
1301 *
1302 * mvitals[].died does double duty as total number of dead monsters
1303 * and as experience factor for the player killing more monsters.
1304 * this means that a dragon dying by other means reduces the
1305 * experience the player gets for killing a dragon directly; this
1306 * is probably not too bad, since the player likely finagled the
1307 * first dead dragon via ring of conflict or pets, and extinguishing
1308 * based on only player kills probably opens more avenues of abuse
1309 * for rings of conflict and such.
1310 */
1311 tmp = monsndx(mtmp->data);
1312 if (mvitals[tmp].died < 255) mvitals[tmp].died++;
1313 #ifdef MAIL
1314 /* if the mail daemon dies, no more mail delivery. -3. */
1315 if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD;
1316 #endif
1317
1318 #ifdef KOPS
1319 if (mtmp->data->mlet == S_KOP) {
1320 /* Dead Kops may come back. */
1321 switch(rnd(5)) {
1322 case 1: /* returns near the stairs */
1323 (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS);
1324 break;
1325 case 2: /* randomly */
1326 (void) makemon(mtmp->data,0,0,NO_MM_FLAGS);
1327 break;
1328 default:
1329 break;
1330 }
1331 }
1332 #endif
1333 if(mtmp->iswiz) wizdead();
1334 if(mtmp->data->msound == MS_NEMESIS) nemdead();
1335 if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
1336 unmap_object(mtmp->mx, mtmp->my);
1337 m_detach(mtmp, mptr);
1338 }
1339
1340 STATIC_OVL boolean
corpse_chance(mon)1341 corpse_chance(mon)
1342 struct monst *mon;
1343 {
1344 struct permonst *mdat = mon->data;
1345 int i, tmp;
1346
1347
1348 if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) {
1349 if (cansee(mon->mx, mon->my))
1350 pline("%s body crumbles into dust.",
1351 s_suffix(Monnam(mon)));
1352 return FALSE;
1353 }
1354
1355 /* Gas spores always explode upon death */
1356 for(i = 0; i < NATTK; i++) {
1357 if (mdat->mattk[i].aatyp == AT_BOOM) {
1358 if (mdat->mattk[i].damn)
1359 tmp = d((int)mdat->mattk[i].damn,
1360 (int)mdat->mattk[i].damd);
1361 else if(mdat->mattk[i].damd)
1362 tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd);
1363 else tmp = 0;
1364 Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname));
1365 killer = killer_buf;
1366 killer_format = KILLED_BY_AN;
1367 explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE);
1368 return (FALSE);
1369 }
1370 }
1371
1372 /* must duplicate this below check in xkilled() since it results in
1373 * creating no objects as well as no corpse
1374 */
1375 if (
1376 #ifdef REINCARNATION
1377 Is_rogue_level(&u.uz) ||
1378 #endif
1379 (level.flags.graveyard && is_undead(mdat) && rn2(3)))
1380 return FALSE;
1381
1382 if (bigmonst(mdat) || mdat == &mons[PM_LIZARD]
1383 || is_golem(mdat)
1384 || is_mplayer(mdat)
1385 || is_rider(mdat))
1386 return TRUE;
1387 return (boolean) (!rn2((int)
1388 (2 + ((int)(mdat->geno & G_FREQ)<2) + verysmall(mdat))));
1389 }
1390
1391 /* drop (perhaps) a cadaver and remove monster */
1392 void
mondied(mdef)1393 mondied(mdef)
1394 register struct monst *mdef;
1395 {
1396 mondead(mdef);
1397 if (mdef->mhp > 0) return; /* lifesaved */
1398
1399 if (corpse_chance(mdef))
1400 (void) make_corpse(mdef);
1401 }
1402
1403 /* monster disappears, not dies */
1404 void
mongone(mdef)1405 mongone(mdef)
1406 register struct monst *mdef;
1407 {
1408 #ifdef STEED
1409 /* Player is thrown from his steed when it disappears */
1410 if (mdef == u.usteed)
1411 dismount_steed(DISMOUNT_GENERIC);
1412 #endif
1413
1414 discard_minvent(mdef); /* release monster's inventory */
1415 mdef->mgold = 0L;
1416 m_detach(mdef, mdef->data);
1417 }
1418
1419 /* drop a statue or rock and remove monster */
1420 void
monstone(mdef)1421 monstone(mdef)
1422 register struct monst *mdef;
1423 {
1424 struct obj *otmp, *obj;
1425 xchar x = mdef->mx, y = mdef->my;
1426
1427 /* we have to make the statue before calling mondead, to be able to
1428 * put inventory in it, and we have to check for lifesaving before
1429 * making the statue....
1430 */
1431 lifesaved_monster(mdef);
1432 if (mdef->mhp > 0) return;
1433
1434 mdef->mtrapped = 0; /* (see m_detach) */
1435
1436 if ((int)mdef->data->msize > MZ_TINY ||
1437 !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) {
1438 otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0,
1439 mdef->data, x, y, FALSE);
1440 if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef));
1441 /* some objects may end up outside the statue */
1442 while ((obj = mdef->minvent) != 0) {
1443 obj_extract_self(obj);
1444 obj->owornmask = 0L;
1445 if (obj->otyp == BOULDER ||
1446 #if 0 /* monsters don't carry statues */
1447 (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) ||
1448 #endif
1449 obj_resists(obj, 0, 0)) {
1450 if (flooreffects(obj, x, y, "fall")) continue;
1451 place_object(obj, x, y);
1452 } else {
1453 if (obj->lamplit) end_burn(obj, TRUE);
1454 add_to_container(otmp, obj);
1455 }
1456 }
1457 if (mdef->mgold) {
1458 struct obj *au;
1459 au = mksobj(GOLD_PIECE, FALSE, FALSE);
1460 au->quan = mdef->mgold;
1461 au->owt = weight(au);
1462 add_to_container(otmp, au);
1463 mdef->mgold = 0;
1464 }
1465 /* Archeologists should not break unique statues */
1466 if (mdef->data->geno & G_UNIQ)
1467 otmp->spe = 1;
1468 otmp->owt = weight(otmp);
1469 } else
1470 otmp = mksobj_at(ROCK, x, y, TRUE);
1471
1472 stackobj(otmp);
1473 /* mondead() already does this, but we must do it before the newsym */
1474 if(glyph_is_invisible(levl[x][y].glyph))
1475 unmap_object(x, y);
1476 if (cansee(x, y)) newsym(x,y);
1477 mondead(mdef);
1478 }
1479
1480 /* another monster has killed the monster mdef */
1481 void
monkilled(mdef,fltxt,how)1482 monkilled(mdef, fltxt, how)
1483 register struct monst *mdef;
1484 const char *fltxt;
1485 int how;
1486 {
1487 boolean be_sad = FALSE; /* true if unseen pet is killed */
1488
1489 if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my))
1490 && fltxt)
1491 pline("%s is %s%s%s!", Monnam(mdef),
1492 nonliving(mdef->data) ? "destroyed" : "killed",
1493 *fltxt ? " by the " : "",
1494 fltxt
1495 );
1496 else
1497 be_sad = (mdef->mtame != 0);
1498
1499 /* no corpses if digested or disintegrated */
1500 if(how == AD_DGST || how == -AD_RBRE)
1501 mondead(mdef);
1502 else
1503 mondied(mdef);
1504
1505 if (be_sad && mdef->mhp <= 0)
1506 You("have a sad feeling for a moment, then it passes.");
1507 }
1508
1509 void
unstuck(mtmp)1510 unstuck(mtmp)
1511 register struct monst *mtmp;
1512 {
1513 if(u.ustuck == mtmp) {
1514 if(u.uswallow){
1515 u.ux = mtmp->mx;
1516 u.uy = mtmp->my;
1517 u.uswallow = 0;
1518 u.uswldtim = 0;
1519 if (Punished) placebc();
1520 vision_full_recalc = 1;
1521 docrt();
1522 }
1523 u.ustuck = 0;
1524 }
1525 }
1526
1527 void
killed(mtmp)1528 killed(mtmp)
1529 register struct monst *mtmp;
1530 {
1531 xkilled(mtmp, 1);
1532 }
1533
1534 /* the player has killed the monster mtmp */
1535 void
xkilled(mtmp,dest)1536 xkilled(mtmp, dest)
1537 register struct monst *mtmp;
1538 /*
1539 * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
1540 * either; dest=3, message but no corpse
1541 */
1542 int dest;
1543 {
1544 register int tmp, x = mtmp->mx, y = mtmp->my;
1545 register struct permonst *mdat;
1546 int mndx;
1547 register struct obj *otmp;
1548 register struct trap *t;
1549 boolean redisp = FALSE;
1550 boolean wasinside = u.uswallow && (u.ustuck == mtmp);
1551
1552
1553 /* KMH, conduct */
1554 u.uconduct.killer++;
1555
1556 if (dest & 1) {
1557 if(!wasinside && !canspotmon(mtmp))
1558 You("destroy it!");
1559 else {
1560 You("destroy %s!",
1561 mtmp->mtame
1562 ? x_monnam(mtmp, ARTICLE_THE, "poor",
1563 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE)
1564 : mon_nam(mtmp));
1565 }
1566 }
1567
1568 if (mtmp->mtrapped &&
1569 ((t = t_at(x, y)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) &&
1570 sobj_at(BOULDER, x, y))
1571 dest ^= 2; /*
1572 * Prevent corpses/treasure being created "on top"
1573 * of the boulder that is about to fall in. This is
1574 * out of order, but cannot be helped unless this
1575 * whole routine is rearranged.
1576 */
1577
1578 /* your pet knows who just killed it...watch out */
1579 if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1;
1580
1581 /* dispose of monster and make cadaver */
1582 if(stoned) monstone(mtmp);
1583 else mondead(mtmp);
1584
1585 if (mtmp->mhp > 0) { /* monster lifesaved */
1586 /* Cannot put the non-visible lifesaving message in
1587 * lifesaved_monster() since the message appears only when you
1588 * kill it (as opposed to visible lifesaving which always
1589 * appears).
1590 */
1591 stoned = FALSE;
1592 if (!cansee(x,y)) pline("Maybe not...");
1593 return;
1594 }
1595
1596 mdat = mtmp->data; /* note: mondead can change mtmp->data */
1597 mndx = monsndx(mdat);
1598
1599 if (stoned) {
1600 stoned = FALSE;
1601 goto cleanup;
1602 }
1603
1604 if((dest & 2)
1605 #ifdef REINCARNATION
1606 || Is_rogue_level(&u.uz)
1607 #endif
1608 || (level.flags.graveyard && is_undead(mdat) && rn2(3)))
1609 goto cleanup;
1610
1611 #ifdef MAIL
1612 if(mdat == &mons[PM_MAIL_DAEMON]) {
1613 stackobj(mksobj_at(SCR_MAIL, x, y, FALSE));
1614 redisp = TRUE;
1615 }
1616 #endif
1617 if(!accessible(x, y) && !is_pool(x, y)) {
1618 /* might be mimic in wall or corpse in lava */
1619 redisp = TRUE;
1620 if(wasinside) spoteffects(TRUE);
1621 } else if(x != u.ux || y != u.uy) {
1622 /* might be here after swallowed */
1623 if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE)
1624 #ifdef KOPS
1625 && mdat->mlet != S_KOP
1626 #endif
1627 ) {
1628 int typ;
1629
1630 otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE);
1631 /* Don't create large objects from small monsters */
1632 typ = otmp->otyp;
1633 if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION
1634 && typ != LEASH
1635 && typ != FIGURINE
1636 && (otmp->owt > 3 ||
1637 objects[typ].oc_big /*oc_bimanual/oc_bulky*/ ||
1638 is_spear(otmp) || is_pole(otmp) ||
1639 typ == MORNING_STAR)) {
1640 delobj(otmp);
1641 } else redisp = TRUE;
1642 }
1643 /* Whether or not it always makes a corpse is, in theory,
1644 * different from whether or not the corpse is "special";
1645 * if we want both, we have to specify it explicitly.
1646 */
1647 if (corpse_chance(mtmp))
1648 (void) make_corpse(mtmp);
1649 }
1650 if(redisp) newsym(x,y);
1651 cleanup:
1652 /* punish bad behaviour */
1653 if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) &&
1654 (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) &&
1655 u.ualign.type != A_CHAOTIC) {
1656 HTelepat &= ~INTRINSIC;
1657 change_luck(-2);
1658 You("murderer!");
1659 if (Blind && !Blind_telepat)
1660 see_monsters(); /* Can't sense monsters any more. */
1661 }
1662 if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1);
1663 if (is_unicorn(mdat) &&
1664 sgn(u.ualign.type) == sgn(mdat->maligntyp)) {
1665 change_luck(-5);
1666 You_feel("guilty...");
1667 }
1668
1669 /* give experience points */
1670 tmp = experience(mtmp, (int)mvitals[mndx].died + 1);
1671 more_experienced(tmp, 0);
1672 newexplevel(); /* will decide if you go up */
1673
1674 /* adjust alignment points */
1675 if (mdat->msound == MS_LEADER) { /* REAL BAD! */
1676 adjalign(-(u.ualign.record+(int)ALIGNLIM/2));
1677 pline("That was %sa bad idea...",
1678 u.uevent.qcompleted ? "probably " : "");
1679 } else if (mdat->msound == MS_NEMESIS) /* Real good! */
1680 adjalign((int)(ALIGNLIM/4));
1681 else if (mdat->msound == MS_GUARDIAN) { /* Bad */
1682 adjalign(-(int)(ALIGNLIM/8));
1683 if (!Hallucination) pline("That was probably a bad idea...");
1684 else pline("Whoopsie-daisy!");
1685 }else if (mtmp->ispriest) {
1686 adjalign((p_coaligned(mtmp)) ? -2 : 2);
1687 /* cancel divine protection for killing your priest */
1688 if (p_coaligned(mtmp)) u.ublessed = 0;
1689 if (mdat->maligntyp == A_NONE)
1690 adjalign((int)(ALIGNLIM / 4)); /* BIG bonus */
1691 } else if (mtmp->mtame) {
1692 adjalign(-15); /* bad!! */
1693 /* your god is mighty displeased... */
1694 if (!Hallucination) You_hear("the rumble of distant thunder...");
1695 else You_hear("the studio audience applaud!");
1696 } else if (mtmp->mpeaceful)
1697 adjalign(-5);
1698
1699 /* malign was already adjusted for u.ualign.type and randomization */
1700 adjalign(mtmp->malign);
1701 }
1702
1703 /* changes the monster into a stone monster of the same type */
1704 /* this should only be called when poly_when_stoned() is true */
1705 void
mon_to_stone(mtmp)1706 mon_to_stone(mtmp)
1707 register struct monst *mtmp;
1708 {
1709 if(mtmp->data->mlet == S_GOLEM) {
1710 /* it's a golem, and not a stone golem */
1711 if(canseemon(mtmp))
1712 pline("%s solidifies...", Monnam(mtmp));
1713 if (newcham(mtmp, &mons[PM_STONE_GOLEM])) {
1714 if(canseemon(mtmp))
1715 pline("Now it's %s.", an(mtmp->data->mname));
1716 } else {
1717 if(canseemon(mtmp))
1718 pline("... and returns to normal.");
1719 }
1720 } else
1721 impossible("Can't polystone %s!", a_monnam(mtmp));
1722 }
1723
1724 void
mnexto(mtmp)1725 mnexto(mtmp) /* Make monster mtmp next to you (if possible) */
1726 struct monst *mtmp;
1727 {
1728 coord mm;
1729
1730 #ifdef STEED
1731 if (mtmp == u.usteed) {
1732 /* Keep your steed in sync with you instead */
1733 mtmp->mx = u.ux;
1734 mtmp->my = u.uy;
1735 return;
1736 }
1737 #endif
1738
1739 if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return;
1740 rloc_to(mtmp, mm.x, mm.y);
1741 return;
1742 }
1743
1744 /* mnearto()
1745 * Put monster near (or at) location if possible.
1746 * Returns:
1747 * 1 - if a monster was moved from x, y to put mtmp at x, y.
1748 * 0 - in most cases.
1749 */
1750 boolean
mnearto(mtmp,x,y,move_other)1751 mnearto(mtmp,x,y,move_other)
1752 register struct monst *mtmp;
1753 xchar x, y;
1754 boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
1755 {
1756 struct monst *othermon = (struct monst *)0;
1757 xchar newx, newy;
1758 coord mm;
1759
1760 if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE);
1761
1762 if (move_other && (othermon = m_at(x, y))) {
1763 if (othermon->wormno)
1764 remove_worm(othermon);
1765 else
1766 remove_monster(x, y);
1767 }
1768
1769 newx = x;
1770 newy = y;
1771
1772 if (!goodpos(newx, newy, mtmp)) {
1773 /* actually we have real problems if enexto ever fails.
1774 * migrating_mons that need to be placed will cause
1775 * no end of trouble.
1776 */
1777 if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE);
1778 newx = mm.x; newy = mm.y;
1779 }
1780
1781 rloc_to(mtmp, newx, newy);
1782
1783 if (move_other && othermon) {
1784 othermon->mx = othermon->my = 0;
1785 (void) mnearto(othermon, x, y, FALSE);
1786 if ((othermon->mx != x) || (othermon->my != y))
1787 return(TRUE);
1788 }
1789
1790 return(FALSE);
1791 }
1792
1793
1794 static const char *poiseff[] = {
1795
1796 " feel weaker", "r brain is on fire",
1797 "r judgement is impaired", "r muscles won't obey you",
1798 " feel very sick", " break out in hives"
1799 };
1800
1801 void
poisontell(typ)1802 poisontell(typ)
1803
1804 int typ;
1805 {
1806 pline("You%s.", poiseff[typ]);
1807 }
1808
1809 void
poisoned(string,typ,pname,fatal)1810 poisoned(string, typ, pname, fatal)
1811 register const char *string, *pname;
1812 register int typ, fatal;
1813 {
1814 register int i, plural;
1815 boolean thrown_weapon = !strncmp(string, "poison", 6);
1816 /* admittedly a kludge... */
1817
1818 if(strcmp(string, "blast") && !thrown_weapon) {
1819 /* 'blast' has already given a 'poison gas' message */
1820 /* so have "poison arrow", "poison dart", etc... */
1821 plural = (string[strlen(string) - 1] == 's')? 1 : 0;
1822 /* avoid "The" Orcus's sting was poisoned... */
1823 pline("%s%s %s poisoned!", isupper(*string) ? "" : "The ",
1824 string, plural ? "were" : "was");
1825 }
1826
1827 if(Poison_resistance) {
1828 if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy);
1829 pline_The("poison doesn't seem to affect you.");
1830 return;
1831 }
1832 i = rn2(fatal + 20*thrown_weapon);
1833 if(i == 0 && typ != A_CHA) {
1834 u.uhp = -1;
1835 pline_The("poison was deadly...");
1836 } else if(i <= 5) {
1837 /* Check that a stat change was made */
1838 if (adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), 1))
1839 pline("You%s!", poiseff[typ]);
1840 } else {
1841 i = thrown_weapon ? rnd(6) : rn1(10,6);
1842 if(Half_physical_damage) i = (i+1) / 2;
1843 losehp(i, pname, KILLED_BY_AN);
1844 }
1845 if(u.uhp < 1) {
1846 killer_format = KILLED_BY_AN;
1847 killer = pname;
1848 /* "Poisoned by a poisoned ___" is redundant */
1849 done(thrown_weapon ? DIED : POISONING);
1850 }
1851 (void) encumber_msg();
1852 }
1853
1854 /* monster responds to player action; not the same as a passive attack */
1855 /* assumes reason for response has been tested, and response _must_ be made */
1856 void
m_respond(mtmp)1857 m_respond(mtmp)
1858 register struct monst *mtmp;
1859 {
1860 if(mtmp->data->msound == MS_SHRIEK) {
1861 if(flags.soundok) {
1862 pline("%s shrieks.", Monnam(mtmp));
1863 stop_occupation();
1864 }
1865 if (!rn2(10)) {
1866 if (!rn2(13))
1867 (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS);
1868 else
1869 (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS);
1870
1871 }
1872 aggravate();
1873 }
1874 if(mtmp->data == &mons[PM_MEDUSA] && !mtmp->mcan) {
1875 register int i;
1876 for(i = 0; i < NATTK; i++)
1877 if(mtmp->data->mattk[i].aatyp == AT_GAZE) {
1878 (void) gazemu(mtmp, &mtmp->data->mattk[i]);
1879 break;
1880 }
1881 }
1882 }
1883
1884 #endif /* OVLB */
1885 #ifdef OVL2
1886
1887 void
setmangry(mtmp)1888 setmangry(mtmp)
1889 register struct monst *mtmp;
1890 {
1891 mtmp->mstrategy &= ~STRAT_WAITMASK;
1892 if(!mtmp->mpeaceful) return;
1893 if(mtmp->mtame) return;
1894 mtmp->mpeaceful = 0;
1895 if(mtmp->ispriest) {
1896 if(p_coaligned(mtmp)) adjalign(-5); /* very bad */
1897 else adjalign(2);
1898 } else
1899 adjalign(-1); /* attacking peaceful monsters is bad */
1900 if (couldsee(mtmp->mx, mtmp->my)) {
1901 if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
1902 pline("%s gets angry!", Monnam(mtmp));
1903 else if (flags.verbose && flags.soundok) growl(mtmp);
1904 }
1905
1906 /* attacking your own quest leader will anger his or her guardians */
1907 if (!flags.mon_moving && /* should always be the case here */
1908 mtmp->data == &mons[quest_info(MS_LEADER)]) {
1909 struct monst *mon;
1910 struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
1911 int got_mad = 0;
1912
1913 /* guardians will sense this attack even if they can't see it */
1914 for (mon = fmon; mon; mon = mon->nmon)
1915 if (!DEADMONSTER(mon) && mon->data == q_guardian && mon->mpeaceful) {
1916 mon->mpeaceful = 0;
1917 if (canseemon(mon)) ++got_mad;
1918 }
1919 if (got_mad && !Hallucination)
1920 pline_The("%s appear%s to be angry too...",
1921 got_mad == 1 ? q_guardian->mname :
1922 makeplural(q_guardian->mname),
1923 got_mad == 1 ? "s" : "");
1924 }
1925 }
1926
1927 void
wakeup(mtmp)1928 wakeup(mtmp)
1929 register struct monst *mtmp;
1930 {
1931 mtmp->msleeping = 0;
1932 mtmp->meating = 0; /* assume there's no salvagable food left */
1933 setmangry(mtmp);
1934 if(mtmp->m_ap_type) seemimic(mtmp);
1935 }
1936
1937 /* Wake up nearby monsters. */
1938 void
wake_nearby()1939 wake_nearby()
1940 {
1941 register struct monst *mtmp;
1942
1943 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1944 if (!DEADMONSTER(mtmp) && distu(mtmp->mx,mtmp->my) < u.ulevel*20) {
1945 mtmp->msleeping = 0;
1946 if (mtmp->mtame && !mtmp->isminion)
1947 EDOG(mtmp)->whistletime = moves;
1948 }
1949 }
1950 }
1951
1952 /* Wake up monsters near some particular location. */
1953 void
wake_nearto(x,y,distance)1954 wake_nearto(x, y, distance)
1955 register int x, y, distance;
1956 {
1957 register struct monst *mtmp;
1958
1959 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1960 if (!DEADMONSTER(mtmp) && mtmp->msleeping && (distance == 0 ||
1961 dist2(mtmp->mx, mtmp->my, x, y) < distance))
1962 mtmp->msleeping = 0;
1963 }
1964 }
1965
1966 /* NOTE: we must check for mimicry before calling this routine */
1967 void
seemimic(mtmp)1968 seemimic(mtmp)
1969 register struct monst *mtmp;
1970 {
1971 /*
1972 * Discovered mimics don't block light.
1973 */
1974 if ((mtmp->m_ap_type == M_AP_FURNITURE &&
1975 (mtmp->mappearance==S_hcdoor || mtmp->mappearance==S_vcdoor))||
1976 (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance == BOULDER))
1977 unblock_point(mtmp->mx,mtmp->my);
1978
1979 mtmp->m_ap_type = M_AP_NOTHING;
1980 mtmp->mappearance = 0;
1981 newsym(mtmp->mx,mtmp->my);
1982 }
1983
1984 /* force all chameleons to become normal */
1985 void
rescham()1986 rescham()
1987 {
1988 register struct monst *mtmp;
1989 int mcham;
1990
1991 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1992 if (DEADMONSTER(mtmp)) continue;
1993 mcham = (int) mtmp->cham;
1994 if (mcham) {
1995 mtmp->cham = CHAM_ORDINARY;
1996 (void) newcham(mtmp, &mons[cham_to_pm[mcham]]);
1997 }
1998 if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
1999 new_were(mtmp);
2000 if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) {
2001 seemimic(mtmp);
2002 /* we pretend that the mimic doesn't */
2003 /* know that it has been unmasked. */
2004 mtmp->msleeping = 1;
2005 }
2006 }
2007 }
2008
2009 /* Let the chameleons change again -dgk */
2010 void
restartcham()2011 restartcham()
2012 {
2013 register struct monst *mtmp;
2014
2015 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
2016 if (DEADMONSTER(mtmp)) continue;
2017 mtmp->cham = pm_to_cham(monsndx(mtmp->data));
2018 if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping &&
2019 cansee(mtmp->mx, mtmp->my)) {
2020 set_mimic_sym(mtmp);
2021 newsym(mtmp->mx,mtmp->my);
2022 }
2023 }
2024 }
2025
2026 /* called when restoring a monster from a saved level; protection
2027 against shape-changing might be different now than it was at the
2028 time the level was saved. */
2029 void
restore_cham(mon)2030 restore_cham(mon)
2031 struct monst *mon;
2032 {
2033 int mcham;
2034
2035 if (Protection_from_shape_changers) {
2036 mcham = (int) mon->cham;
2037 if (mcham) {
2038 mon->cham = CHAM_ORDINARY;
2039 (void) newcham(mon, &mons[cham_to_pm[mcham]]);
2040 } else if (is_were(mon->data) && !is_human(mon->data)) {
2041 new_were(mon);
2042 }
2043 } else {
2044 mon->cham = pm_to_cham(monsndx(mon->data));
2045 }
2046 }
2047
2048 /* unwatched hiders may hide again; if so, a 1 is returned. */
2049 STATIC_OVL boolean
restrap(mtmp)2050 restrap(mtmp)
2051 register struct monst *mtmp;
2052 {
2053 if(mtmp->cham || mtmp->mcan || mtmp->m_ap_type ||
2054 cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck))
2055 return(FALSE);
2056
2057 if(mtmp->data->mlet == S_MIMIC) {
2058 set_mimic_sym(mtmp);
2059 return(TRUE);
2060 } else
2061 if(levl[mtmp->mx][mtmp->my].typ == ROOM) {
2062 mtmp->mundetected = 1;
2063 return(TRUE);
2064 }
2065
2066 return(FALSE);
2067 }
2068
2069 short *animal_list = 0; /* list of PM values for animal monsters */
2070 int animal_list_count;
2071
2072 void
mon_animal_list(construct)2073 mon_animal_list(construct)
2074 boolean construct;
2075 {
2076 if (construct) {
2077 short animal_temp[SPECIAL_PM];
2078 int i, n;
2079
2080 /* if (animal_list) impossible("animal_list already exists"); */
2081
2082 for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++)
2083 if (is_animal(&mons[i])) animal_temp[n++] = i;
2084 /* if (n == 0) animal_temp[n++] = NON_PM; */
2085
2086 animal_list = (short *)alloc(n * sizeof *animal_list);
2087 (void) memcpy((genericptr_t)animal_list,
2088 (genericptr_t)animal_temp,
2089 n * sizeof *animal_list);
2090 animal_list_count = n;
2091 } else { /* release */
2092 if (animal_list) free((genericptr_t)animal_list), animal_list = 0;
2093 animal_list_count = 0;
2094 }
2095 }
2096
2097 STATIC_OVL int
pick_animal()2098 pick_animal()
2099 {
2100 if (!animal_list) mon_animal_list(TRUE);
2101
2102 return animal_list[rn2(animal_list_count)];
2103 }
2104
2105 STATIC_OVL int
select_newcham_form(mon)2106 select_newcham_form(mon)
2107 struct monst *mon;
2108 {
2109 int mndx = NON_PM;
2110
2111 switch (mon->cham) {
2112 case CHAM_SANDESTIN:
2113 if (rn2(7)) mndx = pick_nasty();
2114 break;
2115 case CHAM_DOPPELGANGER:
2116 if (!rn2(7)) mndx = pick_nasty();
2117 else if (rn2(3)) mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1,
2118 PM_ARCHEOLOGIST);
2119 break;
2120 case CHAM_CHAMELEON:
2121 if (!rn2(3)) mndx = pick_animal();
2122 break;
2123 case CHAM_ORDINARY:
2124 break;
2125 }
2126 if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
2127 return mndx;
2128 }
2129
2130 /* make a chameleon look like a new monster; returns 1 if it actually changed */
2131 int
newcham(mtmp,mdat)2132 newcham(mtmp, mdat)
2133 struct monst *mtmp;
2134 struct permonst *mdat;
2135 {
2136 int mhp, hpn, hpd;
2137 int mndx, tryct;
2138 struct permonst *olddata = mtmp->data;
2139
2140 /* mdat = 0 -> caller wants a random monster shape */
2141 tryct = 0;
2142 if (mdat == 0) {
2143 while (++tryct <= 100) {
2144 mndx = select_newcham_form(mtmp);
2145 mdat = &mons[mndx];
2146 if ((mvitals[mndx].mvflags & G_GENOD) != 0 ||
2147 is_placeholder(mdat)) continue;
2148 /* polyok rules out all M2_PNAME and M2_WERE's;
2149 select_newcham_form might deliberately pick a player
2150 character type, so we can't arbitrarily rule out all
2151 human forms any more */
2152 if (is_mplayer(mdat) || (!is_human(mdat) && polyok(mdat)))
2153 break;
2154 }
2155 if (tryct > 100) return 0; /* Should never happen */
2156 } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD)
2157 return(0); /* passed in mdat is genocided */
2158
2159 if(is_male(mdat)) {
2160 if(mtmp->female) mtmp->female = FALSE;
2161 } else if (is_female(mdat)) {
2162 if(!mtmp->female) mtmp->female = TRUE;
2163 } else if (!is_neuter(mdat)) {
2164 if(!rn2(10)) mtmp->female = !mtmp->female;
2165 }
2166
2167 if (In_endgame(&u.uz) && is_mplayer(olddata)) {
2168 /* mplayers start out as "Foo the Bar", but some of the
2169 * titles are inappropriate when polymorphed, particularly
2170 * into the opposite sex. players don't use ranks when
2171 * polymorphed, so dropping the rank for mplayers seems
2172 * reasonable.
2173 */
2174 char *p = index(NAME(mtmp), ' ');
2175 if (p) {
2176 *p = '\0';
2177 mtmp->mnamelth = p - NAME(mtmp) + 1;
2178 }
2179 }
2180
2181 if(mdat == mtmp->data) return(0); /* still the same monster */
2182
2183 if(mtmp->wormno) { /* throw tail away */
2184 wormgone(mtmp);
2185 place_monster(mtmp, mtmp->mx, mtmp->my);
2186 }
2187
2188 hpn = mtmp->mhp;
2189 hpd = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
2190 if(!hpd) hpd = 4;
2191
2192 mtmp->m_lev = adj_lev(mdat); /* new monster level */
2193
2194 mhp = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
2195 if(!mhp) mhp = 4;
2196
2197 /* new hp: same fraction of max as before */
2198 #ifndef LINT
2199 mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
2200 #endif
2201 if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */
2202 /* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
2203 0HD creature will require this statement */
2204 if (!mtmp->mhp) mtmp->mhp = 1;
2205
2206 /* and the same for maximum hit points */
2207 hpn = mtmp->mhpmax;
2208 #ifndef LINT
2209 mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
2210 #endif
2211 if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */
2212 if (!mtmp->mhpmax) mtmp->mhpmax = 1;
2213
2214 /* take on the new form... */
2215 set_mon_data(mtmp, mdat, 0);
2216
2217 if (emits_light(olddata) != emits_light(mtmp->data)) {
2218 /* used to give light, now doesn't, or vice versa,
2219 or light's range has changed */
2220 if (emits_light(olddata))
2221 del_light_source(LS_MONSTER, (genericptr_t)mtmp);
2222 if (emits_light(mtmp->data))
2223 new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data),
2224 LS_MONSTER, (genericptr_t)mtmp);
2225 }
2226 mtmp->perminvis = pm_invisible(mdat);
2227 mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis;
2228 if (!(hides_under(mdat) && OBJ_AT(mtmp->mx, mtmp->my)) &&
2229 !(mdat->mlet == S_EEL && is_pool(mtmp->mx, mtmp->my)))
2230 mtmp->mundetected = 0;
2231 if (u.ustuck == mtmp) {
2232 if(u.uswallow) {
2233 if(!attacktype(mdat,AT_ENGL)) {
2234 /* Does mdat care? */
2235 if (!noncorporeal(mdat) && !amorphous(mdat) &&
2236 !is_whirly(mdat) &&
2237 (mdat != &mons[PM_YELLOW_LIGHT])) {
2238 You("break out of %s%s!", mon_nam(mtmp),
2239 (is_animal(mdat)?
2240 "'s stomach" : ""));
2241 mtmp->mhp = 1; /* almost dead */
2242 }
2243 expels(mtmp, olddata, FALSE);
2244 }
2245 } else if (!sticks(mdat) && !sticks(youmonst.data))
2246 unstuck(mtmp);
2247 }
2248
2249 #ifndef DCC30_BUG
2250 if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) {
2251 #else
2252 /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the
2253 * same expression.
2254 */
2255 if (mdat == &mons[PM_LONG_WORM] &&
2256 (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) {
2257 #endif
2258 /* we can now create worms with tails - 11/91 */
2259 initworm(mtmp, rn2(5));
2260 if (count_wsegs(mtmp))
2261 place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my);
2262 }
2263
2264 newsym(mtmp->mx,mtmp->my);
2265
2266 mon_break_armor(mtmp);
2267 if (!(mtmp->misc_worn_check & W_ARMG))
2268 mselftouch(mtmp, "No longer petrify-resistant, ",
2269 !flags.mon_moving);
2270 possibly_unwield(mtmp);
2271 m_dowear(mtmp, FALSE);
2272
2273 /* This ought to re-test can_carry() on each item in the inventory
2274 * rather than just checking ex-giants & boulders, but that'd be
2275 * pretty expensive to perform. If implemented, then perhaps
2276 * minvent should be sorted in order to drop heaviest items first.
2277 */
2278 /* former giants can't continue carrying boulders */
2279 if (mtmp->minvent && !throws_rocks(mdat)) {
2280 register struct obj *otmp, *otmp2;
2281
2282 for (otmp = mtmp->minvent; otmp; otmp = otmp2) {
2283 otmp2 = otmp->nobj;
2284 if (otmp->otyp == BOULDER) {
2285 obj_extract_self(otmp);
2286 /* probably ought to give some "drop" message here */
2287 if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue;
2288 place_object(otmp, mtmp->mx, mtmp->my);
2289 }
2290 }
2291 }
2292
2293 return(1);
2294 }
2295
2296 /* sometimes an egg will be special */
2297 #define BREEDER_EGG (!rn2(77))
2298
2299 /*
2300 * Determine if the given monster number can be hatched from an egg.
2301 * Return the monster number to use as the egg's corpsenm. Return
2302 * NON_PM if the given monster can't be hatched.
2303 */
2304 int
can_be_hatched(mnum)2305 can_be_hatched(mnum)
2306 int mnum;
2307 {
2308 mnum = little_to_big(mnum);
2309 /*
2310 * Queen bees lay killer bee eggs (usually), but killer bees don't
2311 * grow into queen bees. Ditto for [winged-]gargoyles.
2312 */
2313 if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE ||
2314 (lays_eggs(&mons[mnum]) && (BREEDER_EGG ||
2315 (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE))))
2316 return mnum;
2317 return NON_PM;
2318 }
2319
2320 /* type of egg laid by #sit; usually matches parent */
2321 int
egg_type_from_parent(mnum,force_ordinary)2322 egg_type_from_parent(mnum, force_ordinary)
2323 int mnum; /* parent monster; caller must handle lays_eggs() check */
2324 boolean force_ordinary;
2325 {
2326 if (force_ordinary || !BREEDER_EGG) {
2327 if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE;
2328 else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE;
2329 }
2330 return mnum;
2331 }
2332
2333 /* decide whether an egg of the indicated monster type is viable; */
2334 /* also used to determine whether an egg or tin can be created... */
2335 boolean
dead_species(m_idx,egg)2336 dead_species(m_idx, egg)
2337 int m_idx;
2338 boolean egg;
2339 {
2340 /*
2341 * For monsters with both baby and adult forms, genociding either
2342 * form kills all eggs of that monster. Monsters with more than
2343 * two forms (small->large->giant mimics) are more or less ignored;
2344 * fortunately, none of them have eggs. Species extinction due to
2345 * overpopulation does not kill eggs.
2346 */
2347 return (boolean)
2348 (m_idx >= LOW_PM &&
2349 ((mvitals[m_idx].mvflags & G_GENOD) != 0 ||
2350 (egg &&
2351 (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0)));
2352 }
2353
2354 /* kill off any eggs of genocided monsters */
2355 STATIC_OVL void
kill_eggs(obj_list)2356 kill_eggs(obj_list)
2357 struct obj *obj_list;
2358 {
2359 struct obj *otmp;
2360
2361 for (otmp = obj_list; otmp; otmp = otmp->nobj)
2362 if (otmp->otyp == EGG) {
2363 if (dead_species(otmp->corpsenm, TRUE)) {
2364 /*
2365 * It seems we could also just catch this when
2366 * it attempted to hatch, so we wouldn't have to
2367 * search all of the objlists.. or stop all
2368 * hatch timers based on a corpsenm.
2369 */
2370 kill_egg(otmp);
2371 }
2372 #if 0 /* not used */
2373 } else if (otmp->otyp == TIN) {
2374 if (dead_species(otmp->corpsenm, FALSE))
2375 otmp->corpsenm = NON_PM; /* empty tin */
2376 } else if (otmp->otyp == CORPSE) {
2377 if (dead_species(otmp->corpsenm, FALSE))
2378 ; /* not yet implemented... */
2379 #endif
2380 } else if (Has_contents(otmp)) {
2381 kill_eggs(otmp->cobj);
2382 }
2383 }
2384
2385 /* kill all members of genocided species */
2386 void
kill_genocided_monsters()2387 kill_genocided_monsters()
2388 {
2389 struct monst *mtmp, *mtmp2;
2390 boolean kill_cham[CHAM_MAX_INDX+1];
2391 int mndx;
2392
2393 kill_cham[CHAM_ORDINARY] = FALSE; /* (this is mndx==0) */
2394 for (mndx = 1; mndx <= CHAM_MAX_INDX; mndx++)
2395 kill_cham[mndx] = (mvitals[cham_to_pm[mndx]].mvflags & G_GENOD) != 0;
2396 /*
2397 * Called during genocide, and again upon level change. The latter
2398 * catches up with any migrating monsters as they finally arrive at
2399 * their intended destinations, so possessions get deposited there.
2400 *
2401 * Chameleon handling:
2402 * 1) if chameleons have been genocided, destroy them
2403 * regardless of current form;
2404 * 2) otherwise, force every chameleon which is imitating
2405 * any genocided species to take on a new form.
2406 */
2407 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
2408 mtmp2 = mtmp->nmon;
2409 if (DEADMONSTER(mtmp)) continue;
2410 mndx = monsndx(mtmp->data);
2411 if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) {
2412 if (mtmp->cham && !kill_cham[mtmp->cham])
2413 (void) newcham(mtmp, (struct permonst *)0);
2414 else
2415 mondead(mtmp);
2416 }
2417 if (mtmp->minvent) kill_eggs(mtmp->minvent);
2418 }
2419
2420 kill_eggs(invent);
2421 kill_eggs(fobj);
2422 kill_eggs(level.buriedobjlist);
2423 }
2424
2425 #endif /* OVL2 */
2426 #ifdef OVLB
2427
2428 void
golemeffects(mon,damtype,dam)2429 golemeffects(mon, damtype, dam)
2430 register struct monst *mon;
2431 int damtype, dam;
2432 {
2433 int heal = 0, slow = 0;
2434
2435 if (mon->data == &mons[PM_FLESH_GOLEM]) {
2436 if (damtype == AD_ELEC) heal = dam / 6;
2437 else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1;
2438 } else if (mon->data == &mons[PM_IRON_GOLEM]) {
2439 if (damtype == AD_ELEC) slow = 1;
2440 else if (damtype == AD_FIRE) heal = dam;
2441 } else {
2442 return;
2443 }
2444 if (slow) {
2445 if (mon->mspeed != MSLOW) {
2446 unsigned int oldspeed = mon->mspeed;
2447
2448 mon_adjust_speed(mon, -1);
2449 if (mon->mspeed != oldspeed && cansee(mon->mx, mon->my))
2450 pline("%s seems to be moving slower.", Monnam(mon));
2451 }
2452 }
2453 if (heal) {
2454 if (mon->mhp < mon->mhpmax) {
2455 mon->mhp += dam;
2456 if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
2457 if (cansee(mon->mx, mon->my))
2458 pline("%s seems healthier.", Monnam(mon));
2459 }
2460 }
2461 }
2462
2463 boolean
angry_guards(silent)2464 angry_guards(silent)
2465 register boolean silent;
2466 {
2467 register struct monst *mtmp;
2468 register int ct = 0, nct = 0, sct = 0, slct = 0;
2469
2470 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
2471 if (DEADMONSTER(mtmp)) continue;
2472 if((mtmp->data == &mons[PM_WATCHMAN] ||
2473 mtmp->data == &mons[PM_WATCH_CAPTAIN])
2474 && mtmp->mpeaceful) {
2475 ct++;
2476 if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
2477 if (distu(mtmp->mx, mtmp->my) == 2) nct++;
2478 else sct++;
2479 }
2480 if (mtmp->msleeping || mtmp->mfrozen) {
2481 slct++;
2482 mtmp->msleeping = mtmp->mfrozen = 0;
2483 }
2484 mtmp->mpeaceful = 0;
2485 }
2486 }
2487 if(ct) {
2488 if(!silent) { /* do we want pline msgs? */
2489 if(slct) pline_The("guard%s wake%s up!",
2490 slct > 1 ? "s" : "", slct == 1 ? "s" : "");
2491 if(nct || sct) {
2492 if(nct) pline_The("guard%s get%s angry!",
2493 nct == 1 ? "" : "s", nct == 1 ? "s" : "");
2494 else if(!Blind)
2495 You("see %sangry guard%s approaching!",
2496 sct == 1 ? "an " : "", sct > 1 ? "s" : "");
2497 } else if(flags.soundok)
2498 You_hear("the shrill sound of a guard's whistle.");
2499 }
2500 return(TRUE);
2501 }
2502 return(FALSE);
2503 }
2504
2505 void
pacify_guards()2506 pacify_guards()
2507 {
2508 register struct monst *mtmp;
2509
2510 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
2511 if (DEADMONSTER(mtmp)) continue;
2512 if (mtmp->data == &mons[PM_WATCHMAN] ||
2513 mtmp->data == &mons[PM_WATCH_CAPTAIN])
2514 mtmp->mpeaceful = 1;
2515 }
2516 }
2517 #endif /* OVLB */
2518
2519 /*mon.c*/
2520