Source:NetHack 3.3.0/steed.c

From NetHackWiki
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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