Source:SLASH'EM 0.0.7E7F2/dogmove.c
Jump to navigation
Jump to search
Below is the full text to dogmove.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[Source:SLASH'EM 0.0.7E7F2/dogmove.c#line123]], for example.
Source code for vanilla NetHack is at Source code.
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
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. 5. #include "hack.h" 6. 7. #include "mfndpos.h" 8. #include "edog.h" 9. #include "emin.h" 10. #include "epri.h" 11. 12. /* #define DEBUG */ /* uncomment to enable debugging */ 13. 14. #ifdef DEBUG 15. # ifdef WIZARD 16. #define debugpline if (wizard) pline 17. # else 18. #define debugpline pline 19. # endif 20. #endif 21. 22. extern boolean notonhead; 23. 24. #ifdef OVL0 25. 26. STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *)); 27. STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int)); 28. STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); 29. 30. STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *)); 31. STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P, 32. XCHAR_P,XCHAR_P)); 33. STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P)); 34. 35. STATIC_OVL struct obj * 36. DROPPABLES(mon) 37. register struct monst *mon; 38. { 39. register struct obj *obj; 40. struct obj *wep = MON_WEP(mon); 41. boolean item1 = FALSE, item2 = FALSE; 42. 43. if (is_animal(mon->data) || mindless(mon->data)) 44. item1 = item2 = TRUE; 45. if (!tunnels(mon->data) || !needspick(mon->data)) 46. item1 = TRUE; 47. for(obj = mon->minvent; obj; obj = obj->nobj) { 48. if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK 49. || !which_armor(mon, W_ARMS))) { 50. item1 = TRUE; 51. continue; 52. } 53. if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) { 54. item2 = TRUE; 55. continue; 56. } 57. if (!obj->owornmask && obj != wep) return obj; 58. } 59. return (struct obj *)0; 60. } 61. 62. static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; 63. 64. #endif /* OVL0 */ 65. 66. STATIC_OVL boolean FDECL(cursed_object_at, (struct monst *, int, int)); 67. 68. STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */ 69. 70. STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); 71. 72. #ifdef OVLB 73. STATIC_OVL boolean 74. cursed_object_at(mtmp, x, y) 75. register struct monst *mtmp; 76. int x, y; 77. { 78. struct obj *otmp; 79. 80. for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 81. /* [Tom] demons & undead don't care, though */ 82. /* [ALI] demons & undead avoid blessed items instead */ 83. if ((is_demon(mtmp->data) || is_undead(mtmp->data)) ? 84. otmp->blessed : otmp->cursed) 85. { 86. #ifdef DEBUG 87. debugpline("%s thinks %s at (%d,%d) is `cursed'", 88. noit_Monnam(mtmp), doname(otmp), x, y); 89. #endif 90. return TRUE; 91. } 92. return FALSE; 93. } 94. 95. int 96. dog_nutrition(mtmp, obj) 97. struct monst *mtmp; 98. struct obj *obj; 99. { 100. int nutrit; 101. 102. /* 103. * It is arbitrary that the pet takes the same length of time to eat 104. * as a human, but gets more nutritional value. 105. */ 106. if (obj->oclass == FOOD_CLASS) { 107. if(obj->otyp == CORPSE) { 108. mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); 109. nutrit = mons[obj->corpsenm].cnutrit; 110. } else { 111. mtmp->meating = objects[obj->otyp].oc_delay; 112. nutrit = objects[obj->otyp].oc_nutrition; 113. } 114. switch(mtmp->data->msize) { 115. case MZ_TINY: nutrit *= 8; break; 116. case MZ_SMALL: nutrit *= 6; break; 117. default: 118. case MZ_MEDIUM: nutrit *= 5; break; 119. case MZ_LARGE: nutrit *= 4; break; 120. case MZ_HUGE: nutrit *= 3; break; 121. case MZ_GIGANTIC: nutrit *= 2; break; 122. } 123. if(obj->oeaten) { 124. mtmp->meating = eaten_stat(mtmp->meating, obj); 125. nutrit = eaten_stat(nutrit, obj); 126. } 127. } else if (obj->oclass == COIN_CLASS) { 128. mtmp->meating = (int)(obj->quan/2000) + 1; 129. if (mtmp->meating < 0) mtmp->meating = 1; 130. nutrit = (int)(obj->quan/20); 131. if (nutrit < 0) nutrit = 0; 132. } else { 133. /* Unusual pet such as gelatinous cube eating odd stuff. 134. * meating made consistent with wild monsters in mon.c. 135. * nutrit made consistent with polymorphed player nutrit in 136. * eat.c. (This also applies to pets eating gold.) 137. */ 138. mtmp->meating = obj->owt/20 + 1; 139. nutrit = 5*objects[obj->otyp].oc_nutrition; 140. } 141. return nutrit; 142. } 143. 144. /* returns 2 if pet dies, otherwise 1 */ 145. int 146. dog_eat(mtmp, obj, x, y, devour) 147. register struct monst *mtmp; 148. register struct obj * obj; 149. int x, y; 150. boolean devour; 151. { 152. register struct edog *edog = EDOG(mtmp); 153. boolean poly = FALSE, grow = FALSE, heal = FALSE; 154. int nutrit; 155. boolean vis = (cansee(x, y) || cansee(mtmp->mx, mtmp->my)); 156. boolean vampiric = is_vampire(mtmp->data); 157. 158. if(edog->hungrytime < monstermoves) 159. edog->hungrytime = monstermoves; 160. nutrit = dog_nutrition(mtmp, obj); 161. poly = polyfodder(obj); 162. grow = mlevelgain(obj); 163. heal = mhealup(obj); 164. if (devour) { 165. if (mtmp->meating > 1) mtmp->meating /= 2; 166. if (nutrit > 1) nutrit = (nutrit * 3) / 4; 167. } 168. 169. /* vampires only get 1/5 normal nutrition */ 170. if (vampiric) { 171. mtmp->meating = (mtmp->meating + 4) / 5; 172. nutrit = (nutrit + 4) / 5; 173. } 174. 175. edog->hungrytime += nutrit; 176. mtmp->mconf = 0; 177. if (edog->mhpmax_penalty) { 178. /* no longer starving */ 179. mtmp->mhpmax += edog->mhpmax_penalty; 180. edog->mhpmax_penalty = 0; 181. } 182. if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; 183. if (mtmp->mtame < 20) mtmp->mtame++; 184. if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */ 185. newsym(x, y); 186. newsym(mtmp->mx, mtmp->my); 187. } 188. if (is_pool(x, y) && !Underwater) { 189. /* Don't print obj */ 190. /* TODO: Reveal presence of sea monster (especially sharks) */ 191. } else 192. /* hack: observe the action if either new or old location is in view */ 193. /* However, invisible monsters should still be "it" even though out of 194. sight locations should not. */ 195. if (vis) 196. pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It", 197. vampiric ? "drains" : devour ? "devours" : "eats", 198. (obj->oclass == FOOD_CLASS) ? 199. singular(obj, doname) : doname(obj)); 200. /* It's a reward if it's DOGFOOD and the player dropped/threw it. */ 201. /* We know the player had it if invlet is set -dlc */ 202. if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet) 203. #ifdef LINT 204. edog->apport = 0; 205. #else 206. edog->apport += (int)(200L/ 207. ((long)edog->dropdist + monstermoves - edog->droptime)); 208. #endif 209. if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { 210. /* The object's rustproofing is gone now */ 211. obj->oerodeproof = 0; 212. mtmp->mstun = 1; 213. if (canseemon(mtmp) && flags.verbose) { 214. pline("%s spits %s out in disgust!", 215. Monnam(mtmp), distant_name(obj,doname)); 216. } 217. } else if (vampiric) { 218. /* Split Object */ 219. if (obj->quan > 1L) { 220. if(!carried(obj)) { 221. (void) splitobj(obj, 1L); 222. } else { 223. /* Carried */ 224. obj = splitobj(obj, obj->quan - 1L); 225. 226. freeinv(obj); 227. if (inv_cnt() >= 52 && !merge_choice(invent, obj)) 228. dropy(obj); 229. else 230. obj = addinv(obj); /* unlikely but a merge is possible */ 231. } 232. #ifdef DEBUG 233. debugpline("split object,"); 234. #endif 235. } 236. 237. /* Take away blood nutrition */ 238. obj->oeaten = drainlevel(obj); 239. obj->odrained = 1; 240. } else if (obj == uball) { 241. unpunish(); 242. delobj(obj); 243. } else if (obj == uchain) 244. unpunish(); 245. else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) { 246. obj->quan--; 247. obj->owt = weight(obj); 248. } else 249. delobj(obj); 250. 251. if (poly) { 252. (void) mon_spec_poly(mtmp, (struct permonst *)0, 0L, FALSE, 253. cansee(mtmp->mx, mtmp->my), FALSE, FALSE); 254. #if 0 255. (void) newcham(mtmp, (struct permonst *)0, FALSE, 256. cansee(mtmp->mx, mtmp->my)); 257. #endif 258. } 259. /* limit "instant" growth to prevent potential abuse */ 260. if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { 261. if (!grow_up(mtmp, (struct monst *)0)) return 2; 262. } 263. if (heal) mtmp->mhp = mtmp->mhpmax; 264. return 1; 265. } 266. 267. #endif /* OVLB */ 268. #ifdef OVL0 269. 270. /* hunger effects -- returns TRUE on starvation */ 271. STATIC_OVL boolean 272. dog_hunger(mtmp, edog) 273. register struct monst *mtmp; 274. register struct edog *edog; 275. { 276. if (monstermoves > edog->hungrytime + 500) { 277. if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { 278. edog->hungrytime = monstermoves + 500; 279. /* but not too high; it might polymorph */ 280. } else if (!edog->mhpmax_penalty) { 281. /* starving pets are limited in healing */ 282. int newmhpmax = mtmp->mhpmax / 3; 283. mtmp->mconf = 1; 284. edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax; 285. mtmp->mhpmax = newmhpmax; 286. if (mtmp->mhp > mtmp->mhpmax) 287. mtmp->mhp = mtmp->mhpmax; 288. if (mtmp->mhp < 1) goto dog_died; 289. if (cansee(mtmp->mx, mtmp->my)) 290. pline("%s is confused from hunger.", Monnam(mtmp)); 291. else if (couldsee(mtmp->mx, mtmp->my)) 292. beg(mtmp); 293. else 294. You_feel("worried about %s.", y_monnam(mtmp)); 295. stop_occupation(); 296. } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { 297. dog_died: 298. if (mtmp->mleashed 299. #ifdef STEED 300. && mtmp != u.usteed 301. #endif 302. ) 303. Your("leash goes slack."); 304. else if (cansee(mtmp->mx, mtmp->my)) 305. pline("%s starves.", Monnam(mtmp)); 306. else 307. You_feel("%s for a moment.", 308. Hallucination ? "bummed" : "sad"); 309. mondied(mtmp); 310. return(TRUE); 311. } 312. } 313. return(FALSE); 314. } 315. 316. /* do something with object (drop, pick up, eat) at current position 317. * returns 1 if object eaten (since that counts as dog's move), 2 if died 318. */ 319. STATIC_OVL int 320. dog_invent(mtmp, edog, udist) 321. register struct monst *mtmp; 322. register struct edog *edog; 323. int udist; 324. { 325. /* KMH, balance patch -- quantity picked up should depend on dog's level */ 326. int dogquan = 10 * mtmp->m_lev; 327. register int omx, omy; 328. struct obj *obj; 329. /* 330. struct obj *floor_obj; 331. int temp_quan; 332. */ 333. if (mtmp->msleeping || !mtmp->mcanmove) return(0); 334. 335. omx = mtmp->mx; 336. omy = mtmp->my; 337. 338. /* if we are carrying sth then we drop it (perhaps near @) */ 339. /* Note: if apport == 1 then our behaviour is independent of udist */ 340. /* Use udist+1 so steed won't cause divide by zero */ 341. #ifndef GOLDOBJ 342. if(DROPPABLES(mtmp) || mtmp->mgold) { 343. #else 344. if(DROPPABLES(mtmp)) { 345. #endif 346. if (!rn2(udist+1) || !rn2(edog->apport)) 347. if(rn2(10) < edog->apport){ 348. relobj(mtmp, (int)mtmp->minvis, TRUE); 349. if(edog->apport > 1) edog->apport--; 350. edog->dropdist = udist; /* hpscdi!jon */ 351. edog->droptime = moves; 352. } 353. } else { 354. if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass) 355. #ifdef MAIL 356. && obj->otyp != SCR_MAIL 357. #endif 358. ){ 359. int edible = dogfood(mtmp, obj); 360. 361. if ((edible <= CADAVER || 362. /* starving pet is more aggressive about eating */ 363. (edog->mhpmax_penalty && edible == ACCFOOD)) && 364. could_reach_item(mtmp, obj->ox, obj->oy)) 365. return dog_eat(mtmp, obj, omx, omy, FALSE); 366. 367. /* [Tom] demonic & undead pets don't mind cursed items */ 368. if(can_carry(mtmp, obj) && 369. could_reach_item(mtmp, obj->ox, obj->oy) && 370. (!obj->cursed || is_demon(mtmp->data) || is_undead(mtmp->data)) && 371. (!obj->blessed || (!is_demon(mtmp->data) && !is_undead(mtmp->data)))) { 372. if(rn2(20) < edog->apport+3) { 373. if (rn2(udist) || !rn2(edog->apport)) { 374. if ((!nohands(mtmp->data)) || 375. /* KMH, balance patch -- 10*level */ 376. (obj->quan <= dogquan)) 377. { 378. if (cansee(omx, omy) && flags.verbose) 379. pline("%s picks up %s.", Monnam(mtmp), 380. distant_name(obj, doname)); 381. obj_extract_self(obj); 382. newsym(omx,omy); 383. (void) mpickobj(mtmp,obj); 384. } 385. else /* picking up a few objects from a pile... */ 386. /* KMH -- fix picking up zero quantity */ 387. if (dogquan > 0) { 388. if (obj->oclass == COIN_CLASS) { 389. /* KMH, balance patch -- 10*level */ 390. #ifndef GOLDOBJ 391. obj->quan -= dogquan; 392. if (cansee(omx, omy) && flags.verbose) 393. pline("%s picks up %d gold pieces.", 394. Monnam(mtmp), 395. dogquan); 396. mtmp->mgold += dogquan; 397. #else 398. if (obj->quan != dogquan) 399. obj = splitobj(obj, dogquan); 400. if (cansee(omx, omy) && flags.verbose) 401. pline("%s picks up %s.", 402. Monnam(mtmp), 403. doname(obj)); 404. obj_extract_self(obj); 405. newsym(omx,omy); 406. (void) mpickobj(mtmp,obj); 407. #endif 408. } else { 409. /* 410. struct obj *floor_obj; 411. int temp_quan; 412. 413. obj->quan -= dogquan; 414. temp_quan = obj->quan; 415. floor_obj = level.objects[omx][omy]; 416. mpickobj(mtmp,obj); 417. obj->quan = dogquan; 418. if (cansee(omx, omy) && flags.verbose) 419. pline("%s picks up %s.", Monnam(mtmp), 420. distant_name(obj, doname)); 421. floor_obj->quan = temp_quan;*/ 422. } 423. } 424. if (attacktype(mtmp->data, AT_WEAP) && 425. mtmp->weapon_check == NEED_WEAPON) { 426. mtmp->weapon_check = NEED_HTH_WEAPON; 427. (void) mon_wield_item(mtmp); 428. } 429. m_dowear(mtmp, FALSE); 430. } 431. } 432. } 433. } 434. } 435. return 0; 436. } 437. 438. /* set dog's goal -- gtyp, gx, gy 439. * returns -1/0/1 (dog's desire to approach player) or -2 (abort move) 440. */ 441. STATIC_OVL int 442. dog_goal(mtmp, edog, after, udist, whappr) 443. register struct monst *mtmp; 444. struct edog *edog; 445. int after, udist, whappr; 446. { 447. register int omx, omy; 448. boolean in_masters_sight, dog_has_minvent; 449. register struct obj *obj; 450. xchar otyp; 451. int appr; 452. 453. #ifdef STEED 454. /* Steeds don't move on their own will */ 455. if (mtmp == u.usteed) 456. return (-2); 457. #endif 458. 459. omx = mtmp->mx; 460. omy = mtmp->my; 461. 462. in_masters_sight = couldsee(omx, omy); 463. dog_has_minvent = (DROPPABLES(mtmp) != 0); 464. 465. if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ 466. gtyp = APPORT; 467. gx = u.ux; 468. gy = u.uy; 469. } else { 470. #define DDIST(x,y) (dist2(x,y,omx,omy)) 471. #define SQSRCHRADIUS 5 472. int min_x, max_x, min_y, max_y; 473. register int nx, ny; 474. 475. gtyp = UNDEF; /* no goal as yet */ 476. gx = gy = 0; /* suppress 'used before set' message */ 477. 478. if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; 479. if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; 480. if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; 481. if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; 482. 483. /* nearby food is the first choice, then other objects */ 484. for (obj = fobj; obj; obj = obj->nobj) { 485. nx = obj->ox; 486. ny = obj->oy; 487. if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { 488. otyp = dogfood(mtmp, obj); 489. /* skip inferior goals */ 490. if (otyp > gtyp || otyp == UNDEF) 491. continue; 492. /* avoid cursed items unless starving */ 493. if (cursed_object_at(mtmp, nx, ny) && 494. !(edog->mhpmax_penalty && otyp < MANFOOD)) 495. continue; 496. /* skip completely unreacheable goals */ 497. if (!could_reach_item(mtmp, nx, ny) || 498. !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny)) 499. continue; 500. if (otyp < MANFOOD) { 501. if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) { 502. gx = nx; 503. gy = ny; 504. gtyp = otyp; 505. } 506. } else if(gtyp == UNDEF && in_masters_sight && 507. !dog_has_minvent && 508. (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) && 509. (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) && 510. edog->apport > rn2(8) && 511. can_carry(mtmp,obj)) { 512. gx = nx; 513. gy = ny; 514. gtyp = APPORT; 515. } 516. } 517. } 518. } 519. 520. /* follow player if appropriate */ 521. if (gtyp == UNDEF || 522. (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) { 523. gx = u.ux; 524. gy = u.uy; 525. if (after && udist <= 4 && gx == u.ux && gy == u.uy) 526. return(-2); 527. appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; 528. if (udist > 1) { 529. if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || 530. whappr || 531. (dog_has_minvent && rn2(edog->apport))) 532. appr = 1; 533. } 534. /* if you have dog food it'll follow you more closely */ 535. if (appr == 0) { 536. obj = invent; 537. while (obj) { 538. if(dogfood(mtmp, obj) == DOGFOOD) { 539. appr = 1; 540. break; 541. } 542. obj = obj->nobj; 543. } 544. } 545. } else 546. appr = 1; /* gtyp != UNDEF */ 547. if(mtmp->mconf) 548. appr = 0; 549. 550. #define FARAWAY (COLNO + 2) /* position outside screen */ 551. if (gx == u.ux && gy == u.uy && !in_masters_sight) { 552. register coord *cp; 553. 554. cp = gettrack(omx,omy); 555. if (cp) { 556. gx = cp->x; 557. gy = cp->y; 558. if(edog) edog->ogoal.x = 0; 559. } else { 560. /* assume master hasn't moved far, and reuse previous goal */ 561. if(edog && edog->ogoal.x && 562. ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { 563. gx = edog->ogoal.x; 564. gy = edog->ogoal.y; 565. edog->ogoal.x = 0; 566. } else { 567. int fardist = FARAWAY * FARAWAY; 568. gx = gy = FARAWAY; /* random */ 569. do_clear_area(omx, omy, 9, wantdoor, 570. (genericptr_t)&fardist); 571. 572. /* here gx == FARAWAY e.g. when dog is in a vault */ 573. if (gx == FARAWAY || (gx == omx && gy == omy)) { 574. gx = u.ux; 575. gy = u.uy; 576. } else if(edog) { 577. edog->ogoal.x = gx; 578. edog->ogoal.y = gy; 579. } 580. } 581. } 582. } else if(edog) { 583. edog->ogoal.x = 0; 584. } 585. return appr; 586. } 587. 588. #ifdef DEBUG 589. #define CHECK_ALLOW(flag,str) if ((allowflags & (flag)) == (flag)) { \ 590. allowflags ^= (flag); \ 591. if (bp != buf) { *bp++=','; *bp++=' '; } \ 592. Strcpy(bp, str); \ 593. bp += strlen(bp); \ 594. } else 595. 596. STATIC_OVL char * 597. allow_set(allowflags) 598. long allowflags; 599. { 600. static char buf[500]; 601. char *bp = buf; 602. if (allowflags == 0) 603. return "(none)"; 604. *bp = '\0'; 605. CHECK_ALLOW(ALLOW_TRAPS, "can enter traps"); 606. CHECK_ALLOW(ALLOW_U, "can attack you"); 607. CHECK_ALLOW(ALLOW_M, "can attack other monsters"); 608. CHECK_ALLOW(ALLOW_TM, "can attack tame monsters"); 609. CHECK_ALLOW(NOTONL, "avoids direct line to player"); 610. CHECK_ALLOW(OPENDOOR, "opens closed doors"); 611. CHECK_ALLOW(UNLOCKDOOR, "unlocks locked doors"); 612. CHECK_ALLOW(BUSTDOOR, "breaks any doors"); 613. CHECK_ALLOW(ALLOW_ROCK, "pushes rocks"); 614. CHECK_ALLOW(ALLOW_WALL, "walks thru walls"); 615. CHECK_ALLOW(ALLOW_DIG, "digs"); 616. CHECK_ALLOW(ALLOW_SANCT, "enters temples"); 617. CHECK_ALLOW(ALLOW_SSM, "ignores scare monster"); 618. CHECK_ALLOW(NOGARLIC, "hates garlic"); 619. if (allowflags) { 620. if (bp != buf) { *bp++=','; *bp++=' '; } 621. sprintf(bp, "0x%lX", allowflags); 622. } 623. return buf; 624. } 625. 626. #undef CHECK_ALLOW 627. #endif 628. 629. boolean 630. betrayed(mtmp) 631. register struct monst *mtmp; 632. { 633. boolean has_edog = !mtmp->isminion; 634. struct edog *edog = EDOG(mtmp); 635. int udist = distu(mtmp->mx, mtmp->my); 636. 637. if (udist < 4 && has_edog && !mtmp->isspell && !rn2(3) 638. && can_betray(mtmp->data) 639. && !mindless(mtmp->data) 640. && mtmp->mhp >= u.uhp /* Pet is buff enough */ 641. && rn2(22) > mtmp->mtame /* Roll against tameness */ 642. && rn2(edog->abuse + 2)) { 643. /* Treason */ 644. if (canseemon(mtmp)) 645. pline("%s turns on you!", Monnam(mtmp)); 646. else 647. pline("You feel uneasy about %s.", y_monnam(mtmp)); 648. mtmp->mpeaceful = 0; 649. mtmp->mtame = 0; 650. mtmp->mtraitor = TRUE; 651. 652. /* Do we need to call newsym() here? */ 653. newsym(mtmp->mx, mtmp->my); 654. return TRUE; 655. } 656. return FALSE; 657. } 658. 659. /* return 0 (no move), 1 (move) or 2 (dead) */ 660. int 661. dog_move(mtmp, after) 662. register struct monst *mtmp; 663. register int after; /* this is extra fast monster movement */ 664. { 665. int omx, omy; /* original mtmp position */ 666. int appr, whappr, udist; 667. int i, j, k; 668. register struct edog *edog = EDOG(mtmp); 669. struct obj *obj = (struct obj *) 0; 670. xchar otyp; 671. boolean has_edog, cursemsg[9], is_spell, do_eat = FALSE; 672. xchar nix, niy; /* position mtmp is (considering) moving to */ 673. register int nx, ny; /* temporary coordinates */ 674. xchar cnt, uncursedcnt, chcnt; 675. int chi = -1, nidist, ndist; 676. coord poss[9]; 677. long info[9], allowflags; 678. #define GDIST(x,y) (dist2(x,y,gx,gy)) 679. 680. /* 681. * Tame Angels have isminion set and an ispriest structure instead of 682. * an edog structure. Fortunately, guardian Angels need not worry 683. * about mundane things like eating and fetching objects, and can 684. * spend all their energy defending the player. (They are the only 685. * monsters with other structures that can be tame.) 686. */ 687. has_edog = !mtmp->isminion; 688. 689. /* 690. * Similar to Angels and Guardians are spell beings - temporary 691. * magical manifestations of the spellcaster's mind. 692. * They don't eat/pickup objects - only fight. 693. * But, they aren't dismissed by conflict. 694. */ 695. is_spell = mtmp->isspell; 696. 697. omx = mtmp->mx; 698. omy = mtmp->my; 699. if (has_edog && !is_spell && dog_hunger(mtmp, edog)) return(2); /* starved */ 700. 701. udist = distu(omx,omy); 702. #ifdef STEED 703. /* Let steeds eat and maybe throw rider during Conflict */ 704. if (mtmp == u.usteed) { 705. if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { 706. dismount_steed(DISMOUNT_THROWN); 707. return (1); 708. } 709. udist = 1; 710. } else 711. #endif 712. /* maybe we tamed him while being swallowed --jgm */ 713. if (!udist) return(0); 714. 715. /* Intelligent pets may rebel (apart from minions, spell beings) */ 716. if (!rn2(850) && betrayed(mtmp)) return 1; 717. 718. nix = omx; /* set before newdogpos */ 719. niy = omy; 720. cursemsg[0] = FALSE; /* lint suppression */ 721. info[0] = 0; /* ditto */ 722. 723. if (has_edog && !is_spell) { 724. j = dog_invent(mtmp, edog, udist); 725. if (j == 2) return 2; /* died */ 726. else if (j == 1) goto newdogpos; /* eating something */ 727. 728. whappr = (monstermoves - edog->whistletime < 5); 729. } else 730. whappr = 0; 731. 732. appr = dog_goal(mtmp, (has_edog && !is_spell) ? edog : (struct edog *)0, 733. after, udist, whappr); 734. #ifdef DEBUG 735. { 736. char *goal; 737. switch(gtyp) 738. { 739. case DOGFOOD: goal = "dogfood"; break; 740. case CADAVER: goal = "cadaver"; break; 741. case ACCFOOD: goal = "accfood"; break; 742. case MANFOOD: goal = "manfood"; break; 743. case APPORT: goal = "apport"; break; 744. case POISON: goal = "poison"; break; 745. case UNDEF: goal = "undef"; break; 746. case TABU: goal = "tabu"; break; 747. default: goal = "???"; break; 748. } 749. debugpline("G(%s): %s @ (%d,%d), appr = %d", 750. mon_nam(mtmp), goal, gx, gy, appr); 751. } 752. #endif 753. if (appr == -2) return(0); 754. 755. allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; 756. if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); 757. if (passes_bars(mtmp->data) && !In_sokoban(&u.uz)) 758. allowflags |= ALLOW_BARS; 759. if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; 760. if (Conflict && !resist(mtmp, RING_CLASS, 0, 0) && In_endgame(&u.uz)) { 761. allowflags |= ALLOW_U; 762. if (!has_edog && !is_spell) { 763. coord mm; 764. /* Guardian angel refuses to be conflicted; rather, 765. * it disappears, angrily, and sends in some nasties 766. */ 767. if (canspotmon(mtmp)) { 768. pline("%s rebukes you, saying:", Monnam(mtmp)); 769. verbalize("Since you desire conflict, have some more!"); 770. } 771. mongone(mtmp); 772. i = rnd(4); 773. while(i--) { 774. mm.x = u.ux; 775. mm.y = u.uy; 776. if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) 777. (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, 778. mm.x, mm.y, FALSE); 779. } 780. return(2); 781. 782. } 783. } 784. 785. /* ALI -- Mindless pets shouldn't attack monsters when 786. * scared; they have no sense of allegiance to the hero, 787. * only self-preservation. This prevents weak pets blocking 788. * your exit from a shop by constantly missing shopkeeper. 789. */ 790. if (mindless(mtmp->data) && mtmp->mflee) 791. allowflags &= ~ALLOW_M; 792. 793. if (!Conflict && !mtmp->mconf && 794. mtmp == u.ustuck && !sticks(youmonst.data)) { 795. unstuck(mtmp); /* swallowed case handled above */ 796. You("get released!"); 797. } 798. if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { 799. allowflags |= OPENDOOR; 800. if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; 801. } 802. if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; 803. if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; 804. cnt = mfndpos(mtmp, poss, info, allowflags); 805. #ifdef DEBUG 806. debugpline("%d positions found with allow: %s", cnt, 807. allow_set(allowflags)); 808. for (i = 0; i < cnt; i++) { 809. debugpline("[%d] %s @ (%d, %d)", i, 810. allow_set(info[i]), poss[i].x, poss[i].y); 811. } 812. #endif 813. 814. /* Normally dogs don't step on cursed items, but if they have no 815. * other choice they will. This requires checking ahead of time 816. * to see how many uncursed item squares are around. 817. */ 818. 819. uncursedcnt = 0; 820. for (i = 0; i < cnt; i++) { 821. nx = poss[i].x; ny = poss[i].y; 822. if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue; 823. if (cursed_object_at(mtmp, nx, ny)) continue; 824. uncursedcnt++; 825. } 826. 827. chcnt = 0; 828. chi = -1; 829. nidist = GDIST(nix,niy); 830. 831. for (i = 0; i < cnt; i++) { 832. nx = poss[i].x; 833. ny = poss[i].y; 834. cursemsg[i] = FALSE; 835. 836. /* if leashed, we drag him along. */ 837. if (mtmp->mleashed && distu(nx, ny) > 4) continue; 838. 839. /* if a guardian, try to stay close by choice */ 840. if ((!has_edog || is_spell) && 841. (j = distu(nx, ny)) > 16 && j >= udist) continue; 842. 843. if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { 844. int mstatus; 845. register struct monst *mtmp2 = m_at(nx,ny); 846. aligntyp align1, align2; /* For priests, minions etc. */ 847. 848. if (mtmp->isminion) align1 = EMIN(mtmp)->min_align; 849. else if (is_unicorn(mtmp->data)) 850. align1 = sgn(mtmp->data->maligntyp); 851. else if (mtmp->ispriest) align1 = EPRI(mtmp)->shralign; 852. else align1 = A_NONE; 853. if (mtmp2->isminion) align2 = EMIN(mtmp2)->min_align; 854. else if (is_unicorn(mtmp2->data)) 855. align2 = sgn(mtmp2->data->maligntyp); 856. else if (mtmp2->ispriest) align2 = EPRI(mtmp2)->shralign; 857. else align2 = A_NONE; 858. 859. /* Mindless monsters and spelled monsters have no fear of 860. * attacking higher level monsters 861. */ 862. if (((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 && !is_spell && 863. !mindless(mtmp->data)) || 864. (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && 865. mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee 866. && (perceives(mtmp->data) || !mtmp2->minvis)) || 867. (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) || 868. (mtmp2->data==&mons[PM_GAS_SPORE] && rn2(16)) || 869. (!attacktype(mtmp->data, AT_EXPL) && 870. max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || 871. /* Minions/Angels don't attack 872. * coaligned minions/priests/angels/unicorns. 873. */ 874. (align1 == align2 && align1 != A_NONE) || 875. ((mtmp->mhp*4 < mtmp->mhpmax 876. || mtmp2->data->msound == MS_GUARDIAN 877. || mtmp2->data->msound == MS_LEADER) && 878. mtmp2->mpeaceful && !Conflict) || 879. (touch_petrifies(mtmp2->data) && 880. !resists_ston(mtmp))) 881. continue; 882. 883. if (after) return(0); /* hit only once each move */ 884. 885. notonhead = 0; 886. mstatus = mattackm(mtmp, mtmp2); 887. 888. /* aggressor (pet) died */ 889. if (mstatus & MM_AGR_DIED) return 2; 890. 891. if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && 892. rn2(4) && mtmp2->mlstmv != monstermoves && 893. !onscary(mtmp->mx, mtmp->my, mtmp2) && 894. /* monnear check needed: long worms hit on tail */ 895. monnear(mtmp2, mtmp->mx, mtmp->my)) { 896. mstatus = mattackm(mtmp2, mtmp); /* return attack */ 897. if (mstatus & MM_DEF_DIED) return 2; 898. } 899. 900. return 0; 901. } 902. 903. { /* Dog avoids harmful traps, but perhaps it has to pass one 904. * in order to follow player. (Non-harmful traps do not 905. * have ALLOW_TRAPS in info[].) The dog only avoids the 906. * trap if you've seen it, unlike enemies who avoid traps 907. * if they've seen some trap of that type sometime in the 908. * past. (Neither behavior is really realistic.) 909. */ 910. struct trap *trap; 911. 912. if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) { 913. if (mtmp->mleashed) { 914. if (flags.soundok) whimper(mtmp); 915. } else 916. /* 1/40 chance of stepping on it anyway, in case 917. * it has to pass one to follow the player... 918. */ 919. if (trap->tseen && rn2(40)) continue; 920. } 921. } 922. 923. /* dog eschews cursed objects, but likes dog food */ 924. /* [Tom] except demons & undead, who don't care */ 925. /* (minion isn't interested; `cursemsg' stays FALSE) */ 926. if (has_edog && !is_spell) { 927. for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { 928. if ((obj->cursed) && has_edog && !is_demon(mtmp->data) 929. && !is_undead(mtmp->data)) cursemsg[i] = TRUE; 930. if (obj->blessed && has_edog && (is_demon(mtmp->data) 931. || is_undead(mtmp->data))) cursemsg[i] = TRUE; 932. else if ((otyp = dogfood(mtmp, obj)) < MANFOOD && 933. (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) { 934. /* Note: our dog likes the food so much that he 935. * might eat it even when it conceals a cursed object */ 936. nix = nx; 937. niy = ny; 938. chi = i; 939. do_eat = TRUE; 940. cursemsg[i] = FALSE; /* not reluctant */ 941. goto newdogpos; 942. } 943. } 944. } 945. /* didn't find something to eat; if we saw a cursed item and 946. aren't being forced to walk on it, usually keep looking */ 947. if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 && 948. rn2(13 * uncursedcnt)) continue; 949. 950. /* lessen the chance of backtracking to previous position(s) */ 951. k = (has_edog && !is_spell) ? uncursedcnt : cnt; 952. for (j = 0; j < MTSZ && j < k - 1; j++) 953. if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) 954. if (rn2(MTSZ * (k - j))) goto nxti; 955. 956. j = ((ndist = GDIST(nx,ny)) - nidist) * appr; 957. if ((j == 0 && !rn2(++chcnt)) || j < 0 || 958. (j > 0 && !whappr && 959. ((omx == nix && omy == niy && !rn2(3)) 960. || !rn2(12)) 961. )) { 962. nix = nx; 963. niy = ny; 964. nidist = ndist; 965. if(j < 0) chcnt = 0; 966. chi = i; 967. } 968. nxti: ; 969. } 970. newdogpos: 971. if (nix != omx || niy != omy) { 972. struct obj *mw_tmp; 973. 974. if (info[chi] & ALLOW_U) { 975. if (mtmp->mleashed) { /* play it safe */ 976. pline("%s breaks loose of %s leash!", 977. Monnam(mtmp), mhis(mtmp)); 978. m_unleash(mtmp, FALSE); 979. } 980. (void) mattacku(mtmp); 981. return(0); 982. } 983. if (!m_in_out_region(mtmp, nix, niy)) 984. return 1; 985. if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || 986. closed_door(nix, niy)) && 987. mtmp->weapon_check != NO_WEAPON_WANTED && 988. tunnels(mtmp->data) && needspick(mtmp->data)) { 989. if (closed_door(nix, niy)) { 990. if (!(mw_tmp = MON_WEP(mtmp)) || 991. !is_pick(mw_tmp) || !is_axe(mw_tmp)) 992. mtmp->weapon_check = NEED_PICK_OR_AXE; 993. } else if (IS_TREE(levl[nix][niy].typ)) { 994. if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) 995. mtmp->weapon_check = NEED_AXE; 996. } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { 997. mtmp->weapon_check = NEED_PICK_AXE; 998. } 999. if (mtmp->weapon_check >= NEED_PICK_AXE && 1000. mon_wield_item(mtmp)) 1001. return 0; 1002. } 1003. /* insert a worm_move() if worms ever begin to eat things */ 1004. remove_monster(omx, omy); 1005. place_monster(mtmp, nix, niy); 1006. if (has_edog && !is_spell && cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy))) 1007. pline("%s moves only reluctantly.", Monnam(mtmp)); 1008. for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; 1009. mtmp->mtrack[0].x = omx; 1010. mtmp->mtrack[0].y = omy; 1011. /* We have to know if the pet's gonna do a combined eat and 1012. * move before moving it, but it can't eat until after being 1013. * moved. Thus the do_eat flag. 1014. */ 1015. if (do_eat) { 1016. if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; 1017. } 1018. } else if (mtmp->mleashed && distu(omx, omy) > 4) { 1019. /* an incredible kludge, but the only way to keep pooch near 1020. * after it spends time eating or in a trap, etc. 1021. */ 1022. coord cc; 1023. 1024. nx = sgn(omx - u.ux); 1025. ny = sgn(omy - u.uy); 1026. cc.x = u.ux + nx; 1027. cc.y = u.uy + ny; 1028. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1029. 1030. i = xytod(nx, ny); 1031. for (j = (i + 7)%8; j < (i + 1)%8; j++) { 1032. dtoxy(&cc, j); 1033. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1034. } 1035. for (j = (i + 6)%8; j < (i + 2)%8; j++) { 1036. dtoxy(&cc, j); 1037. if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; 1038. } 1039. cc.x = mtmp->mx; 1040. cc.y = mtmp->my; 1041. dognext: 1042. if (!m_in_out_region(mtmp, nix, niy)) 1043. return 1; 1044. remove_monster(mtmp->mx, mtmp->my); 1045. place_monster(mtmp, cc.x, cc.y); 1046. newsym(cc.x,cc.y); 1047. set_apparxy(mtmp); 1048. } 1049. return(1); 1050. } 1051. 1052. /* check if a monster could pick up objects from a location */ 1053. STATIC_OVL boolean 1054. could_reach_item(mon, nx, ny) 1055. struct monst *mon; 1056. xchar nx, ny; 1057. { 1058. if ((!is_pool(nx,ny) || is_swimmer(mon->data)) && 1059. (!is_lava(nx,ny) || likes_lava(mon->data)) && 1060. (!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data))) 1061. return TRUE; 1062. return FALSE; 1063. } 1064. 1065. /* Hack to prevent a dog from being endlessly stuck near an object that 1066. * it can't reach, such as caught in a teleport scroll niche. It recursively 1067. * checks to see if the squares in between are good. The checking could be a 1068. * little smarter; a full check would probably be useful in m_move() too. 1069. * Since the maximum food distance is 5, this should never be more than 5 calls 1070. * deep. 1071. */ 1072. STATIC_OVL boolean 1073. can_reach_location(mon, mx, my, fx, fy) 1074. struct monst *mon; 1075. xchar mx, my, fx, fy; 1076. { 1077. int i, j; 1078. int dist; 1079. 1080. if (mx == fx && my == fy) return TRUE; 1081. if (!isok(mx, my)) return FALSE; /* should not happen */ 1082. 1083. dist = dist2(mx, my, fx, fy); 1084. for(i=mx-1; i<=mx+1; i++) { 1085. for(j=my-1; j<=my+1; j++) { 1086. if (!isok(i, j)) 1087. continue; 1088. if (dist2(i, j, fx, fy) >= dist) 1089. continue; 1090. if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) && 1091. (!may_dig(i,j) || !tunnels(mon->data))) 1092. continue; 1093. if (IS_DOOR(levl[i][j].typ) && 1094. (levl[i][j].doormask & (D_CLOSED | D_LOCKED))) 1095. continue; 1096. if (!could_reach_item(mon, i, j)) 1097. continue; 1098. if (can_reach_location(mon, i, j, fx, fy)) 1099. return TRUE; 1100. } 1101. } 1102. return FALSE; 1103. } 1104. 1105. #endif /* OVL0 */ 1106. #ifdef OVLB 1107. 1108. /*ARGSUSED*/ /* do_clear_area client */ 1109. STATIC_PTR void 1110. wantdoor(x, y, distance) 1111. int x, y; 1112. genericptr_t distance; 1113. { 1114. int ndist; 1115. 1116. if (*(int*)distance > (ndist = distu(x, y))) { 1117. gx = x; 1118. gy = y; 1119. *(int*)distance = ndist; 1120. } 1121. } 1122. 1123. #endif /* OVLB */ 1124. 1125. /*dogmove.c*/