Source:NetHack 3.3.0/steed.c

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 */