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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1802 | poisontell(typ)
1803 |
1804 | int typ;
1805 | {
1806 | pline("You%s.", poiseff[typ]);
1807 | }
1808 |
1809 | void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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*/