abstract
| - Below is the full text to steed.c from the source code of NetHack 3.3.0. To link to a particular line, write [[NetHack 3.3.0/steed.c#line123]], for example. Warning! This is the source code from an old release. For the latest release, see Source code 1. /* SCCS Id: @(#)steed.c 3.3 1999/08/16 */ 2. /* Copyright (c) Kevin Hugo, 1998-1999. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. #include "hack.h" 6. 7. 8. #ifdef STEED 9. 10. /* Monsters that might be ridden */ 11. static NEARDATA const char steeds[] = { 12. S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0' 13. }; 14. 15. 16. /*** Putting the saddle on ***/ 17. 18. /* Can this monster wear a saddle? */ 19. boolean 20. can_saddle(mtmp) 21. struct monst *mtmp; 22. { 23. struct permonst *ptr = mtmp->data; 24. 25. return (index(steeds, ptr->mlet) && 26. !humanoid(ptr) && (ptr->msize >= MZ_MEDIUM) && 27. !amorphous(ptr) && !noncorporeal(ptr) && 28. !is_whirly(ptr) && !unsolid(ptr)); 29. } 30. 31. 32. int 33. use_saddle(otmp) 34. struct obj *otmp; 35. { 36. struct monst *mtmp; 37. struct permonst *ptr; 38. int chance; 39. const char *s; 40. 41. 42. /* Can you use it? */ 43. if (nohands(youmonst.data)) { 44. You("have no hands!"); /* not `body_part(HAND)' */ 45. return 0; 46. } else if (!freehand()) { 47. You("have no free %s.", body_part(HAND)); 48. return 0; 49. } 50. 51. /* Select an animal */ 52. if (u.uswallow || Underwater || !getdir((char *)0)) { 53. pline("Never mind."); 54. return 0; 55. } 56. if (!u.dx && !u.dy) { 57. pline("Saddle yourself? Very funny..."); 58. return 0; 59. } 60. if (!isok(u.ux+u.dx, u.uy+u.dy) || 61. !(mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) || 62. !canspotmon(mtmp)) { 63. pline("I see nobody there."); 64. return 1; 65. } 66. 67. /* Is this a valid monster? */ 68. if (mtmp->misc_worn_check & W_SADDLE || 69. which_armor(mtmp, W_SADDLE)) { 70. pline("%s is already saddled.", Monnam(mtmp)); 71. return 1; 72. } 73. ptr = mtmp->data; 74. if (touch_petrifies(ptr) && !Stone_resistance) { 75. char kbuf[BUFSZ]; 76. 77. You("touch %s.", mon_nam(mtmp)); 78. if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { 79. Sprintf(kbuf, "attempting to saddle %s", a_monnam(mtmp)); 80. instapetrify(kbuf); 81. } 82. } 83. if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { 84. pline("Shame on you!"); 85. exercise(A_WIS, FALSE); 86. return 1; 87. } 88. if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || 89. mtmp->isgd || mtmp->iswiz) { 90. pline("I think %s would mind.", mon_nam(mtmp)); 91. return 1; 92. } 93. if (!can_saddle(mtmp)) { 94. You_cant("saddle such a creature."); 95. return 1; 96. } 97. 98. /* Calculate your chance */ 99. chance = ACURR(A_DEX) + ACURR(A_CHA)/2 + 2*mtmp->mtame; 100. chance += u.ulevel * (mtmp->mtame ? 20 : 5); 101. if (!mtmp->mtame) chance -= 10*mtmp->m_lev; 102. if (Role_if(PM_KNIGHT)) 103. chance += 20; 104. switch (P_SKILL(P_RIDING)) { 105. case P_ISRESTRICTED: 106. case P_UNSKILLED: 107. default: 108. chance -= 20; break; 109. case P_BASIC: 110. break; 111. case P_SKILLED: 112. chance += 15; break; 113. case P_EXPERT: 114. chance += 30; break; 115. } 116. if (Confusion || Fumbling || Glib) 117. chance -= 20; 118. else if (uarmg && 119. (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *)0 && 120. !strncmp(s, "riding ", 7)) 121. /* Bonus for wearing "riding" (but not fumbling) gloves */ 122. chance += 10; 123. else if (uarmf && 124. (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *)0 && 125. !strncmp(s, "riding ", 7)) 126. /* ... or for "riding boots" */ 127. chance += 10; 128. if (otmp->cursed) 129. chance -= 50; 130. 131. /* Make the attempt */ 132. if (rn2(100) < chance) { 133. You("put the saddle on %s.", mon_nam(mtmp)); 134. freeinv(otmp); 135. mpickobj(mtmp, otmp); 136. mtmp->misc_worn_check |= W_SADDLE; 137. otmp->owornmask = W_SADDLE; 138. otmp->leashmon = mtmp->m_id; 139. update_mon_intrinsics(mtmp, otmp, TRUE); 140. } else 141. pline("%s resists!", Monnam(mtmp)); 142. return 1; 143. } 144. 145. 146. /*** Riding the monster ***/ 147. 148. /* Can we ride this monster? Caller should also check can_saddle() */ 149. boolean 150. can_ride(mtmp) 151. struct monst *mtmp; 152. { 153. return (mtmp->mtame && humanoid(youmonst.data) && 154. !verysmall(youmonst.data) && !bigmonst(youmonst.data) && 155. (!Underwater || is_swimmer(mtmp->data))); 156. } 157. 158. 159. int 160. doride() 161. { 162. boolean forcemount = FALSE; 163. if (u.usteed) 164. dismount_steed(DISMOUNT_BYCHOICE); 165. else if(getdir((char *)0) && isok(u.ux+u.dx, u.uy+u.dy)) { 166. #ifdef WIZARD 167. if (wizard && yn("Force the mount to succeed?") == 'y') 168. forcemount = TRUE; 169. #endif 170. (void) mount_steed(m_at(u.ux+u.dx, u.uy+u.dy), forcemount); 171. } 172. return 1; 173. } 174. 175. 176. /* Start riding, with the given monster */ 177. boolean 178. mount_steed(mtmp, force) 179. struct monst *mtmp; /* The animal */ 180. boolean force; /* Quietly force this animal */ 181. { 182. struct obj *otmp; 183. char buf[BUFSZ]; 184. struct permonst *ptr; 185. 186. 187. /* Sanity checks */ 188. if (u.usteed) { 189. if (!force) 190. You("are already riding %s.", mon_nam(u.usteed)); 191. return (FALSE); 192. } 193. 194. /* Is the player in the right form? */ 195. if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) || 196. bigmonst(youmonst.data))) { 197. if (!force) 198. You("won't fit on a saddle."); 199. return (FALSE); 200. } 201. if(!force && (near_capacity() > SLT_ENCUMBER)) { 202. You_cant("do that while carrying so much stuff."); 203. return (FALSE); 204. } 205. 206. /* Can the player reach and see the monster? */ 207. if (u.uswallow || u.ustuck || u.utrap || Punished) { 208. if (!force) 209. You("are stuck here for now."); 210. return (FALSE); 211. } 212. if (!mtmp || (!force && ((Blind && !Blind_telepat) || 213. mtmp->mundetected || 214. mtmp->m_ap_type == M_AP_FURNITURE || 215. mtmp->m_ap_type == M_AP_OBJECT))) { 216. if (!force) 217. pline("I see nobody there."); 218. return (FALSE); 219. } 220. 221. /* Is this a valid monster? */ 222. otmp = which_armor(mtmp, W_SADDLE); 223. if (!otmp) { 224. pline("%s is not saddled.", Monnam(mtmp)); 225. return (FALSE); 226. } 227. ptr = mtmp->data; 228. if (touch_petrifies(ptr) && !Stone_resistance) { 229. char kbuf[BUFSZ]; 230. 231. You("touch %s.", mon_nam(mtmp)); 232. Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); 233. instapetrify(kbuf); 234. } 235. if (!mtmp->mtame || mtmp->isminion) { 236. if (!force) 237. pline("I think %s would mind.", mon_nam(mtmp)); 238. return (FALSE); 239. } 240. if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) { 241. pline("%s resists!", Monnam(mtmp)); 242. return (FALSE); 243. } 244. if (!force && Underwater && !is_swimmer(ptr)) { 245. You_cant("ride that creature while under water."); 246. return (FALSE); 247. } 248. if (!can_saddle(mtmp) || !can_ride(mtmp)) { 249. if (!force) 250. You_cant("ride such a creature."); 251. return (0); 252. } 253. 254. /* Is the player impaired? */ 255. if (!force && !is_floater(ptr) && !is_flyer(ptr) && 256. Levitation && !Lev_at_will) { 257. You("cannot reach %s.", mon_nam(mtmp)); 258. return (FALSE); 259. } 260. if (!force && uarm && is_metallic(uarm) && 261. greatest_erosion(uarm)) { 262. Your("%s armor is too stiff to be able to mount %s.", 263. uarm->oeroded ? "rusty" : "corroded", 264. mon_nam(mtmp)); 265. return (FALSE); 266. } 267. if (!force && (Confusion || Fumbling || Glib || Wounded_legs || 268. otmp->cursed || (u.ulevel+mtmp->mtame < rnd(MAXULEV/2+5)))) { 269. You("slip while trying to get on %s.", mon_nam(mtmp)); 270. Sprintf(buf, "slipped while mounting %s", a_monnam(mtmp)); 271. losehp(rn1(5,10), buf, NO_KILLER_PREFIX); 272. return (FALSE); 273. } 274. 275. /* Success */ 276. if (!force) { 277. if (Levitation && !is_floater(ptr) && !is_flyer(ptr)) 278. /* Must have Lev_at_will at this point */ 279. pline("%s magically floats up!", Monnam(mtmp)); 280. You("mount %s.", mon_nam(mtmp)); 281. } 282. u.usteed = mtmp; 283. remove_monster(mtmp->mx, mtmp->my); 284. teleds(mtmp->mx, mtmp->my); 285. return (TRUE); 286. } 287. 288. 289. /* You and your steed have moved */ 290. void 291. exercise_steed() 292. { 293. if (!u.usteed) 294. return; 295. 296. /* It takes many turns of riding to exercise skill */ 297. if (u.urideturns++ >= 100) { 298. u.urideturns = 0; 299. use_skill(P_RIDING, 1); 300. } 301. return; 302. } 303. 304. 305. /* The player kicks or whips the steed */ 306. void 307. kick_steed() 308. { 309. if (!u.usteed) 310. return; 311. 312. /* Make the steed less tame and check if it resists */ 313. if (u.usteed->mtame) u.usteed->mtame--; 314. if (!u.usteed->mtame || (u.ulevel+u.usteed->mtame < rnd(MAXULEV/2+5))) { 315. dismount_steed(DISMOUNT_THROWN); 316. return; 317. } 318. 319. pline("%s gallops!", Monnam(u.usteed)); 320. u.ugallop += rn1(20, 30); 321. return; 322. } 323. 324. 325. /* Stop riding the current steed */ 326. void 327. dismount_steed(reason) 328. int reason; /* Player was thrown off etc. */ 329. { 330. struct monst *mtmp; 331. struct obj *otmp; 332. coord cc; 333. const char *verb = "fall"; 334. boolean repair_leg_damage = TRUE; 335. unsigned save_utrap = u.utrap; 336. 337. /* Sanity checks */ 338. if (!(mtmp = u.usteed)) 339. /* Just return silently */ 340. return; 341. 342. /* Check the reason for dismounting */ 343. otmp = which_armor(mtmp, W_SADDLE); 344. switch (reason) { 345. case DISMOUNT_THROWN: 346. verb = "are thrown"; 347. case DISMOUNT_FELL: 348. You("%s off of %s!", verb, mon_nam(mtmp)); 349. losehp(rn1(10,10), "riding accident", KILLED_BY_AN); 350. HWounded_legs += rn1(5, 5); 351. EWounded_legs |= BOTH_SIDES; 352. repair_leg_damage = FALSE; 353. break; 354. case DISMOUNT_POLY: 355. You("can no longer ride %s.", mon_nam(u.usteed)); 356. break; 357. case DISMOUNT_ENGULFED: 358. /* caller displays message */ 359. break; 360. case DISMOUNT_GENERIC: 361. /* no messages, just make it so */ 362. break; 363. case DISMOUNT_BYCHOICE: 364. default: 365. if (otmp && otmp->cursed) { 366. You("can't. The saddle seems to be cursed."); 367. otmp->bknown = TRUE; 368. return; 369. } 370. if (!mtmp->mnamelth) { 371. pline("You've been through the dungeon on %s with no name.", 372. an(mtmp->data->mname)); 373. if (Hallucination) 374. pline("It felt good to get out of the rain."); 375. } else 376. You("dismount %s.", mon_nam(mtmp)); 377. } 378. /* While riding these refer to the steed's legs 379. * so after dismounting they refer to the player's 380. * legs once again. 381. */ 382. if (repair_leg_damage) HWounded_legs = EWounded_legs = 0; 383. 384. /* Release the steed and saddle */ 385. u.usteed = 0; 386. u.ugallop = 0L; 387. 388. /* Set player and steed's position. Try moving the player first */ 389. place_monster(mtmp, u.ux, u.uy); 390. if (!u.uswallow && !u.ustuck && enexto(&cc, u.ux, u.uy, youmonst.data)) { 391. /* The steed may drop into water/lava */ 392. if (mtmp->mhp > 0 && is_pool(u.ux,u.uy) && 393. !is_flyer(mtmp->data) && !is_floater(mtmp->data) && 394. !is_clinger(mtmp->data)) { 395. if (!Underwater) 396. pline("%s falls into the %s!", Monnam(mtmp), surface(u.ux,u.uy)); 397. if (!is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { 398. killed(mtmp); 399. adjalign(-1); 400. } 401. } 402. if (mtmp->mhp > 0 && is_lava(u.ux,u.uy) && 403. !is_flyer(mtmp->data) && !is_floater(mtmp->data) && 404. !is_clinger(mtmp->data)) { 405. pline("%s is pulled into the lava!", Monnam(mtmp)); 406. if (!likes_lava(mtmp->data)) { 407. killed(mtmp); 408. adjalign(-1); 409. } 410. } 411. 412. /* Steed dismounting consists of two steps: being moved to another 413. * square, and descending to the floor. We have functions to do 414. * each of these activities, but they're normally called 415. * individually and include an attempt to look at or pick up the 416. * objects on the floor: 417. * teleds() --> spoteffects() --> pickup() 418. * float_down() --> pickup() 419. * We use this kludge to make sure there is only one such attempt. 420. * 421. * Clearly this is not the best way to do it. A full fix would 422. * involve having these functions not call pickup() at all, instead 423. * calling them first and calling pickup() afterwards. But it 424. * would take a lot of work to keep this change from having any 425. * unforseen side effects (for instance, you would no longer be 426. * able to walk onto a square with a hole, and autopickup before 427. * falling into the hole). 428. */ 429. /* Keep steed here, move the player to cc; teleds() clears u.utrap */ 430. in_steed_dismounting = TRUE; 431. teleds(cc.x, cc.y); 432. in_steed_dismounting = FALSE; 433. if (reason != DISMOUNT_ENGULFED) /* being swallowed anyway in that case */ 434. vision_full_recalc = 1; 435. 436. /* Put your steed in your trap */ 437. if (save_utrap && mtmp->mhp > 0) 438. (void) mintrap(mtmp); 439. 440. /* Couldn't... try placing the steed */ 441. } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) 442. /* Keep player here, move the steed to cc */ 443. rloc_to(mtmp, cc.x, cc.y); 444. /* Player stays put */ 445. /* Otherwise, kill the steed */ 446. else { 447. killed(mtmp); 448. adjalign(-1); 449. } 450. 451. /* Return the player to the floor */ 452. (void) float_down(0L, W_SADDLE); 453. flags.botl = 1; 454. if (reason != DISMOUNT_ENGULFED) (void)encumber_msg(); 455. return; 456. } 457. 458. 459. #endif /* STEED */
|