1 1.14 dholland /* $NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $ */ 2 1.4 christos 3 1.2 mycroft /* 4 1.6 jsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 1.6 jsm * Amsterdam 6 1.6 jsm * All rights reserved. 7 1.6 jsm * 8 1.6 jsm * Redistribution and use in source and binary forms, with or without 9 1.6 jsm * modification, are permitted provided that the following conditions are 10 1.6 jsm * met: 11 1.6 jsm * 12 1.6 jsm * - Redistributions of source code must retain the above copyright notice, 13 1.6 jsm * this list of conditions and the following disclaimer. 14 1.6 jsm * 15 1.6 jsm * - Redistributions in binary form must reproduce the above copyright 16 1.6 jsm * notice, this list of conditions and the following disclaimer in the 17 1.6 jsm * documentation and/or other materials provided with the distribution. 18 1.6 jsm * 19 1.6 jsm * - Neither the name of the Stichting Centrum voor Wiskunde en 20 1.6 jsm * Informatica, nor the names of its contributors may be used to endorse or 21 1.6 jsm * promote products derived from this software without specific prior 22 1.6 jsm * written permission. 23 1.6 jsm * 24 1.6 jsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 1.6 jsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 1.6 jsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 1.6 jsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 1.6 jsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 1.6 jsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 1.6 jsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 1.6 jsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 1.6 jsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 1.6 jsm */ 36 1.6 jsm 37 1.6 jsm /* 38 1.6 jsm * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org> 39 1.6 jsm * All rights reserved. 40 1.6 jsm * 41 1.6 jsm * Redistribution and use in source and binary forms, with or without 42 1.6 jsm * modification, are permitted provided that the following conditions 43 1.6 jsm * are met: 44 1.6 jsm * 1. Redistributions of source code must retain the above copyright 45 1.6 jsm * notice, this list of conditions and the following disclaimer. 46 1.6 jsm * 2. Redistributions in binary form must reproduce the above copyright 47 1.6 jsm * notice, this list of conditions and the following disclaimer in the 48 1.6 jsm * documentation and/or other materials provided with the distribution. 49 1.6 jsm * 3. The name of the author may not be used to endorse or promote products 50 1.6 jsm * derived from this software without specific prior written permission. 51 1.6 jsm * 52 1.6 jsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 1.6 jsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 1.6 jsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 1.6 jsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 1.6 jsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 1.6 jsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 1.6 jsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 1.6 jsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.2 mycroft */ 63 1.2 mycroft 64 1.4 christos #include <sys/cdefs.h> 65 1.2 mycroft #ifndef lint 66 1.14 dholland __RCSID("$NetBSD: hack.mon.c,v 1.14 2011/08/07 06:03:45 dholland Exp $"); 67 1.4 christos #endif /* not lint */ 68 1.1 cgd 69 1.4 christos #include <stdlib.h> 70 1.1 cgd #include "hack.h" 71 1.4 christos #include "extern.h" 72 1.1 cgd #include "hack.mfndpos.h" 73 1.1 cgd 74 1.10 dholland static int warnlevel; /* used by movemon and dochugw */ 75 1.10 dholland static long lastwarntime; 76 1.10 dholland static int lastwarnlev; 77 1.10 dholland 78 1.10 dholland static const char *const warnings[] = { 79 1.1 cgd "white", "pink", "red", "ruby", "purple", "black" 80 1.1 cgd }; 81 1.1 cgd 82 1.10 dholland static int dochugw(struct monst *); 83 1.10 dholland static void mpickgold(struct monst *); 84 1.10 dholland static void mpickgems(struct monst *); 85 1.10 dholland static void dmonsfree(void); 86 1.10 dholland static int ishuman(struct monst *); 87 1.10 dholland 88 1.4 christos void 89 1.9 dholland movemon(void) 90 1.1 cgd { 91 1.4 christos struct monst *mtmp; 92 1.4 christos int fr; 93 1.1 cgd 94 1.1 cgd warnlevel = 0; 95 1.1 cgd 96 1.4 christos while (1) { 97 1.1 cgd /* find a monster that we haven't treated yet */ 98 1.4 christos /* 99 1.4 christos * note that mtmp or mtmp->nmon might get killed while mtmp 100 1.4 christos * moves, so we cannot just walk down the chain (even new 101 1.4 christos * monsters might get created!) 102 1.4 christos */ 103 1.4 christos for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 104 1.4 christos if (mtmp->mlstmv < moves) 105 1.4 christos goto next_mon; 106 1.1 cgd /* treated all monsters */ 107 1.1 cgd break; 108 1.1 cgd 109 1.4 christos next_mon: 110 1.1 cgd mtmp->mlstmv = moves; 111 1.1 cgd 112 1.1 cgd /* most monsters drown in pools */ 113 1.4 christos { 114 1.4 christos boolean inpool, iseel; 115 1.1 cgd 116 1.4 christos inpool = (levl[mtmp->mx][mtmp->my].typ == POOL); 117 1.4 christos iseel = (mtmp->data->mlet == ';'); 118 1.4 christos if (inpool && !iseel) { 119 1.4 christos if (cansee(mtmp->mx, mtmp->my)) 120 1.4 christos pline("%s drowns.", Monnam(mtmp)); 121 1.4 christos mondead(mtmp); 122 1.4 christos continue; 123 1.4 christos } 124 1.4 christos /* but eels have a difficult time outside */ 125 1.4 christos if (iseel && !inpool) { 126 1.4 christos if (mtmp->mhp > 1) 127 1.4 christos mtmp->mhp--; 128 1.4 christos mtmp->mflee = 1; 129 1.4 christos mtmp->mfleetim += 2; 130 1.4 christos } 131 1.1 cgd } 132 1.4 christos if (mtmp->mblinded && !--mtmp->mblinded) 133 1.1 cgd mtmp->mcansee = 1; 134 1.4 christos if (mtmp->mfleetim && !--mtmp->mfleetim) 135 1.1 cgd mtmp->mflee = 0; 136 1.4 christos if (mtmp->mimic) 137 1.4 christos continue; 138 1.4 christos if (mtmp->mspeed != MSLOW || !(moves % 2)) { 139 1.1 cgd /* continue if the monster died fighting */ 140 1.1 cgd fr = -1; 141 1.4 christos if (Conflict && cansee(mtmp->mx, mtmp->my) 142 1.4 christos && (fr = fightm(mtmp)) == 2) 143 1.1 cgd continue; 144 1.4 christos if (fr < 0 && dochugw(mtmp)) 145 1.1 cgd continue; 146 1.1 cgd } 147 1.4 christos if (mtmp->mspeed == MFAST && dochugw(mtmp)) 148 1.1 cgd continue; 149 1.1 cgd } 150 1.1 cgd 151 1.1 cgd warnlevel -= u.ulevel; 152 1.4 christos if (warnlevel >= SIZE(warnings)) 153 1.4 christos warnlevel = SIZE(warnings) - 1; 154 1.4 christos if (warnlevel >= 0) 155 1.4 christos if (warnlevel > lastwarnlev || moves > lastwarntime + 5) { 156 1.5 jsm const char *rr; 157 1.4 christos switch (Warning & (LEFT_RING | RIGHT_RING)) { 158 1.4 christos case LEFT_RING: 159 1.4 christos rr = "Your left ring glows"; 160 1.4 christos break; 161 1.4 christos case RIGHT_RING: 162 1.4 christos rr = "Your right ring glows"; 163 1.4 christos break; 164 1.4 christos case LEFT_RING | RIGHT_RING: 165 1.4 christos rr = "Both your rings glow"; 166 1.4 christos break; 167 1.4 christos default: 168 1.4 christos rr = "Your fingertips glow"; 169 1.4 christos break; 170 1.4 christos } 171 1.4 christos pline("%s %s!", rr, warnings[warnlevel]); 172 1.4 christos lastwarntime = moves; 173 1.4 christos lastwarnlev = warnlevel; 174 1.4 christos } 175 1.4 christos dmonsfree(); /* remove all dead monsters */ 176 1.1 cgd } 177 1.1 cgd 178 1.4 christos void 179 1.9 dholland justswld(struct monst *mtmp, const char *name) 180 1.1 cgd { 181 1.1 cgd 182 1.1 cgd mtmp->mx = u.ux; 183 1.1 cgd mtmp->my = u.uy; 184 1.1 cgd u.ustuck = mtmp; 185 1.1 cgd pmon(mtmp); 186 1.4 christos kludge("%s swallows you!", name); 187 1.1 cgd more(); 188 1.1 cgd seeoff(1); 189 1.1 cgd u.uswallow = 1; 190 1.1 cgd u.uswldtim = 0; 191 1.1 cgd swallowed(); 192 1.1 cgd } 193 1.1 cgd 194 1.4 christos void 195 1.11 joerg youswld(struct monst *mtmp, int dam, unsigned int die, const char *name) 196 1.1 cgd { 197 1.4 christos if (mtmp != u.ustuck) 198 1.4 christos return; 199 1.4 christos kludge("%s digests you!", name); 200 1.1 cgd u.uhp -= dam; 201 1.4 christos if (u.uswldtim++ >= die) { /* a3 */ 202 1.1 cgd pline("It totally digests you!"); 203 1.1 cgd u.uhp = -1; 204 1.1 cgd } 205 1.4 christos if (u.uhp < 1) 206 1.4 christos done_in_by(mtmp); 207 1.4 christos #if 0 208 1.4 christos flags.botlx = 1; /* should we show status line ? */ 209 1.4 christos #endif 210 1.1 cgd } 211 1.1 cgd 212 1.10 dholland static int 213 1.9 dholland dochugw(struct monst *mtmp) 214 1.4 christos { 215 1.4 christos int x = mtmp->mx; 216 1.4 christos int y = mtmp->my; 217 1.8 dholland int dead = dochug(mtmp); 218 1.4 christos int dd; 219 1.8 dholland 220 1.8 dholland if (!dead) /* monster still alive */ 221 1.4 christos if (Warning) 222 1.4 christos if (!mtmp->mpeaceful) 223 1.4 christos if (mtmp->data->mlevel > warnlevel) 224 1.4 christos if ((dd = dist(mtmp->mx, mtmp->my)) < dist(x, y)) 225 1.4 christos if (dd < 100) 226 1.4 christos if (!canseemon(mtmp)) 227 1.4 christos warnlevel = mtmp->data->mlevel; 228 1.8 dholland return (dead); 229 1.1 cgd } 230 1.1 cgd 231 1.1 cgd /* returns 1 if monster died moving, 0 otherwise */ 232 1.4 christos int 233 1.9 dholland dochug(struct monst *mtmp) 234 1.1 cgd { 235 1.5 jsm const struct permonst *mdat; 236 1.4 christos int tmp = 0, nearby, scared; 237 1.1 cgd 238 1.4 christos if (mtmp->cham && !rn2(6)) 239 1.4 christos (void) newcham(mtmp, &mons[dlevel + 14 + rn2(CMNUM - 14 - dlevel)]); 240 1.1 cgd mdat = mtmp->data; 241 1.4 christos if (mdat->mlevel < 0) 242 1.4 christos panic("bad monster %c (%d)", mdat->mlet, mdat->mlevel); 243 1.1 cgd 244 1.1 cgd /* regenerate monsters */ 245 1.4 christos if ((!(moves % 20) || strchr(MREGEN, mdat->mlet)) && 246 1.1 cgd mtmp->mhp < mtmp->mhpmax) 247 1.1 cgd mtmp->mhp++; 248 1.1 cgd 249 1.4 christos if (mtmp->mfroz) 250 1.4 christos return (0); /* frozen monsters don't do anything */ 251 1.1 cgd 252 1.4 christos if (mtmp->msleep) { 253 1.1 cgd /* wake up, or get out of here. */ 254 1.1 cgd /* ettins are hard to surprise */ 255 1.1 cgd /* Nymphs and Leprechauns do not easily wake up */ 256 1.4 christos if (cansee(mtmp->mx, mtmp->my) && 257 1.4 christos (!Stealth || (mdat->mlet == 'e' && rn2(10))) && 258 1.4 christos (!strchr("NL", mdat->mlet) || !rn2(50)) && 259 1.4 christos (Aggravate_monster || strchr("d1", mdat->mlet) 260 1.4 christos || (!rn2(7) && !mtmp->mimic))) 261 1.1 cgd mtmp->msleep = 0; 262 1.4 christos else 263 1.4 christos return (0); 264 1.1 cgd } 265 1.1 cgd /* not frozen or sleeping: wipe out texts written in the dust */ 266 1.1 cgd wipe_engr_at(mtmp->mx, mtmp->my, 1); 267 1.1 cgd 268 1.1 cgd /* confused monsters get unconfused with small probability */ 269 1.4 christos if (mtmp->mconf && !rn2(50)) 270 1.4 christos mtmp->mconf = 0; 271 1.1 cgd 272 1.1 cgd /* some monsters teleport */ 273 1.4 christos if (mtmp->mflee && strchr("tNL", mdat->mlet) && !rn2(40)) { 274 1.1 cgd rloc(mtmp); 275 1.4 christos return (0); 276 1.1 cgd } 277 1.4 christos if (mdat->mmove < rnd(6)) 278 1.4 christos return (0); 279 1.1 cgd 280 1.1 cgd /* fleeing monsters might regain courage */ 281 1.4 christos if (mtmp->mflee && !mtmp->mfleetim 282 1.1 cgd && mtmp->mhp == mtmp->mhpmax && !rn2(25)) 283 1.1 cgd mtmp->mflee = 0; 284 1.1 cgd 285 1.1 cgd nearby = (dist(mtmp->mx, mtmp->my) < 3); 286 1.1 cgd scared = (nearby && (sengr_at("Elbereth", u.ux, u.uy) || 287 1.4 christos sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy))); 288 1.4 christos if (scared && !mtmp->mflee) { 289 1.1 cgd mtmp->mflee = 1; 290 1.1 cgd mtmp->mfleetim = (rn2(7) ? rnd(10) : rnd(100)); 291 1.1 cgd } 292 1.4 christos if (!nearby || 293 1.4 christos mtmp->mflee || 294 1.4 christos mtmp->mconf || 295 1.4 christos (mtmp->minvis && !rn2(3)) || 296 1.4 christos (strchr("BIuy", mdat->mlet) && !rn2(4)) || 297 1.4 christos (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) || 298 1.4 christos (!mtmp->mcansee && !rn2(4)) || 299 1.4 christos mtmp->mpeaceful 300 1.4 christos ) { 301 1.4 christos tmp = m_move(mtmp, 0); /* 2: monster died moving */ 302 1.4 christos if (tmp == 2 || (tmp && mdat->mmove <= 12)) 303 1.4 christos return (tmp == 2); 304 1.4 christos } 305 1.4 christos if (!strchr("Ea", mdat->mlet) && nearby && 306 1.4 christos !mtmp->mpeaceful && u.uhp > 0 && !scared) { 307 1.4 christos if (mhitu(mtmp)) 308 1.4 christos return (1); /* monster died (e.g. 'y' or 'F') */ 309 1.1 cgd } 310 1.1 cgd /* extra movement for fast monsters */ 311 1.4 christos if (mdat->mmove - 12 > rnd(12)) 312 1.4 christos tmp = m_move(mtmp, 1); 313 1.4 christos return (tmp == 2); 314 1.4 christos } 315 1.4 christos 316 1.4 christos int 317 1.5 jsm m_move(struct monst *mtmp, int after) 318 1.4 christos { 319 1.4 christos struct monst *mtmp2; 320 1.4 christos int nx, ny, omx, omy, appr, nearer, cnt, i, j; 321 1.4 christos xchar gx, gy, nix, niy, chcnt; 322 1.4 christos schar chi; 323 1.4 christos boolean likegold = 0, likegems = 0, likeobjs = 0; 324 1.4 christos char msym = mtmp->data->mlet; 325 1.4 christos schar mmoved = 0; /* not strictly nec.: chi >= 0 will 326 1.4 christos * do */ 327 1.4 christos coord poss[9]; 328 1.4 christos int info[9]; 329 1.4 christos 330 1.4 christos if (mtmp->mfroz || mtmp->msleep) 331 1.4 christos return (0); 332 1.4 christos if (mtmp->mtrapped) { 333 1.1 cgd i = mintrap(mtmp); 334 1.4 christos if (i == 2) 335 1.4 christos return (2); /* he died */ 336 1.4 christos if (i == 1) 337 1.4 christos return (0); /* still in trap, so didnt move */ 338 1.1 cgd } 339 1.4 christos if (mtmp->mhide && o_at(mtmp->mx, mtmp->my) && rn2(10)) 340 1.4 christos return (0); /* do not leave hiding place */ 341 1.1 cgd 342 1.1 cgd #ifndef NOWORM 343 1.4 christos if (mtmp->wormno) 344 1.1 cgd goto not_special; 345 1.4 christos #endif /* NOWORM */ 346 1.1 cgd 347 1.1 cgd /* my dog gets a special treatment */ 348 1.4 christos if (mtmp->mtame) { 349 1.4 christos return (dog_move(mtmp, after)); 350 1.1 cgd } 351 1.1 cgd /* likewise for shopkeeper */ 352 1.4 christos if (mtmp->isshk) { 353 1.1 cgd mmoved = shk_move(mtmp); 354 1.4 christos if (mmoved >= 0) 355 1.1 cgd goto postmov; 356 1.4 christos mmoved = 0; /* follow player outside shop */ 357 1.1 cgd } 358 1.1 cgd /* and for the guard */ 359 1.4 christos if (mtmp->isgd) { 360 1.1 cgd mmoved = gd_move(); 361 1.1 cgd goto postmov; 362 1.1 cgd } 363 1.4 christos /* 364 1.4 christos * teleport if that lies in our nature ('t') or when badly wounded 365 1.4 christos * ('1') 366 1.4 christos */ 367 1.4 christos if ((msym == 't' && !rn2(5)) 368 1.4 christos || (msym == '1' && (mtmp->mhp < 7 || (!xdnstair && !rn2(5)) 369 1.4 christos || levl[u.ux][u.uy].typ == STAIRS))) { 370 1.4 christos if (mtmp->mhp < 7 || (msym == 't' && rn2(2))) 371 1.1 cgd rloc(mtmp); 372 1.1 cgd else 373 1.1 cgd mnexto(mtmp); 374 1.1 cgd mmoved = 1; 375 1.1 cgd goto postmov; 376 1.1 cgd } 377 1.1 cgd /* spit fire ('D') or use a wand ('1') when appropriate */ 378 1.4 christos if (strchr("D1", msym)) 379 1.1 cgd inrange(mtmp); 380 1.1 cgd 381 1.4 christos if (msym == 'U' && !mtmp->mcan && canseemon(mtmp) && 382 1.1 cgd mtmp->mcansee && rn2(5)) { 383 1.4 christos if (!Confusion) 384 1.1 cgd pline("%s's gaze has confused you!", Monnam(mtmp)); 385 1.1 cgd else 386 1.1 cgd pline("You are getting more and more confused."); 387 1.4 christos if (rn2(3)) 388 1.4 christos mtmp->mcan = 1; 389 1.4 christos Confusion += d(3, 4); /* timeout */ 390 1.1 cgd } 391 1.1 cgd not_special: 392 1.4 christos if (!mtmp->mflee && u.uswallow && u.ustuck != mtmp) 393 1.4 christos return (1); 394 1.1 cgd appr = 1; 395 1.4 christos if (mtmp->mflee) 396 1.4 christos appr = -1; 397 1.4 christos if (mtmp->mconf || Invis || !mtmp->mcansee || 398 1.4 christos (strchr("BIy", msym) && !rn2(3))) 399 1.1 cgd appr = 0; 400 1.1 cgd omx = mtmp->mx; 401 1.1 cgd omy = mtmp->my; 402 1.1 cgd gx = u.ux; 403 1.1 cgd gy = u.uy; 404 1.4 christos if (msym == 'L' && appr == 1 && mtmp->mgold > u.ugold) 405 1.1 cgd appr = -1; 406 1.1 cgd 407 1.4 christos /* 408 1.4 christos * random criterion for 'smell' or track finding ability should use 409 1.4 christos * mtmp->msmell or sth 410 1.1 cgd */ 411 1.4 christos if (msym == '@' || 412 1.4 christos ('a' <= msym && msym <= 'z')) { 413 1.4 christos coord *cp; 414 1.4 christos schar mroom; 415 1.4 christos mroom = inroom(omx, omy); 416 1.4 christos if (mroom < 0 || mroom != inroom(u.ux, u.uy)) { 417 1.4 christos cp = gettrack(omx, omy); 418 1.4 christos if (cp) { 419 1.4 christos gx = cp->x; 420 1.4 christos gy = cp->y; 421 1.4 christos } 422 1.1 cgd } 423 1.1 cgd } 424 1.1 cgd /* look for gold or jewels nearby */ 425 1.4 christos likegold = (strchr("LOD", msym) != NULL); 426 1.4 christos likegems = (strchr("ODu", msym) != NULL); 427 1.1 cgd likeobjs = mtmp->mhide; 428 1.1 cgd #define SRCHRADIUS 25 429 1.4 christos { 430 1.4 christos xchar mind = SRCHRADIUS; /* not too far away */ 431 1.4 christos int dd; 432 1.4 christos if (likegold) { 433 1.4 christos struct gold *gold; 434 1.4 christos for (gold = fgold; gold; gold = gold->ngold) 435 1.4 christos if ((dd = DIST(omx, omy, gold->gx, gold->gy)) < mind) { 436 1.4 christos mind = dd; 437 1.4 christos gx = gold->gx; 438 1.4 christos gy = gold->gy; 439 1.4 christos } 440 1.4 christos } 441 1.4 christos if (likegems || likeobjs) { 442 1.4 christos struct obj *otmp; 443 1.4 christos for (otmp = fobj; otmp; otmp = otmp->nobj) 444 1.4 christos if (likeobjs || otmp->olet == GEM_SYM) 445 1.4 christos if (msym != 'u' || 446 1.4 christos objects[otmp->otyp].g_val != 0) 447 1.4 christos if ((dd = DIST(omx, omy, otmp->ox, otmp->oy)) < mind) { 448 1.4 christos mind = dd; 449 1.4 christos gx = otmp->ox; 450 1.4 christos gy = otmp->oy; 451 1.4 christos } 452 1.4 christos } 453 1.4 christos if (mind < SRCHRADIUS && appr == -1) { 454 1.4 christos if (dist(omx, omy) < 10) { 455 1.4 christos gx = u.ux; 456 1.4 christos gy = u.uy; 457 1.4 christos } else 458 1.4 christos appr = 1; 459 1.4 christos } 460 1.1 cgd } 461 1.1 cgd nix = omx; 462 1.1 cgd niy = omy; 463 1.4 christos cnt = mfndpos(mtmp, poss, info, 464 1.4 christos msym == 'u' ? NOTONL : 465 1.4 christos (msym == '@' || msym == '1') ? (ALLOW_SSM | ALLOW_TRAPS) : 466 1.4 christos strchr(UNDEAD, msym) ? NOGARLIC : ALLOW_TRAPS); 467 1.4 christos /* ALLOW_ROCK for some monsters ? */ 468 1.1 cgd chcnt = 0; 469 1.1 cgd chi = -1; 470 1.4 christos for (i = 0; i < cnt; i++) { 471 1.1 cgd nx = poss[i].x; 472 1.1 cgd ny = poss[i].y; 473 1.4 christos for (j = 0; j < MTSZ && j < cnt - 1; j++) 474 1.4 christos if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) 475 1.4 christos if (rn2(4 * (cnt - j))) 476 1.4 christos goto nxti; 477 1.1 cgd #ifdef STUPID 478 1.1 cgd /* some stupid compilers think that this is too complicated */ 479 1.4 christos { 480 1.4 christos int d1 = DIST(nx, ny, gx, gy); 481 1.4 christos int d2 = DIST(nix, niy, gx, gy); 482 1.4 christos nearer = (d1 < d2); 483 1.1 cgd } 484 1.1 cgd #else 485 1.4 christos nearer = (DIST(nx, ny, gx, gy) < DIST(nix, niy, gx, gy)); 486 1.4 christos #endif /* STUPID */ 487 1.4 christos if ((appr == 1 && nearer) || (appr == -1 && !nearer) || 488 1.4 christos !mmoved || 489 1.4 christos (!appr && !rn2(++chcnt))) { 490 1.1 cgd nix = nx; 491 1.1 cgd niy = ny; 492 1.1 cgd chi = i; 493 1.1 cgd mmoved = 1; 494 1.1 cgd } 495 1.4 christos nxti: ; 496 1.1 cgd } 497 1.4 christos if (mmoved) { 498 1.4 christos if (info[chi] & ALLOW_M) { 499 1.4 christos mtmp2 = m_at(nix, niy); 500 1.7 jnemeth if (mtmp2 == NULL) 501 1.7 jnemeth panic("error in m_move"); 502 1.4 christos if (hitmm(mtmp, mtmp2) == 1 && rn2(4) && 503 1.4 christos hitmm(mtmp2, mtmp) == 2) 504 1.4 christos return (2); 505 1.4 christos return (0); 506 1.4 christos } 507 1.4 christos if (info[chi] & ALLOW_U) { 508 1.4 christos (void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd) + 1); 509 1.4 christos return (0); 510 1.1 cgd } 511 1.1 cgd mtmp->mx = nix; 512 1.1 cgd mtmp->my = niy; 513 1.4 christos for (j = MTSZ - 1; j > 0; j--) 514 1.4 christos mtmp->mtrack[j] = mtmp->mtrack[j - 1]; 515 1.1 cgd mtmp->mtrack[0].x = omx; 516 1.1 cgd mtmp->mtrack[0].y = omy; 517 1.1 cgd #ifndef NOWORM 518 1.4 christos if (mtmp->wormno) 519 1.4 christos worm_move(mtmp); 520 1.4 christos #endif /* NOWORM */ 521 1.1 cgd } else { 522 1.4 christos if (msym == 'u' && rn2(2)) { 523 1.1 cgd rloc(mtmp); 524 1.4 christos return (0); 525 1.1 cgd } 526 1.1 cgd #ifndef NOWORM 527 1.4 christos if (mtmp->wormno) 528 1.4 christos worm_nomove(mtmp); 529 1.4 christos #endif /* NOWORM */ 530 1.1 cgd } 531 1.1 cgd postmov: 532 1.4 christos if (mmoved == 1) { 533 1.4 christos if (mintrap(mtmp) == 2) /* he died */ 534 1.4 christos return (2); 535 1.4 christos if (likegold) 536 1.4 christos mpickgold(mtmp); 537 1.4 christos if (likegems) 538 1.4 christos mpickgems(mtmp); 539 1.4 christos if (mtmp->mhide) 540 1.4 christos mtmp->mundetected = 1; 541 1.1 cgd } 542 1.1 cgd pmon(mtmp); 543 1.4 christos return (mmoved); 544 1.1 cgd } 545 1.1 cgd 546 1.10 dholland static void 547 1.9 dholland mpickgold(struct monst *mtmp) 548 1.4 christos { 549 1.4 christos struct gold *gold; 550 1.4 christos while ((gold = g_at(mtmp->mx, mtmp->my)) != NULL) { 551 1.1 cgd mtmp->mgold += gold->amount; 552 1.1 cgd freegold(gold); 553 1.4 christos if (levl[mtmp->mx][mtmp->my].scrsym == '$') 554 1.1 cgd newsym(mtmp->mx, mtmp->my); 555 1.1 cgd } 556 1.1 cgd } 557 1.1 cgd 558 1.10 dholland static void 559 1.9 dholland mpickgems(struct monst *mtmp) 560 1.4 christos { 561 1.4 christos struct obj *otmp; 562 1.4 christos for (otmp = fobj; otmp; otmp = otmp->nobj) 563 1.4 christos if (otmp->olet == GEM_SYM) 564 1.4 christos if (otmp->ox == mtmp->mx && otmp->oy == mtmp->my) 565 1.4 christos if (mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0) { 566 1.4 christos freeobj(otmp); 567 1.4 christos mpickobj(mtmp, otmp); 568 1.4 christos if (levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM) 569 1.4 christos newsym(mtmp->mx, mtmp->my); /* %% */ 570 1.4 christos return; /* pick only one object */ 571 1.4 christos } 572 1.1 cgd } 573 1.1 cgd 574 1.1 cgd /* return number of acceptable neighbour positions */ 575 1.4 christos int 576 1.9 dholland mfndpos(struct monst *mon, coord poss[9], int info[9], int flag) 577 1.4 christos { 578 1.4 christos int x, y, nx, ny, cnt = 0, ntyp; 579 1.4 christos struct monst *mtmp; 580 1.4 christos int nowtyp; 581 1.4 christos boolean pool; 582 1.1 cgd 583 1.1 cgd x = mon->mx; 584 1.1 cgd y = mon->my; 585 1.1 cgd nowtyp = levl[x][y].typ; 586 1.1 cgd 587 1.1 cgd pool = (mon->data->mlet == ';'); 588 1.4 christos nexttry: /* eels prefer the water, but if there is no 589 1.4 christos * water nearby, they will crawl over land */ 590 1.4 christos if (mon->mconf) { 591 1.1 cgd flag |= ALLOW_ALL; 592 1.1 cgd flag &= ~NOTONL; 593 1.1 cgd } 594 1.4 christos for (nx = x - 1; nx <= x + 1; nx++) 595 1.4 christos for (ny = y - 1; ny <= y + 1; ny++) 596 1.4 christos if (nx != x || ny != y) 597 1.4 christos if (isok(nx, ny)) 598 1.4 christos if (!IS_ROCK(ntyp = levl[nx][ny].typ)) 599 1.4 christos if (!(nx != x && ny != y && (nowtyp == DOOR || ntyp == DOOR))) 600 1.4 christos if ((ntyp == POOL) == pool) { 601 1.4 christos info[cnt] = 0; 602 1.4 christos if (nx == u.ux && ny == u.uy) { 603 1.4 christos if (!(flag & ALLOW_U)) 604 1.4 christos continue; 605 1.4 christos info[cnt] = ALLOW_U; 606 1.4 christos } else if ((mtmp = m_at(nx, ny)) != NULL) { 607 1.4 christos if (!(flag & ALLOW_M)) 608 1.4 christos continue; 609 1.4 christos info[cnt] = ALLOW_M; 610 1.4 christos if (mtmp->mtame) { 611 1.4 christos if (!(flag & ALLOW_TM)) 612 1.4 christos continue; 613 1.4 christos info[cnt] |= ALLOW_TM; 614 1.4 christos } 615 1.4 christos } 616 1.4 christos if (sobj_at(CLOVE_OF_GARLIC, nx, ny)) { 617 1.4 christos if (flag & NOGARLIC) 618 1.4 christos continue; 619 1.4 christos info[cnt] |= NOGARLIC; 620 1.4 christos } 621 1.4 christos if (sobj_at(SCR_SCARE_MONSTER, nx, ny) || 622 1.4 christos (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) { 623 1.4 christos if (!(flag & ALLOW_SSM)) 624 1.4 christos continue; 625 1.4 christos info[cnt] |= ALLOW_SSM; 626 1.4 christos } 627 1.4 christos if (sobj_at(ENORMOUS_ROCK, nx, ny)) { 628 1.4 christos if (!(flag & ALLOW_ROCK)) 629 1.4 christos continue; 630 1.4 christos info[cnt] |= ALLOW_ROCK; 631 1.4 christos } 632 1.4 christos if (!Invis && online(nx, ny)) { 633 1.4 christos if (flag & NOTONL) 634 1.4 christos continue; 635 1.4 christos info[cnt] |= NOTONL; 636 1.4 christos } 637 1.4 christos /* 638 1.4 christos * we cannot 639 1.4 christos * avoid 640 1.4 christos * traps of 641 1.4 christos * an unknown 642 1.4 christos * kind 643 1.4 christos */ 644 1.4 christos { 645 1.4 christos struct trap *ttmp = t_at(nx, ny); 646 1.4 christos int tt; 647 1.4 christos if (ttmp) { 648 1.4 christos tt = 1 << ttmp->ttyp; 649 1.4 christos if (mon->mtrapseen & tt) { 650 1.4 christos if (!(flag & tt)) 651 1.4 christos continue; 652 1.4 christos info[cnt] |= tt; 653 1.4 christos } 654 1.4 christos } 655 1.4 christos } 656 1.4 christos poss[cnt].x = nx; 657 1.4 christos poss[cnt].y = ny; 658 1.4 christos cnt++; 659 1.4 christos } 660 1.4 christos if (!cnt && pool && nowtyp != POOL) { 661 1.1 cgd pool = FALSE; 662 1.1 cgd goto nexttry; 663 1.1 cgd } 664 1.4 christos return (cnt); 665 1.1 cgd } 666 1.1 cgd 667 1.4 christos int 668 1.9 dholland dist(int x, int y) 669 1.4 christos { 670 1.4 christos return ((x - u.ux) * (x - u.ux) + (y - u.uy) * (y - u.uy)); 671 1.1 cgd } 672 1.1 cgd 673 1.4 christos void 674 1.9 dholland poisoned(const char *string, const char *pname) 675 1.1 cgd { 676 1.4 christos int i; 677 1.1 cgd 678 1.4 christos if (Blind) 679 1.4 christos pline("It was poisoned."); 680 1.4 christos else 681 1.4 christos pline("The %s was poisoned!", string); 682 1.4 christos if (Poison_resistance) { 683 1.1 cgd pline("The poison doesn't seem to affect you."); 684 1.1 cgd return; 685 1.1 cgd } 686 1.1 cgd i = rn2(10); 687 1.4 christos if (i == 0) { 688 1.1 cgd u.uhp = -1; 689 1.1 cgd pline("I am afraid the poison was deadly ..."); 690 1.4 christos } else if (i <= 5) { 691 1.4 christos losestr(rn1(3, 3)); 692 1.1 cgd } else { 693 1.4 christos losehp(rn1(10, 6), pname); 694 1.1 cgd } 695 1.4 christos if (u.uhp < 1) { 696 1.1 cgd killer = pname; 697 1.1 cgd done("died"); 698 1.1 cgd } 699 1.1 cgd } 700 1.1 cgd 701 1.4 christos void 702 1.9 dholland mondead(struct monst *mtmp) 703 1.1 cgd { 704 1.4 christos relobj(mtmp, 1); 705 1.1 cgd unpmon(mtmp); 706 1.1 cgd relmon(mtmp); 707 1.1 cgd unstuck(mtmp); 708 1.4 christos if (mtmp->isshk) 709 1.4 christos shkdead(mtmp); 710 1.4 christos if (mtmp->isgd) 711 1.4 christos gddead(); 712 1.1 cgd #ifndef NOWORM 713 1.4 christos if (mtmp->wormno) 714 1.4 christos wormdead(mtmp); 715 1.4 christos #endif /* NOWORM */ 716 1.1 cgd monfree(mtmp); 717 1.1 cgd } 718 1.1 cgd 719 1.1 cgd /* called when monster is moved to larger structure */ 720 1.4 christos void 721 1.9 dholland replmon(struct monst *mtmp, struct monst *mtmp2) 722 1.1 cgd { 723 1.1 cgd relmon(mtmp); 724 1.1 cgd monfree(mtmp); 725 1.1 cgd mtmp2->nmon = fmon; 726 1.1 cgd fmon = mtmp2; 727 1.4 christos if (u.ustuck == mtmp) 728 1.4 christos u.ustuck = mtmp2; 729 1.4 christos if (mtmp2->isshk) 730 1.4 christos replshk(mtmp, mtmp2); 731 1.4 christos if (mtmp2->isgd) 732 1.4 christos replgd(mtmp, mtmp2); 733 1.1 cgd } 734 1.1 cgd 735 1.4 christos void 736 1.9 dholland relmon(struct monst *mon) 737 1.1 cgd { 738 1.4 christos struct monst *mtmp; 739 1.1 cgd 740 1.4 christos if (mon == fmon) 741 1.4 christos fmon = fmon->nmon; 742 1.1 cgd else { 743 1.4 christos for (mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon); 744 1.1 cgd mtmp->nmon = mon->nmon; 745 1.1 cgd } 746 1.1 cgd } 747 1.1 cgd 748 1.4 christos /* 749 1.4 christos * we do not free monsters immediately, in order to have their name available 750 1.4 christos * shortly after their demise 751 1.4 christos */ 752 1.10 dholland static struct monst *fdmon; /* chain of dead monsters, need not to be 753 1.4 christos * saved */ 754 1.1 cgd 755 1.4 christos void 756 1.9 dholland monfree(struct monst *mtmp) 757 1.4 christos { 758 1.1 cgd mtmp->nmon = fdmon; 759 1.1 cgd fdmon = mtmp; 760 1.1 cgd } 761 1.1 cgd 762 1.10 dholland static void 763 1.9 dholland dmonsfree(void) 764 1.4 christos { 765 1.4 christos struct monst *mtmp; 766 1.4 christos while ((mtmp = fdmon) != NULL) { 767 1.1 cgd fdmon = mtmp->nmon; 768 1.13 dholland free(mtmp); 769 1.1 cgd } 770 1.1 cgd } 771 1.1 cgd 772 1.4 christos void 773 1.9 dholland unstuck(struct monst *mtmp) 774 1.1 cgd { 775 1.4 christos if (u.ustuck == mtmp) { 776 1.4 christos if (u.uswallow) { 777 1.1 cgd u.ux = mtmp->mx; 778 1.1 cgd u.uy = mtmp->my; 779 1.1 cgd u.uswallow = 0; 780 1.1 cgd setsee(); 781 1.1 cgd docrt(); 782 1.1 cgd } 783 1.1 cgd u.ustuck = 0; 784 1.1 cgd } 785 1.1 cgd } 786 1.1 cgd 787 1.4 christos void 788 1.9 dholland killed(struct monst *mtmp) 789 1.1 cgd { 790 1.1 cgd #ifdef lint 791 1.1 cgd #define NEW_SCORING 792 1.4 christos #endif /* lint */ 793 1.4 christos int tmp, nk, x, y; 794 1.5 jsm const struct permonst *mdat; 795 1.1 cgd 796 1.4 christos if (mtmp->cham) 797 1.4 christos mtmp->data = PM_CHAMELEON; 798 1.1 cgd mdat = mtmp->data; 799 1.4 christos if (Blind) 800 1.4 christos pline("You destroy it!"); 801 1.1 cgd else { 802 1.1 cgd pline("You destroy %s!", 803 1.4 christos mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp)); 804 1.1 cgd } 805 1.4 christos if (u.umconf) { 806 1.4 christos if (!Blind) 807 1.4 christos pline("Your hands stop glowing blue."); 808 1.1 cgd u.umconf = 0; 809 1.1 cgd } 810 1.1 cgd /* count killed monsters */ 811 1.1 cgd #define MAXMONNO 100 812 1.4 christos nk = 1; /* in case we cannot find it in mons */ 813 1.4 christos tmp = mdat - mons; /* strchr in mons array (if not 'd', '@', ...) */ 814 1.4 christos if (tmp >= 0 && tmp < CMNUM + 2) { 815 1.4 christos u.nr_killed[tmp]++; 816 1.4 christos if ((nk = u.nr_killed[tmp]) > MAXMONNO && 817 1.4 christos !strchr(fut_geno, mdat->mlet)) 818 1.4 christos charcat(fut_geno, mdat->mlet); 819 1.1 cgd } 820 1.1 cgd /* punish bad behaviour */ 821 1.4 christos if (mdat->mlet == '@') 822 1.4 christos Telepat = 0, u.uluck -= 2; 823 1.4 christos if (mtmp->mpeaceful || mtmp->mtame) 824 1.4 christos u.uluck--; 825 1.4 christos if (mdat->mlet == 'u') 826 1.4 christos u.uluck -= 5; 827 1.4 christos if ((int) u.uluck < LUCKMIN) 828 1.4 christos u.uluck = LUCKMIN; 829 1.1 cgd 830 1.1 cgd /* give experience points */ 831 1.1 cgd tmp = 1 + mdat->mlevel * mdat->mlevel; 832 1.4 christos if (mdat->ac < 3) 833 1.4 christos tmp += 2 * (7 - mdat->ac); 834 1.4 christos if (strchr("AcsSDXaeRTVWU&In:P", mdat->mlet)) 835 1.4 christos tmp += 2 * mdat->mlevel; 836 1.4 christos if (strchr("DeV&P", mdat->mlet)) 837 1.4 christos tmp += (7 * mdat->mlevel); 838 1.4 christos if (mdat->mlevel > 6) 839 1.4 christos tmp += 50; 840 1.4 christos if (mdat->mlet == ';') 841 1.4 christos tmp += 1000; 842 1.1 cgd 843 1.1 cgd #ifdef NEW_SCORING 844 1.4 christos /* 845 1.4 christos * ------- recent addition: make nr of points decrease when this is 846 1.4 christos * not the first of this kind 847 1.4 christos */ 848 1.4 christos { 849 1.4 christos int ul = u.ulevel; 850 1.4 christos int ml = mdat->mlevel; 851 1.14 dholland int tmp2; 852 1.4 christos 853 1.4 christos if (ul < 14) /* points are given based on present and 854 1.4 christos * future level */ 855 1.4 christos for (tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++) 856 1.4 christos if (u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4 << (tmp2 - 1))) / nk 857 1.4 christos >= 10 * pow((unsigned) (ul - 1))) 858 1.4 christos if (++ul == 14) 859 1.4 christos break; 860 1.4 christos 861 1.4 christos tmp2 = ml - ul - 1; 862 1.4 christos tmp = (tmp + ((tmp2 < 0) ? 0 : 4 << tmp2)) / nk; 863 1.4 christos if (!tmp) 864 1.4 christos tmp = 1; 865 1.1 cgd } 866 1.1 cgd /* note: ul is not necessarily the future value of u.ulevel */ 867 1.1 cgd /* ------- end of recent valuation change ------- */ 868 1.4 christos #endif /* NEW_SCORING */ 869 1.1 cgd 870 1.4 christos more_experienced(tmp, 0); 871 1.1 cgd flags.botl = 1; 872 1.4 christos while (u.ulevel < 14 && u.uexp >= newuexp()) { 873 1.1 cgd pline("Welcome to experience level %u.", ++u.ulevel); 874 1.1 cgd tmp = rnd(10); 875 1.4 christos if (tmp < 3) 876 1.4 christos tmp = rnd(10); 877 1.1 cgd u.uhpmax += tmp; 878 1.1 cgd u.uhp += tmp; 879 1.1 cgd flags.botl = 1; 880 1.1 cgd } 881 1.1 cgd 882 1.1 cgd /* dispose of monster and make cadaver */ 883 1.4 christos x = mtmp->mx; 884 1.4 christos y = mtmp->my; 885 1.1 cgd mondead(mtmp); 886 1.1 cgd tmp = mdat->mlet; 887 1.4 christos if (tmp == 'm') { /* he killed a minotaur, give him a wand of 888 1.4 christos * digging */ 889 1.4 christos /* note: the dead minotaur will be on top of it! */ 890 1.1 cgd mksobj_at(WAN_DIGGING, x, y); 891 1.1 cgd /* if(cansee(x,y)) atl(x,y,fobj->olet); */ 892 1.1 cgd stackobj(fobj); 893 1.1 cgd } else 894 1.1 cgd #ifndef NOWORM 895 1.4 christos if (tmp == 'w') { 896 1.1 cgd mksobj_at(WORM_TOOTH, x, y); 897 1.1 cgd stackobj(fobj); 898 1.1 cgd } else 899 1.4 christos #endif /* NOWORM */ 900 1.4 christos if (!letter(tmp) || (!strchr("mw", tmp) && !rn2(3))) 901 1.4 christos tmp = 0; 902 1.4 christos 903 1.4 christos if (ACCESSIBLE(levl[x][y].typ)) /* might be mimic in wall or dead eel */ 904 1.4 christos if (x != u.ux || y != u.uy) /* might be here after 905 1.4 christos * swallowed */ 906 1.4 christos if (strchr("NTVm&", mdat->mlet) || rn2(5)) { 907 1.4 christos struct obj *obj2 = mkobj_at(tmp, x, y); 908 1.4 christos if (cansee(x, y)) 909 1.4 christos atl(x, y, obj2->olet); 910 1.4 christos stackobj(obj2); 911 1.4 christos } 912 1.1 cgd } 913 1.1 cgd 914 1.4 christos void 915 1.5 jsm kludge(const char *str, const char *arg) 916 1.4 christos { 917 1.4 christos if (Blind) { 918 1.4 christos if (*str == '%') 919 1.4 christos pline(str, "It"); 920 1.4 christos else 921 1.4 christos pline(str, "it"); 922 1.4 christos } else 923 1.4 christos pline(str, arg); 924 1.1 cgd } 925 1.1 cgd 926 1.4 christos void 927 1.9 dholland rescham(void) 928 1.4 christos { /* force all chameleons to become normal */ 929 1.4 christos struct monst *mtmp; 930 1.1 cgd 931 1.4 christos for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) 932 1.4 christos if (mtmp->cham) { 933 1.1 cgd mtmp->cham = 0; 934 1.1 cgd (void) newcham(mtmp, PM_CHAMELEON); 935 1.1 cgd } 936 1.1 cgd } 937 1.1 cgd 938 1.9 dholland /* make a chameleon look like a new monster */ 939 1.9 dholland /* returns 1 if the monster actually changed */ 940 1.4 christos int 941 1.9 dholland newcham(struct monst *mtmp, const struct permonst *mdat) 942 1.1 cgd { 943 1.4 christos int mhp, hpn, hpd; 944 1.1 cgd 945 1.4 christos if (mdat == mtmp->data) 946 1.4 christos return (0); /* still the same monster */ 947 1.1 cgd #ifndef NOWORM 948 1.4 christos if (mtmp->wormno) 949 1.4 christos wormdead(mtmp); /* throw tail away */ 950 1.4 christos #endif /* NOWORM */ 951 1.1 cgd if (u.ustuck == mtmp) { 952 1.1 cgd if (u.uswallow) { 953 1.1 cgd u.uswallow = 0; 954 1.1 cgd u.uswldtim = 0; 955 1.4 christos mnexto(mtmp); 956 1.4 christos docrt(); 957 1.4 christos prme(); 958 1.1 cgd } 959 1.1 cgd u.ustuck = 0; 960 1.1 cgd } 961 1.1 cgd hpn = mtmp->mhp; 962 1.4 christos hpd = (mtmp->data->mlevel) * 8; 963 1.4 christos if (!hpd) 964 1.4 christos hpd = 4; 965 1.1 cgd mtmp->data = mdat; 966 1.4 christos mhp = (mdat->mlevel) * 8; 967 1.1 cgd /* new hp: same fraction of max as before */ 968 1.4 christos mtmp->mhp = 2 + (hpn * mhp) / hpd; 969 1.1 cgd hpn = mtmp->mhpmax; 970 1.4 christos mtmp->mhpmax = 2 + (hpn * mhp) / hpd; 971 1.1 cgd mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0; 972 1.1 cgd #ifndef NOWORM 973 1.4 christos if (mdat->mlet == 'w' && getwn(mtmp)) 974 1.4 christos initworm(mtmp); 975 1.4 christos /* perhaps we should clear mtmp->mtame here? */ 976 1.4 christos #endif /* NOWORM */ 977 1.4 christos unpmon(mtmp); /* necessary for 'I' and to force pmon */ 978 1.1 cgd pmon(mtmp); 979 1.4 christos return (1); 980 1.1 cgd } 981 1.1 cgd 982 1.9 dholland /* Make monster mtmp next to you (if possible) */ 983 1.4 christos void 984 1.9 dholland mnexto(struct monst *mtmp) 985 1.1 cgd { 986 1.4 christos coord mm; 987 1.1 cgd mm = enexto(u.ux, u.uy); 988 1.1 cgd mtmp->mx = mm.x; 989 1.1 cgd mtmp->my = mm.y; 990 1.1 cgd pmon(mtmp); 991 1.1 cgd } 992 1.1 cgd 993 1.10 dholland static int 994 1.9 dholland ishuman(struct monst *mtmp) 995 1.4 christos { 996 1.4 christos return (mtmp->data->mlet == '@'); 997 1.1 cgd } 998 1.1 cgd 999 1.4 christos void 1000 1.9 dholland setmangry(struct monst *mtmp) 1001 1.4 christos { 1002 1.4 christos if (!mtmp->mpeaceful) 1003 1.4 christos return; 1004 1.4 christos if (mtmp->mtame) 1005 1.4 christos return; 1006 1.1 cgd mtmp->mpeaceful = 0; 1007 1.4 christos if (ishuman(mtmp)) 1008 1.4 christos pline("%s gets angry!", Monnam(mtmp)); 1009 1.1 cgd } 1010 1.1 cgd 1011 1.4 christos /* 1012 1.4 christos * not one hundred procent correct: now a snake may hide under an invisible 1013 1.4 christos * object 1014 1.4 christos */ 1015 1.4 christos int 1016 1.9 dholland canseemon(struct monst *mtmp) 1017 1.1 cgd { 1018 1.4 christos return ((!mtmp->minvis || See_invisible) 1019 1.4 christos && (!mtmp->mhide || !o_at(mtmp->mx, mtmp->my)) 1020 1.1 cgd && cansee(mtmp->mx, mtmp->my)); 1021 1.1 cgd } 1022