abstract
| - Below is the full text to hack.dog.c from the source code of Hack 1.0. To link to a particular line, write [[Hack 1.0/hack.dog.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2. 3. #include "hack.h" 4. #include "hack.mfndpos.h" 5. extern char POISONOUS[]; 6. extern struct monst *makemon(); 7. #include "def.edog.h" 8. 9. struct permonst li_dog = 10. { "little dog", 'd',2,18,6,1,6,sizeof(struct edog) }; 11. struct permonst dog = 12. { "dog", 'd',4,16,5,1,6,sizeof(struct edog) }; 13. struct permonst la_dog = 14. { "large dog", 'd',6,15,4,2,4,sizeof(struct edog) }; 15. 16. 17. makedog(){ 18. register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy); 19. if(!mtmp) return; /* dogs were genocided */ 20. initedog(mtmp); 21. } 22. 23. initedog(mtmp) register struct monst *mtmp; { 24. mtmp->mtame = mtmp->mpeaceful = 1; 25. EDOG(mtmp)->hungrytime = 1000 + moves; 26. EDOG(mtmp)->eattime = 0; 27. EDOG(mtmp)->droptime = 0; 28. EDOG(mtmp)->dropdist = 10000; 29. EDOG(mtmp)->apport = 10; 30. EDOG(mtmp)->whistletime = 0; 31. } 32. 33. /* attach the monsters that went down (or up) together with @ */ 34. struct monst *mydogs = 0; 35. struct monst *fallen_down = 0; /* monsters that fell through a trapdoor */ 36. 37. losedogs(){ 38. register struct monst *mtmp; 39. while(mtmp = mydogs){ 40. mydogs = mtmp->nmon; 41. mtmp->nmon = fmon; 42. fmon = mtmp; 43. mnexto(mtmp); 44. } 45. while(mtmp = fallen_down){ 46. fallen_down = mtmp->nmon; 47. mtmp->nmon = fmon; 48. fmon = mtmp; 49. rloc(mtmp); 50. } 51. } 52. 53. keepdogs(){ 54. register struct monst *mtmp; 55. for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->mtame) { 56. if(dist(mtmp->mx,mtmp->my) > 2) { 57. mtmp->mtame = 0; /* dog becomes wild */ 58. mtmp->mpeaceful = 0; 59. continue; 60. } 61. relmon(mtmp); 62. mtmp->nmon = mydogs; 63. mydogs = mtmp; 64. unpmon(mtmp); 65. keepdogs(); /* we destroyed the link, so use recursion */ 66. return; /* (admittedly somewhat primitive) */ 67. } 68. } 69. 70. fall_down(mtmp) register struct monst *mtmp; { 71. relmon(mtmp); 72. mtmp->nmon = fallen_down; 73. fallen_down = mtmp; 74. unpmon(mtmp); 75. mtmp->mtame = 0; 76. } 77. 78. /* return quality of food; the lower the better */ 79. #define DOGFOOD 0 80. #define CADAVER 1 81. #define ACCFOOD 2 82. #define MANFOOD 3 83. #define APPORT 4 84. #define POISON 5 85. #define UNDEF 6 86. dogfood(obj) register struct obj *obj; { 87. switch(obj->olet) { 88. case FOOD_SYM: 89. return( 90. (obj->otyp == TRIPE_RATION) ? DOGFOOD : 91. (obj->otyp < CARROT) ? ACCFOOD : 92. (obj->otyp < CORPSE) ? MANFOOD : 93. (index(POISONOUS, obj->spe) || obj->age + 50 <= moves || 94. obj->otyp == DEAD_COCKATRICE) 95. ? POISON : CADAVER 96. ); 97. default: 98. if(!obj->cursed) return(APPORT); 99. /* fall into next case */ 100. case BALL_SYM: 101. case CHAIN_SYM: 102. case ROCK_SYM: 103. return(UNDEF); 104. } 105. } 106. 107. /* return 0 (no move), 1 (move) or 2 (dead) */ 108. dog_move(mtmp, after) register struct monst *mtmp; { 109. register int nx,ny,omx,omy,appr,nearer,j; 110. int udist,chi,i,whappr; 111. register struct monst *mtmp2; 112. register struct permonst *mdat = mtmp->data; 113. register struct edog *edog = EDOG(mtmp); 114. struct obj *obj; 115. struct gen *trap; 116. xchar cnt,chcnt,nix,niy; 117. schar dogroom,uroom; 118. xchar gx,gy,gtyp,otyp; /* current goal */ 119. coord poss[9]; 120. int info[9]; 121. #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy)) 122. #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy)) 123. 124. if(moves <= edog->eattime) return(0); /* dog is still eating */ 125. omx = mtmp->mx; 126. omy = mtmp->my; 127. whappr = (moves - EDOG(mtmp)->whistletime < 5); 128. if(moves > edog->hungrytime + 500 && !mtmp->mconf){ 129. mtmp->mconf = 1; 130. mtmp->orig_hp /= 3; 131. if(mtmp->mhp > mtmp->orig_hp) 132. mtmp->mhp = mtmp->orig_hp; 133. if(cansee(omx,omy)) 134. pline("%s is confused from hunger", Monnam(mtmp)); 135. else pline("You feel worried about your %s.", monnam(mtmp)); 136. } else 137. if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){ 138. if(cansee(omx,omy)) 139. pline("%s dies from hunger", Monnam(mtmp)); 140. else 141. pline("You have a sad feeling for a moment, then it passes"); 142. mondied(mtmp); 143. return(2); 144. } 145. dogroom = inroom(omx,omy); 146. uroom = inroom(u.ux,u.uy); 147. udist = dist(omx,omy); 148. 149. /* if we are carrying sth then we drop it (perhaps near @) */ 150. /* Note: if apport == 1 then our behaviour is independent of udist */ 151. if(mtmp->minvent){ 152. if(!rn2(udist) || !rn2((int) edog->apport)) 153. if(rn2(10) < edog->apport){ 154. relobj(mtmp,0); 155. if(edog->apport > 1) edog->apport--; 156. } 157. } else { 158. if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){ 159. if((otyp = dogfood(obj)) <= CADAVER){ 160. nix = omx; 161. niy = omy; 162. goto eatobj; 163. } 164. if(obj->owt < 10*mtmp->data->mlevel) 165. if(rn2(20) < edog->apport+3) 166. if(rn2(udist) || !rn2((int) edog->apport)){ 167. freeobj(obj); 168. unpobj(obj); 169. /* if(levl[omx][omy].scrsym == obj->olet) 170. newsym(omx,omy); */ 171. mpickobj(mtmp,obj); 172. } 173. } 174. } 175. 176. /* first we look for food */ 177. gtyp = UNDEF; /* no goal as yet */ 178. #ifdef LINT 179. gx = gy = 0; 180. #endif LINT 181. for(obj = fobj; obj; obj = obj->nobj) { 182. otyp = dogfood(obj); 183. if(otyp > gtyp || otyp == UNDEF) continue; 184. if(inroom(obj->ox,obj->oy) != dogroom) continue; 185. if(otyp < MANFOOD && 186. (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) { 187. if(otyp < gtyp || (otyp == gtyp && 188. DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){ 189. gx = obj->ox; 190. gy = obj->oy; 191. gtyp = otyp; 192. } 193. } else 194. if(gtyp == UNDEF && dogroom >= 0 && 195. uroom == dogroom && 196. !mtmp->minvent && edog->apport > rn2(8)){ 197. gx = obj->ox; 198. gy = obj->oy; 199. gtyp = APPORT; 200. } 201. } 202. if(gtyp == UNDEF || 203. (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){ 204. if(dogroom < 0 || dogroom == uroom){ 205. gx = u.ux; 206. gy = u.uy; 207. #ifndef QUEST 208. } else { 209. int tmp = rooms[dogroom].fdoor; 210. cnt = rooms[dogroom].doorct; 211. 212. gx = gy = FAR; /* random, far away */ 213. while(cnt--){ 214. if(dist(gx,gy) > 215. dist(doors[tmp].x, doors[tmp].y)){ 216. gx = doors[tmp].x; 217. gy = doors[tmp].y; 218. } 219. tmp++; 220. } 221. /* here gx == FAR e.g. when dog is in a vault */ 222. if(gx == FAR || (gx == omx && gy == omy)){ 223. gx = u.ux; 224. gy = u.uy; 225. } 226. #endif QUEST 227. } 228. appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; 229. if(after && udist <= 4 && gx == u.ux && gy == u.uy) 230. return(0); 231. if(udist > 1){ 232. if(levl[u.ux][u.uy].typ < ROOM || !rn2(4) || 233. whappr || 234. (mtmp->minvent && rn2((int) edog->apport))) 235. appr = 1; 236. } 237. /* if you have dog food he'll follow you more closely */ 238. if(appr == 0){ 239. obj = invent; 240. while(obj){ 241. if(obj->otyp == TRIPE_RATION){ 242. appr = 1; 243. break; 244. } 245. obj = obj->nobj; 246. } 247. } 248. } else appr = 1; /* gtyp != UNDEF */ 249. if(mtmp->mconf) appr = 0; 250. #ifdef TRACK 251. if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){ 252. extern coord *gettrack(); 253. register coord *cp; 254. cp = gettrack(omx,omy); 255. if(cp){ 256. gx = cp->x; 257. gy = cp->y; 258. } 259. } 260. #endif TRACK 261. nix = omx; 262. niy = omy; 263. cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS); 264. chcnt = 0; 265. chi = -1; 266. for(i=0; i 267. nx = poss[i].x; 268. ny = poss[i].y; 269. if(info[i] & ALLOW_M){ 270. mtmp2 = m_at(nx,ny); 271. if(mtmp2->data->mlevel >= mdat->mlevel+2 || 272. mtmp2->data->mlet == 'c') 273. continue; 274. if(after) return(0); /* hit only once each move */ 275. 276. if(hitmm(mtmp, mtmp2) == 1 && rn2(4) && 277. mtmp2->mlstmv != moves && 278. hitmm(mtmp2,mtmp) == 2) return(2); 279. return(0); 280. } 281. 282. /* dog avoids traps */ 283. /* but perhaps we have to pass a trap in order to follow @ */ 284. if((info[i] & ALLOW_TRAPS) && (trap = g_at(nx,ny,ftrap))){ 285. if(!(trap->gflag & SEEN) && rn2(40)) continue; 286. if(rn2(10)) continue; 287. } 288. 289. /* dog eschewes cursed objects */ 290. /* but likes dog food */ 291. obj = fobj; 292. while(obj){ 293. if(obj->ox != nx || obj->oy != ny) 294. goto nextobj; 295. if(obj->cursed) goto nxti; 296. if(obj->olet == FOOD_SYM && 297. (otyp = dogfood(obj)) < MANFOOD && 298. (otyp < ACCFOOD || edog->hungrytime <= moves)){ 299. /* Note: our dog likes the food so much that he 300. might eat it even when it conceals a cursed object */ 301. nix = nx; 302. niy = ny; 303. chi = i; 304. eatobj: 305. edog->eattime = moves + objects[obj->otyp].oc_delay; 306. edog->hungrytime = 307. moves + 5*objects[obj->otyp].nutrition; 308. mtmp->mconf = 0; 309. if(cansee(nix,niy)) 310. pline("%s ate %s.", Monnam(mtmp), doname(obj)); 311. /* perhaps this was a reward */ 312. if(otyp != CADAVER) 313. edog->apport += 200/(edog->dropdist+moves-edog->droptime); 314. delobj(obj); 315. goto newdogpos; 316. } 317. nextobj: 318. obj = obj->nobj; 319. } 320. 321. for(j=0; j 322. if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) 323. if(rn2(4*(cnt-j))) goto nxti; 324. 325. /* Some stupid C compilers cannot compute the whole expression at once. */ 326. nearer = GDIST(nx,ny); 327. nearer -= GDIST(nix,niy); 328. nearer *= appr; 329. if((nearer == 0 && !rn2(++chcnt)) || nearer<0 || 330. (nearer > 0 && !whappr && 331. ((omx == nix && omy == niy && !rn2(3)) 332. || !rn2(12)) 333. )){ 334. nix = nx; 335. niy = ny; 336. if(nearer < 0) chcnt = 0; 337. chi = i; 338. } 339. nxti: ; 340. } 341. newdogpos: 342. if(nix != omx || niy != omy){ 343. if(info[chi] & ALLOW_U){ 344. (void) hitu(mtmp, d(mdat->damn, mdat->damd)+1); 345. return(0); 346. } 347. mtmp->mx = nix; 348. mtmp->my = niy; 349. for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; 350. mtmp->mtrack[0].x = omx; 351. mtmp->mtrack[0].y = omy; 352. } 353. if(mintrap(mtmp) == 2) /* he died */ 354. return(2); 355. pmon(mtmp); 356. return(1); 357. } 358. 359. /* return roomnumber or -1 */ 360. inroom(x,y) xchar x,y; { 361. #ifndef QUEST 362. register struct mkroom *croom = &rooms[0]; 363. while(croom->hx >= 0){ 364. if(croom->hx >= x-1 && croom->lx <= x+1 && 365. croom->hy >= y-1 && croom->ly <= y+1) 366. return(croom - rooms); 367. croom++; 368. } 369. #endif QUEST 370. return(-1); /* not in room or on door */ 371. } 372. 373. tamedog(mtmp, obj) 374. register struct monst *mtmp; 375. register struct obj *obj; 376. { 377. register struct monst *mtmp2; 378. if(mtmp->mtame || 379. #ifndef NOWORM 380. mtmp->wormno || 381. #endif NOWORM 382. mtmp->isshk || mtmp->isgd) 383. return(0); /* no tame long worms? */ 384. if(obj) { 385. if(dogfood(obj) >= MANFOOD) return(0); 386. if(cansee(mtmp->mx,mtmp->my)){ 387. pline("%s devours the %s.", Monnam(mtmp), 388. objects[obj->otyp].oc_name); 389. } 390. obfree(obj, (struct obj *) 0); 391. } 392. mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth); 393. *mtmp2 = *mtmp; 394. mtmp2->mxlth = sizeof(struct edog); 395. if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp)); 396. initedog(mtmp2); 397. replmon(mtmp,mtmp2); 398. return(1); 399. }
|