From Wikihack
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.
[edit] 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.
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.
[edit] 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.
[edit] 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.
[edit] 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.
[edit] 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 */
[edit] 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.
[edit] 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.
[edit] 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.
[edit] 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.
[edit] 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.
[edit] 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 */
[edit] 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*/