Source:Hack 1.0/hack.dog.c
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
Screenshots and source code from Hack are used under the CWI license.
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<cnt; 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<MTSZ && j<cnt-1; 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. }