Below is the full text to src/dogmove.c from NetHack 3.4.3. To link to a particular line, write [[dogmove.c#line123]], for example.
Top of file[]
1. /* SCCS Id: @(#)dogmove.c 3.4 2002/09/10 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4.
| The NetHack General Public License applies to screenshots, source code and other content from NetHack. |
5. #include "hack.h" 6. 7. #include "mfndpos.h" 8. #include "edog.h" 9. 10. extern boolean notonhead; 11. 12. #ifdef OVL0 13. 14. STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *)); 15. STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int)); 16. STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); 17. 18. STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *)); 19. STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P, 20. XCHAR_P,XCHAR_P)); 21. STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P)); 22.
DROPPABLES[]
23. STATIC_OVL struct obj * 24. DROPPABLES(mon) 25. register struct monst *mon; 26. { 27. register struct obj *obj; 28. struct obj *wep = MON_WEP(mon); 29. boolean item1 = FALSE, item2 = FALSE; 30. 31. if (is_animal(mon->data) || mindless(mon->data)) 32. item1 = item2 = TRUE; 33. if (!tunnels(mon->data) || !needspick(mon->data)) 34. item1 = TRUE; 35. for(obj = mon->minvent; obj; obj = obj->nobj) { 36. if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK 37. || !which_armor(mon, W_ARMS))) { 38. item1 = TRUE; 39. continue; 40. } 41. if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) { 42. item2 = TRUE; 43. continue; 44. } 45. if (!obj->owornmask && obj != wep) return obj; 46. } 47. return (struct obj *)0; 48. } 49. 50. static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; 51. 52. #endif /* OVL0 */ 53. 54. STATIC_OVL boolean FDECL(cursed_object_at, (int, int)); 55. 56. STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */ 57. 58. STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); 59.
cursed_object_at[]
60. #ifdef OVLB 61. STATIC_OVL boolean 62. cursed_object_at(x, y) 63. int x, y; 64. { 65. struct obj *otmp; 66. 67. for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 68. if (otmp->cursed) return TRUE; 69. return FALSE; 70. } 71.
dog_nutrition[]
72. int 73. dog_nutrition(mtmp, obj) 74. struct monst *mtmp; 75. struct obj *obj; 76. { 77. int nutrit; 78. 79. /* 80. * It is arbitrary that the pet takes the same length of time to eat 81. * as a human, but gets more nutritional value. 82. */ 83. if (obj->oclass == FOOD_CLASS) { 84. if(obj->otyp == CORPSE) { 85. mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); 86. nutrit = mons[obj->corpsenm].cnutrit; 87. } else { 88. mtmp->meating = objects[obj->otyp].oc_delay; 89. nutrit = objects[obj->otyp].oc_nutrition; 90. } 91. switch(mtmp->data->msize) { 92. case MZ_TINY: nutrit *= 8; break; 93. case MZ_SMALL: nutrit *= 6; break; 94. default: 95. case MZ_MEDIUM: nutrit *= 5; break; 96. case MZ_LARGE: nutrit *= 4; break; 97. case MZ_HUGE: nutrit *= 3; break; 98. case MZ_GIGANTIC: nutrit *= 2; break; 99. } 100. if(obj->oeaten) { 101. mtmp->meating = eaten_stat(mtmp->meating, obj); 102. nutrit = eaten_stat(nutrit, obj); 103. } 104. } else if (obj->oclass == COIN_CLASS) { 105. mtmp->meating = (int)(obj->quan/2000) + 1; 106. if (mtmp->meating < 0) mtmp->meating = 1; 107. nutrit = (int)(obj->quan/20); 108. if (nutrit < 0) nutrit = 0; 109. } else { 110. /* Unusual pet such as gelatinous cube eating odd stuff. 111. * meating made consistent with wild monsters in mon.c. 112. * nutrit made consistent with polymorphed player nutrit in 113. * eat.c. (This also applies to pets eating gold.) 114. */ 115. mtmp->meating = obj->owt/20 + 1; 116. nutrit = 5*objects[obj->otyp].oc_nutrition; 117. } 118. return nutrit; 119. } 120.
dog_eat[]
121. /* returns 2 if pet dies, otherwise 1 */ 122. int 123. dog_eat(mtmp, obj, x, y, devour) 124. register struct monst *mtmp; 125. register struct obj * obj; 126. int x, y; 127. boolean devour; 128. { 129. register struct edog *edog = EDOG(mtmp); 130. boolean poly = FALSE, grow = FALSE, heal = FALSE; 131. int nutrit; 132. 133. if(edog->hungrytime < monstermoves) 134. edog->hungrytime = monstermoves; 135. nutrit = dog_nutrition(mtmp, obj); 136. poly = polyfodder(obj); 137. grow = mlevelgain(obj); 138. heal = mhealup(obj); 139. if (devour) { 140. if (mtmp->meating > 1) mtmp->meating /= 2; 141. if (nutrit > 1) nutrit = (nutrit * 3) / 4; 142. } 143. edog->hungrytime += nutrit; 144. mtmp->mconf = 0; 145. if (edog->mhpmax_penalty) { 146. /* no longer starving */ 147. mtmp->mhpmax += edog->mhpmax_penalty; 148. edog->mhpmax_penalty = 0; 149. } 150. if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; 151. if (mtmp->mtame < 20) mtmp->mtame++; 152. if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */ 153. newsym(x, y); 154. newsym(mtmp->mx, mtmp->my); 155. } 156. if (is_pool(x, y) && !Underwater) { 157. /* Don't print obj */ 158. /* TODO: Reveal presence of sea monster (especially sharks) */ 159. } else 160. /* hack: observe the action if either new or old location is in view */ 161. /* However, invisible monsters should still be "it" even though out of 162. sight locations should not. */ 163. if (cansee(x, y) || cansee(mtmp->mx, mtmp->my)) 164. pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It", 165. devour ? "devours" : "eats", 166. (obj->oclass == FOOD_CLASS) ? 167. singular(obj, doname) : doname(obj)); 168. /* It's a reward if it's DOGFOOD and the player dropped/threw it. */ 169. /* We know the player had it if invlet is set -dlc */ 170. if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet) 171. #ifdef LINT 172. edog->apport = 0; 173. #else 174. edog->apport += (int)(200L/ 175. ((long)edog->dropdist + monstermoves - edog->droptime)); 176. #endif 177. if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { 178. /* The object's rustproofing is gone now */ 179. obj->oerodeproof = 0; 180. mtmp->mstun = 1; 181. if (canseemon(mtmp) && flags.verbose) { 182. pline("%s spits %s out in disgust!", 183. Monnam(mtmp), distant_name(obj,doname)); 184. } 185. } else if (obj == uball) { 186. unpunish(); 187. delobj(obj); 188. } else if (obj == uchain) 189. unpunish(); 190. else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) { 191. obj->quan--; 192. obj->owt = weight(obj); 193. } else 194. delobj(obj); 195. 196. if (poly) { 197. (void) newcham(mtmp, (struct permonst *)0, FALSE, 198. cansee(mtmp->mx, mtmp->my)); 199. } 200. /* limit "instant" growth to prevent potential abuse */ 201. if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { 202. if (!grow_up(mtmp, (struct monst *)0)) return 2; 203. } 204. if (heal) mtmp->mhp = mtmp->mhpmax; 205. return 1; 206. } 207. 208. #endif /* OVLB */
dog_hunger[]
209. #ifdef OVL0 210. 211. /* hunger effects -- returns TRUE on starvation */ 212. STATIC_OVL boolean 213. dog_hunger(mtmp, edog) 214. register struct monst *mtmp; 215. register struct edog *edog; 216. { 217. if (monstermoves > edog->hungrytime + 500) { 218. if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { 219. edog->hungrytime = monstermoves + 500; 220. /* but not too high; it might polymorph */ 221. } else if (!edog->mhpmax_penalty) { 222. /* starving pets are limited in healing */ 223. int newmhpmax = mtmp->mhpmax / 3; 224. mtmp->mconf = 1; 225. edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax; 226. mtmp->mhpmax = newmhpmax; 227. if (mtmp->mhp > mtmp->mhpmax) 228. mtmp->mhp = mtmp->mhpmax; 229. if (mtmp->mhp < 1) goto dog_died; 230. if (cansee(mtmp->mx, mtmp->my)) 231. pline("%s is confused from hunger.", Monnam(mtmp)); 232. else if (couldsee(mtmp->mx, mtmp->my)) 233. beg(mtmp); 234. else 235. You_feel("worried about %s.", y_monnam(mtmp)); 236. stop_occupation(); 237. } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { 238. dog_died: 239. if (mtmp->mleashed 240. #ifdef STEED 241. && mtmp != u.usteed 242. #endif 243. ) 244. Your("leash goes slack."); 245. else if (cansee(mtmp->mx, mtmp->my)) 246. pline("%s starves.", Monnam(mtmp)); 247. else 248. You_feel("%s for a moment.", 249. Hallucination ? "bummed" : "sad"); 250. mondied(mtmp); 251. return(TRUE); 252. } 253. } 254. return(FALSE); 255. } 256.
dog_invent[]
257. /* do something with object (drop, pick up, eat) at current position 258. * returns 1 if object eaten (since that counts as dog's move), 2 if died 259. */ 260. STATIC_OVL int 261. dog_invent(mtmp, edog, udist) 262. register struct monst *mtmp; 263. register struct edog *edog; 264. int udist; 265. { 266. register int omx, omy; 267. struct obj *obj; 268. 269. if (mtmp->msleeping || !mtmp->mcanmove) return(0); 270. 271. omx = mtmp->mx; 272. omy = mtmp->my; 273. 274. /* if we are carrying sth then we drop it (perhaps near @) */ 275. /* Note: if apport == 1 then our behaviour is independent of udist */ 276. /* Use udist+1 so steed won't cause divide by zero */ 277. #ifndef GOLDOBJ 278. if(DROPPABLES(mtmp) || mtmp->mgold) { 279. #else 280. if(DROPPABLES(mtmp)) { 281. #endif 282. if (!rn2(udist+1) || !rn2(edog->apport)) 283. if(rn2(10) < edog->apport){ 284. relobj(mtmp, (int)mtmp->minvis, TRUE); 285. if(edog->apport > 1) edog->apport--; 286. edog->dropdist = udist; /* hpscdi!jon */ 287. edog->droptime = monstermoves; 288. } 289. } else { 290. if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass) 291. #ifdef MAIL 292. && obj->otyp != SCR_MAIL 293. #endif 294. ){ 295. int edible = dogfood(mtmp, obj); 296. 297. if ((edible <= CADAVER || 298. /* starving pet is more aggressive about eating */ 299. (edog->mhpmax_penalty && edible == ACCFOOD)) && 300. could_reach_item(mtmp, obj->ox, obj->oy)) 301. return dog_eat(mtmp, obj, omx, omy, FALSE); 302. 303. if(can_carry(mtmp, obj) && !obj->cursed && 304. could_reach_item(mtmp, obj->ox, obj->oy)) { 305. if(rn2(20) < edog->apport+3) { 306. if (rn2(udist) || !rn2(edog->apport)) { 307. if (cansee(omx, omy) && flags.verbose) 308. pline("%s picks up %s.", Monnam(mtmp), 309. distant_name(obj, doname)); 310. obj_extract_self(obj); 311. newsym(omx,omy); 312. (void) mpickobj(mtmp,obj); 313. if (attacktype(mtmp->data, AT_WEAP) && 314. mtmp->weapon_check == NEED_WEAPON) { 315. mtmp->weapon_check = NEED_HTH_WEAPON; 316. (void) mon_wield_item(mtmp); 317. } 318. m_dowear(mtmp, FALSE); 319. } 320. } 321. } 322. } 323. } 324. return 0; 325. } 326.
dog_goal[]
327. /* set dog's goal -- gtyp, gx, gy 328. * returns -1/0/1 (dog's desire to approach player) or -2 (abort move) 329. */ 330. STATIC_OVL int 331. dog_goal(mtmp, edog, after, udist, whappr) 332. register struct monst *mtmp; 333. struct edog *edog; 334. int after, udist, whappr; 335. { 336. register int omx, omy; 337. boolean in_masters_sight, dog_has_minvent; 338. register struct obj *obj; 339. xchar otyp; 340. int appr; 341. 342. #ifdef STEED 343. /* Steeds don't move on their own will */ 344. if (mtmp == u.usteed) 345. return (-2); 346. #endif 347. 348. omx = mtmp->mx; 349. omy = mtmp->my; 350. 351. in_masters_sight = couldsee(omx, omy); 352. dog_has_minvent = (DROPPABLES(mtmp) != 0); 353. 354. if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ 355. gtyp = APPORT; 356. gx = u.ux; 357. gy = u.uy; 358. } else { 359. #define DDIST(x,y) (dist2(x,y,omx,omy)) 360. #define SQSRCHRADIUS 5 361. int min_x, max_x, min_y, max_y; 362. register int nx, ny; 363. 364. gtyp = UNDEF; /* no goal as yet */ 365. gx = gy = 0; /* suppress 'used before set' message */ 366. 367. if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; 368. if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; 369. if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; 370. if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; 371. 372. /* nearby food is the first choice, then other objects */ 373. for (obj = fobj; obj; obj = obj->nobj) { 374. nx = obj->ox; 375. ny = obj->oy; 376. if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { 377. otyp = dogfood(mtmp, obj); 378. /* skip inferior goals */ 379. if (otyp > gtyp || otyp == UNDEF) 380. continue; 381. /* avoid cursed items unless starving */ 382. if (cursed_object_at(nx, ny) && 383. !(edog->mhpmax_penalty && otyp < MANFOOD)) 384. continue; 385. /* skip completely unreacheable goals */ 386. if (!could_reach_item(mtmp, nx, ny) || 387. !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny)) 388. continue; 389. if (otyp < MANFOOD) { 390. if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) { 391. gx = nx; 392. gy = ny; 393. gtyp = otyp; 394. } 395. } else if(gtyp == UNDEF && in_masters_sight && 396. !dog_has_minvent && 397. (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) && 398. (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) && 399. edog->apport > rn2(8) && 400. can_carry(mtmp,obj)) { 401. gx = nx; 402. gy = ny; 403. gtyp = APPORT; 404. } 405. } 406. } 407. } 408. 409. /* follow player if appropriate */ 410. if (gtyp == UNDEF || 411. (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) { 412. gx = u.ux; 413. gy = u.uy; 414. if (after && udist <= 4 && gx == u.ux && gy == u.uy) 415. return(-2); 416. appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; 417. if (udist > 1) { 418. if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || 419. whappr || 420. (dog_has_minvent && rn2(edog->apport))) 421. appr = 1; 422. } 423. /* if you have dog food it'll follow you more closely */ 424. if (appr == 0) { 425. obj = invent; 426. while (obj) { 427. if(dogfood(mtmp, obj) == DOGFOOD) { 428. appr = 1; 429. break; 430. } 431. obj = obj->nobj; 432. } 433. } 434. } else 435. appr = 1; /* gtyp != UNDEF */ 436. if(mtmp->mconf) 437. appr = 0; 438. 439. #define FARAWAY (COLNO + 2) /* position outside screen */ 440. if (gx == u.ux && gy == u.uy && !in_masters_sight) { 441. register coord *cp; 442. 443. cp = gettrack(omx,omy); 444. if (cp) { 445. gx = cp->x; 446. gy = cp->y; 447. if(edog) edog->ogoal.x = 0; 448. } else { 449. /* assume master hasn't moved far, and reuse previous goal */ 450. if(edog && edog->ogoal.x && 451. ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { 452. gx = edog->ogoal.x; 453. gy = edog->ogoal.y; 454. edog->ogoal.x = 0; 455. } else { 456. int fardist = FARAWAY * FARAWAY; 457. gx = gy = FARAWAY; /* random */ 458. do_clear_area(omx, omy, 9, wantdoor, 459. (genericptr_t)&fardist); 460. 461. /* here gx == FARAWAY e.g. when dog is in a vault */ 462. if (gx == FARAWAY || (gx == omx && gy == omy)) { 463. gx = u.ux; 464. gy = u.uy; 465. } else if(edog) { 466. edog->ogoal.x = gx; 467. edog->ogoal.y = gy; 468. } 469. } 470. } 471. } else if(edog) { 472. edog->ogoal.x = 0; 473. } 474. return appr; 475. } 476.
dog_move[]
477. /* return 0 (no move), 1 (move) or 2 (dead) */ 478. int 479. dog_move(mtmp, after) 480. register struct monst *mtmp; 481. register int after; /* this is extra fast monster movement */ 482. { 483. int omx, omy; /* original mtmp position */ 484. int appr, whappr, udist; 485. int i, j, k; 486. register struct edog *edog = EDOG(mtmp); 487. struct obj *obj = (struct obj *) 0; 488. xchar otyp; 489. boolean has_edog, cursemsg[9], do_eat = FALSE; 490. xchar nix, niy; /* position mtmp is (considering) moving to */ 491. register int nx, ny; /* temporary coordinates */ 492. xchar cnt, uncursedcnt, chcnt; 493. int chi = -1, nidist, ndist; 494. coord poss[9]; 495. long info[9], allowflags; 496. #define GDIST(x,y) (dist2(x,y,gx,gy)) 497. 498. /* 499. * Tame Angels have isminion set and an ispriest structure instead of 500. * an edog structure. Fortunately, guardian Angels need not worry 501. * about mundane things like eating and fetching objects, and can 502. * spend all their energy defending the player. (They are the only 503. * monsters with other structures that can be tame.) 504. */ 505. has_edog = !mtmp->isminion; 506. 507. omx = mtmp->mx; 508. omy = mtmp->my; 509. if (has_edog && dog_hunger(mtmp, edog)) return(2); /* starved */ 510. 511. udist = distu(omx,omy); 512. #ifdef STEED 513. /* Let steeds eat and maybe throw rider during Conflict */ 514. if (mtmp == u.usteed) { 515. if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { 516. dismount_steed(DISMOUNT_THROWN); 517. return (1); 518. } 519. udist = 1; 520. } else 521. #endif 522. /* maybe we tamed him while being swallowed --jgm */ 523. if (!udist) return(0); 524. 525. nix = omx; /* set before newdogpos */ 526. niy = omy; 527. cursemsg[0] = FALSE; /* lint suppression */ 528. info[0] = 0; /* ditto */ 529. 530. if (has_edog) { 531. j = dog_invent(mtmp, edog, udist); 532. if (j == 2) return 2; /* died */ 533. else if (j == 1) goto newdogpos; /* eating something */ 534. 535. whappr = (monstermoves - edog->whistletime < 5); 536. } else 537. whappr = 0; 538. 539. appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0, 540. after, udist, whappr); 541. if (appr == -2) return(0); 542. 543. allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; 544. if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); 545. if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS; 546. if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; 547. if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { 548. allowflags |= ALLOW_U; 549. if (!has_edog) { 550. coord mm; 551. /* Guardian angel refuses to be conflicted; rather, 552. * it disappears, angrily, and sends in some nasties 553. */ 554. if (canspotmon(mtmp)) { 555. pline("%s rebukes you, saying:", Monnam(mtmp)); 556. verbalize("Since you desire conflict, have some more!"); 557. } 558. mongone(mtmp); 559. i = rnd(4); 560. while(i--) { 561. mm.x = u.ux; 562. mm.y = u.uy; 563. if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) 564. (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, 565. mm.x, mm.y, FALSE); 566. } 567. return(2); 568. 569. } 570. } 571. if (!Conflict && !mtmp->mconf && 572. mtmp == u.ustuck && !sticks(youmonst.data)) { 573. unstuck(mtmp); /* swallowed case handled above */ 574. You("get released!"); 575. } 576. if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { 577. allowflags |= OPENDOOR; 578. if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; 579. } 580. if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; 581. if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; 582. cnt = mfndpos(mtmp, poss, info, allowflags); 583. 584. /* Normally dogs don't step on cursed items, but if they have no 585. * other choice they will. This requires checking ahead of time 586. * to see how many uncursed item squares are around. 587. */ 588. uncursedcnt = 0; 589. for (i = 0; i < cnt; i++) { 590. nx = poss[i].x; ny = poss[i].y; 591. if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue; 592. if (cursed_object_at(nx, ny)) continue; 593. uncursedcnt++; 594. } 595. 596. chcnt = 0; 597. chi = -1; 598. nidist = GDIST(nix,niy); 599. 600. for (i = 0; i < cnt; i++) { 601. nx = poss[i].x; 602. ny = poss[i].y; 603. cursemsg[i] = FALSE; 604. 605. /* if leashed, we drag him along. */ 606. if (mtmp->mleashed && distu(nx, ny) > 4) continue; 607. 608. /* if a guardian, try to stay close by choice */ 609. if (!has_edog && 610. (j = distu(nx, ny)) > 16 && j >= udist) continue; 611. 612. if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { 613. int mstatus; 614. register struct monst *mtmp2 = m_at(nx,ny); 615. 616. if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 || 617. (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && 618. mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee 619. && (perceives(mtmp->data) || !mtmp2->minvis)) || 620. (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) || 621. (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || 622. ((mtmp->mhp*4 < mtmp->mhpmax 623. || mtmp2->data->msound == MS_GUARDIAN 624. || mtmp2->data->msound == MS_LEADER) && 625. mtmp2->mpeaceful && !Conflict) || 626. (touch_petrifies(mtmp2->data) && 627. !resists_ston(mtmp))) 628. continue; 629. 630. if (after) return(0); /* hit only once each move */ 631. 632. notonhead = 0; 633. mstatus = mattackm(mtmp, mtmp2); 634. 635. /* aggressor (pet) died */ 636. if (mstatus & MM_AGR_DIED) return 2; 637. 638. if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && 639. rn2(4) && mtmp2->mlstmv != monstermoves && 640. !onscary(mtmp->mx, mtmp->my, mtmp2) && 641. /* monnear check needed: long worms hit on tail */ 642. monnear(mtmp2, mtmp->mx, mtmp->my)) { 643. mstatus = mattackm(mtmp2, mtmp); /* return attack */ 644. if (mstatus & MM_DEF_DIED) return 2; 645. } 646. 647. return 0; 648. } 649. 650. { /* Dog avoids harmful traps, but perhaps it has to pass one 651. * in order to follow player. (Non-harmful traps do not 652. * have ALLOW_TRAPS in info[].) The dog only avoids the 653. * trap if you've seen it, unlike enemies who avoid traps 654. * if they've seen some trap of that type sometime in the 655. * past. (Neither behavior is really realistic.) 656. */ 657. struct trap *trap; 658. 659. if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) { 660. if (mtmp->mleashed) { 661. if (flags.soundok) whimper(mtmp); 662. } else 663. /* 1/40 chance of stepping on it anyway, in case 664. * it has to pass one to follow the player... 665. */ 666. if (trap->tseen && rn2(40)) continue; 667. } 668. } 669. 670. /* dog eschews cursed objects, but likes dog food */ 671. /* (minion isn't interested; `cursemsg' stays FALSE) */ 672. if (has_edog) 673. for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { 674. if (obj->cursed) cursemsg[i] = TRUE; 675. else if ((otyp = dogfood(mtmp, obj)) < MANFOOD && 676. (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) { 677. /* Note: our dog likes the food so much that he 678. * might eat it even when it conceals a cursed object */ 679. nix = nx; 680. niy = ny; 681. chi = i; 682. do_eat = TRUE; 683. cursemsg[i] = FALSE; /* not reluctant */ 684. goto newdogpos; 685. } 686. } 687. /* didn't find something to eat; if we saw a cursed item and 688. aren't being forced to walk on it, usually keep looking */ 689. if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 && 690. rn2(13 * uncursedcnt)) continue; 691. 692. /* lessen the chance of backtracking to previous position(s) */ 693. k = has_edog ? uncursedcnt : cnt; 694. for (j = 0; j < MTSZ && j < k - 1; j++) 695. if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) 696. if (rn2(MTSZ * (k - j))) goto nxti; 697. 698. j = ((ndist = GDIST(nx,ny)) - nidist) * appr; 699. if ((j == 0 && !rn2(++chcnt)) || j < 0 || 700. (j > 0 && !whappr && 701. ((omx == nix && omy == niy && !rn2(3)) 702. || !rn2(12)) 703. )) { 704. nix = nx; 705. niy = ny; 706. nidist = ndist; 707. if(j < 0) chcnt = 0; 708. chi = i; 709. } 710. nxti: ; 711. } 712. newdogpos: 713. if (nix != omx || niy != omy) { 714. struct obj *mw_tmp; 715. 716. if (info[chi] & ALLOW_U) { 717. if (mtmp->mleashed) { /* play it safe */ 718. pline("%s breaks loose of %s leash!", 719. Monnam(mtmp), mhis(mtmp)); 720. m_unleash(mtmp, FALSE); 721. } 722. (void) mattacku(mtmp); 723. return(0); 724. } 725. if (!m_in_out_region(mtmp, nix, niy)) 726. return 1; 727. if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || 728. closed_door(nix, niy)) && 729. mtmp->weapon_check != NO_WEAPON_WANTED && 730. tunnels(mtmp->data) && needspick(mtmp->data)) { 731. if (closed_door(nix, niy)) { 732. if (!(mw_tmp = MON_WEP(mtmp)) || 733. !is_pick(mw_tmp) || !is_axe(mw_tmp)) 734. mtmp->weapon_check = NEED_PICK_OR_AXE; 735. } else if (IS_TREE(levl[nix][niy].typ)) { 736. if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) 737. mtmp->weapon_check = NEED_AXE; 738. } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { 739. mtmp->weapon_check = NEED_PICK_AXE; 740. } 741. if (mtmp->weapon_check >= NEED_PICK_AXE && 742. mon_wield_item(mtmp)) 743. return 0; 744. } 745. /* insert a worm_move() if worms ever begin to eat things */ 746. remove_monster(omx, omy); 747. place_monster(mtmp, nix, niy); 748. if (cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy))) 749. pline("%s moves only reluctantly.", Monnam(mtmp)); 750. for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; 751. mtmp->mtrack[0].x = omx; 752. mtmp->mtrack[0].y = omy; 753. /* We have to know if the pet's gonna do a combined eat and 754. * move before moving it, but it can't eat until after being 755. * moved. Thus the do_eat flag. 756. */ 757. if (do_eat) { 758. if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; 759. } 760. } else if (mtmp->mleashed && distu(omx, omy) > 4) { 761. /* an incredible kludge, but the only way to keep pooch near 762. * after it spends time eating or in a trap, etc. 763. */ 764. coord cc; 765. 766. nx = sgn(omx - u.ux); 767. ny = sgn(omy - u.uy); 768. cc.x = u.ux + nx; 769. cc.y = u.uy + ny; 770. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 771. 772. i = xytod(nx, ny); 773. for (j = (i + 7)%8; j < (i + 1)%8; j++) { 774. dtoxy(&cc, j); 775. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 776. } 777. for (j = (i + 6)%8; j < (i + 2)%8; j++) { 778. dtoxy(&cc, j); 779. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 780. } 781. cc.x = mtmp->mx; 782. cc.y = mtmp->my; 783. dognext: 784. if (!m_in_out_region(mtmp, nix, niy)) 785. return 1; 786. remove_monster(mtmp->mx, mtmp->my); 787. place_monster(mtmp, cc.x, cc.y); 788. newsym(cc.x,cc.y); 789. set_apparxy(mtmp); 790. } 791. return(1); 792. } 793.
could_reach_item[]
794. /* check if a monster could pick up objects from a location */ 795. STATIC_OVL boolean 796. could_reach_item(mon, nx, ny) 797. struct monst *mon; 798. xchar nx, ny; 799. { 800. if ((!is_pool(nx,ny) || is_swimmer(mon->data)) && 801. (!is_lava(nx,ny) || likes_lava(mon->data)) && 802. (!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data))) 803. return TRUE; 804. return FALSE; 805. } 806.
can_reach_location[]
807. /* Hack to prevent a dog from being endlessly stuck near an object that 808. * it can't reach, such as caught in a teleport scroll niche. It recursively 809. * checks to see if the squares in between are good. The checking could be a 810. * little smarter; a full check would probably be useful in m_move() too. 811. * Since the maximum food distance is 5, this should never be more than 5 calls 812. * deep. 813. */ 814. STATIC_OVL boolean 815. can_reach_location(mon, mx, my, fx, fy) 816. struct monst *mon; 817. xchar mx, my, fx, fy; 818. { 819. int i, j; 820. int dist; 821. 822. if (mx == fx && my == fy) return TRUE; 823. if (!isok(mx, my)) return FALSE; /* should not happen */ 824. 825. dist = dist2(mx, my, fx, fy); 826. for(i=mx-1; i<=mx+1; i++) { 827. for(j=my-1; j<=my+1; j++) { 828. if (!isok(i, j)) 829. continue; 830. if (dist2(i, j, fx, fy) >= dist) 831. continue; 832. if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) && 833. (!may_dig(i,j) || !tunnels(mon->data))) 834. continue; 835. if (IS_DOOR(levl[i][j].typ) && 836. (levl[i][j].doormask & (D_CLOSED | D_LOCKED))) 837. continue; 838. if (!could_reach_item(mon, i, j)) 839. continue; 840. if (can_reach_location(mon, i, j, fx, fy)) 841. return TRUE; 842. } 843. } 844. return FALSE; 845. } 846. 847. #endif /* OVL0 */
wantdoor[]
848. #ifdef OVLB 849. 850. /*ARGSUSED*/ /* do_clear_area client */ 851. STATIC_PTR void 852. wantdoor(x, y, distance) 853. int x, y; 854. genericptr_t distance; 855. { 856. int ndist; 857. 858. if (*(int*)distance > (ndist = distu(x, y))) { 859. gx = x; 860. gy = y; 861. *(int*)distance = ndist; 862. } 863. } 864. 865. #endif /* OVLB */ 866. 867. /*dogmove.c*/