Blindfold removal fix
[slashemextended.git] / src / steed.c
blobe37ae39ebb60b14789f129c0fecb422ba4460caa
1 /* SCCS Id: @(#)steed.c 3.4 2003/01/10 */
2 /* Copyright (c) Kevin Hugo, 1998-1999. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
8 /* Monsters that might be ridden */
9 static NEARDATA const char steeds[] = {
10 S_QUADRUPED, S_UNICORN, S_ANGEL, S_DEMON, S_CENTAUR, S_DRAGON, S_JABBERWOCK, S_COCKATRICE, S_HUMANOID, S_NYMPH,
11 S_SPIDER, S_ZOUTHERN, S_BAT, S_GIANT, S_KOP, S_LICH, S_MUMMY, S_NAGA, S_VAMPIRE, S_WRAITH, S_YETI, S_ZOMBIE, S_GOLEM,
12 S_HUMAN, S_EEL, S_LIZARD, S_BAD_FOOD, S_BAD_COINS, S_FLYFISH, '\0'
13 /* added demons and some other stuff --Amy */
16 STATIC_DCL boolean landing_spot(coord *, int, int);
18 /* caller has decided that hero can't reach something while mounted */
19 void
20 rider_cant_reach()
22 You("aren't skilled enough to reach from %s.", y_monnam(u.usteed));
25 /* to check for your current steed's saddle, because we might be looking for a specific artifact --Amy */
26 boolean
27 bmwride(artid)
28 int artid;
30 if (!u.usteed) return FALSE;
32 struct obj *osaeddle = which_armor(u.usteed, W_SADDLE);
33 if ((osaeddle = which_armor(u.usteed, W_SADDLE)) && osaeddle->oartifact == artid) return TRUE;
35 return FALSE;
39 /* to check for your current steed's saddle, when looking for a specific base type of saddle --Amy */
40 boolean
41 opelride(saddleid)
42 int saddleid;
44 if (!u.usteed) return FALSE;
46 struct obj *osaeddle = which_armor(u.usteed, W_SADDLE);
47 if ((osaeddle = which_armor(u.usteed, W_SADDLE)) && osaeddle->otyp == saddleid) return TRUE;
49 return FALSE;
53 /* to check for some random monster's saddle, because we might be looking for a specific artifact --Amy */
54 boolean
55 mercedesride(artid, mtmp)
56 int artid;
57 struct monst *mtmp;
59 if (!mtmp) return FALSE;
61 struct obj *osaeddle = which_armor(mtmp, W_SADDLE);
62 if ((osaeddle = which_armor(mtmp, W_SADDLE)) && osaeddle->oartifact == artid) return TRUE;
64 return FALSE;
68 /* to check for some random monster's saddle, when looking for a specific base type of saddle --Amy */
69 boolean
70 fordride(saddleid, mtmp)
71 int saddleid;
72 struct monst *mtmp;
74 if (!mtmp) return FALSE;
76 struct obj *osaeddle = which_armor(mtmp, W_SADDLE);
77 if ((osaeddle = which_armor(mtmp, W_SADDLE)) && osaeddle->otyp == saddleid) return TRUE;
79 return FALSE;
83 /* is the monster mtmp a dedicated steed (gives better speed returns, see allmain.c)? --Amy */
84 boolean
85 dedicatedsteed(mtmp)
86 struct monst *mtmp;
88 if (mercedesride(ART_MOUNT_OF_THE_MAD_POTATO, mtmp)) return TRUE;
89 if (index(steeds, mtmp->data->mlet)) return TRUE;
90 if (mtmp->egotype_steed) return TRUE;
91 if (mtmp->data->msound == MS_NEIGH || mtmp->data->msound == MS_SHOE || mtmp->data->msound == MS_CAR) return TRUE;
93 return FALSE;
96 /* is the monster mtmp not suitable for riding (makes you very slow if you attempt to ride, see allmain.c)? --Amy */
97 boolean
98 nogoodsteed(mtmp)
99 struct monst *mtmp;
101 if (mtmp->data->msound == MS_BULLETATOR) return TRUE;
103 return FALSE;
106 /*** Putting the saddle on ***/
108 /* Can this monster wear a saddle? */
109 boolean
110 can_saddle(mtmp)
111 struct monst *mtmp;
113 if (!issoviet) return 1; /* just remove all those annoying restrictions and allow everything to be saddled --Amy */
114 struct permonst *ptr = mtmp->data;
116 return (index(steeds, ptr->mlet) && (ptr->msize >= MZ_MEDIUM) &&
117 (!humanoid(ptr) || ptr->mlet == S_CENTAUR) &&
118 !amorphous(ptr) && !noncorporeal(ptr) &&
119 !is_whirly(ptr) && !unsolid(ptr));
122 /* high skill should allow the player to have a saving throw against falling off --Amy
123 * not all instances of falling off the steed will allow you to do this though, and since I follow the rule that no skills
124 * may make things harder for you, you'll always have a chance of falling off anyway just in case you specifically WANT
125 * to be thrown off the steed (hint: cursed saddle and player would want to unmount but cannot).
126 * returns 0 if the player failed the check and will fall off, 1 if the saving throw was successful and you stay mounted */
127 boolean
128 mayfalloffsteed()
130 int ridesavingthrow = 0;
131 int spcsavingthrow = 0;
132 char buf[BUFSZ];
134 if (opelride(SEATBELT_SADDLE)) {
135 spcsavingthrow = 75;
136 if (bmwride(ART_RULES_MAKE_SENSE)) spcsavingthrow = 90;
137 if (bmwride(ART_CAR_SAFETY) && u.usteed && u.usteed->data->msound == MS_CAR) spcsavingthrow = 100;
140 if (!PlayerCannotUseSkills) {
141 if (Race_if(PM_PERVERT)) {
142 switch (P_SKILL(P_RIDING)) {
143 case P_SKILLED: ridesavingthrow = 56; break;
144 case P_EXPERT: ridesavingthrow = 67; break;
145 case P_MASTER: ridesavingthrow = 89; break;
146 case P_GRAND_MASTER: ridesavingthrow = 96; break;
147 case P_SUPREME_MASTER: ridesavingthrow = 101; break;
149 } else {
150 switch (P_SKILL(P_RIDING)) {
151 case P_SKILLED: ridesavingthrow = 11; break;
152 case P_EXPERT: ridesavingthrow = 34; break;
153 case P_MASTER: ridesavingthrow = 76; break;
154 case P_GRAND_MASTER: ridesavingthrow = 91; break;
155 case P_SUPREME_MASTER: ridesavingthrow = 101; break;
160 skillcheckdone:
162 if (Role_if(PM_JOCKEY)) ridesavingthrow += ((100 - ridesavingthrow) / 2);
164 if ((ridesavingthrow > 0) || (spcsavingthrow > 0)) {
165 getlin ("Uh-oh! You're about to fall off your steed! Attempt a saving throw? [y/yes/no]",buf);
166 (void) lcase (buf);
167 if (!(strcmp (buf, "yes")) || !(strcmp (buf, "y")) || !(strcmp (buf, "ye")) || !(strcmp (buf, "ys"))) {
168 if ((ridesavingthrow > rnd(100)) || (spcsavingthrow > rnd(100)) ) {
169 pline("Success! You've managed to stay mounted.");
170 return TRUE;
171 } else {
172 pline("Unfortunately your saving throw failed...");
173 return FALSE;
178 return FALSE;
182 /* it was SOOOOOOO annoying that a confused steed would always walk randomly, when a confused player would only be
183 * subjected to random-direction walking some of the time. Change that, and make it use riding skill. --Amy
184 * Returns TRUE if you will walk randomly, FALSE otherwise */
185 boolean
186 confsteeddir()
188 if (PlayerCannotUseSkills) return rn2(Race_if(PM_PERVERT) ? 2 : 4);
189 if (!Race_if(PM_PERVERT)) {
190 switch (P_SKILL(P_RIDING)) {
192 default: return rn2(4);
193 case P_BASIC: return rn2(2);
194 case P_SKILLED: return !rn2(3);
195 case P_EXPERT: return !rn2(4);
196 case P_MASTER: return !rn2(5);
197 case P_GRAND_MASTER: return !rn2(7);
198 case P_SUPREME_MASTER: return !rn2(10);
200 } else {
201 switch (P_SKILL(P_RIDING)) {
202 default: return rn2(2);
203 case P_BASIC: return !rn2(4);
204 case P_SKILLED: return !rn2(6);
205 case P_EXPERT: return !rn2(10);
206 case P_MASTER: return !rn2(15);
207 case P_GRAND_MASTER: return !rn2(25);
208 case P_SUPREME_MASTER: return !rn2(50);
215 use_saddle(otmp)
216 struct obj *otmp;
218 struct monst *mtmp;
219 struct permonst *ptr;
220 int chance;
221 const char *s;
224 /* Can you use it? */
225 if (nohands(youmonst.data) && !Race_if(PM_TRANSFORMER) ) {
226 You("have no hands!"); /* not `body_part(HAND)' */
227 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
229 if (yn("Try to use the saddle with another part of your body instead?") == 'y') {
230 if (rn2(3) && !polyskillchance()) {
231 make_blinded(Blinded + rnd(50),TRUE);
232 pline("You got something in your face!");
233 if (!rn2(20)) badeffect();
234 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
235 return 1;
238 else {return(0);}
240 } else if (!freehandX()) {
241 You("have no free %s.", body_part(HAND));
242 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
243 return 0;
246 /* Select an animal */
247 if (u.uswallow || Underwater || !getdir((char *)0)) {
248 pline("%s", Never_mind);
249 if (FailureEffects || u.uprops[FAILURE_EFFECTS].extrinsic || have_failurestone()) {
250 pline("Oh wait, actually I do mind...");
251 badeffect();
253 return 0;
255 if (!u.dx && !u.dy) {
256 pline("Saddle yourself? Very funny...");
257 return 0;
259 if (!isok(u.ux+u.dx, u.uy+u.dy) ||
260 !(mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) ||
261 !canspotmon(mtmp)) {
262 pline("I see nobody there.");
263 return 1;
266 /* Is this a valid monster? */
267 if (mtmp->misc_worn_check & W_SADDLE ||
268 which_armor(mtmp, W_SADDLE)) {
269 pline("%s doesn't need another one.", Monnam(mtmp));
270 return 1;
272 ptr = mtmp->data;
273 if (touch_petrifies(ptr) && (!uarmg || FingerlessGloves) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) )) {
274 static char kbuf[BUFSZ];
276 You("touch %s.", mon_nam(mtmp));
277 if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
278 sprintf(kbuf, "attempting to saddle a petrifying monster");
279 instapetrify(kbuf);
282 if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) {
283 pline("Shame on you!");
284 exercise(A_WIS, FALSE);
285 /*return 1;*/ /* removed that stupid restriction --Amy */
287 if (mtmp->isminion || mtmp->isshk || mtmp->ispriest ||
288 mtmp->isgd || mtmp->iswiz) {
289 pline("I think %s would mind.", mon_nam(mtmp));
290 return 1;
292 if (!can_saddle(mtmp)) {
293 if (!issoviet) You_cant("saddle such a creature.");
294 else pline("Ublyudka, kotoryy nazyvayet sebya sovetskiy ne khochet, chtoby vy yezdit' eto sushchestvo.");
295 return 1;
298 /* Calculate your chance */
299 chance = ACURR(A_DEX) + ACURR(A_CHA)/2 + 2*mtmp->mtame;
300 chance += GushLevel * (mtmp->mtame ? 20 : 5);
301 if (!mtmp->mtame) { /* humpers and steed egotypes should be easier... --Amy */
303 if (mtmp->egotype_steed || canalwaysride(mtmp->data) || ((mercedesride(ART_GRAND_THEFT_AUTO, mtmp)) && (mtmp->data->msound == MS_CAR) ) || ((mercedesride(ART_UTTER_USELESSNESS, mtmp)) && (mtmp->data->msound == MS_FART_NORMAL || mtmp->data->msound == MS_FART_QUIET || mtmp->data->msound == MS_FART_LOUD || mtmp->data->msound == MS_STENCH || mtmp->data->msound == MS_SUPERMAN ) ) ) {
304 if (mtmp->mpeaceful) chance -= mtmp->m_lev;
305 else chance -= 2*mtmp->m_lev;
306 } else {
307 if (mtmp->mpeaceful) chance -= 5*mtmp->m_lev;
308 else chance -= 10*mtmp->m_lev;
312 if (Role_if(PM_KNIGHT) || Role_if(PM_CHEVALIER))
313 chance += 20;
314 if (Role_if(PM_JOCKEY))
315 chance += 25;
316 if (Role_if(PM_TRANSVESTITE) || Role_if(PM_TOPMODEL))
317 chance += 50;
319 if (FemtrapActiveSabrina && mtmp->data == &mons[PM_SABRINA_S_PLATEAU_BOOT]) {
320 chance += 100;
323 if (otmp && otmp->otyp == INKA_SADDLE) chance += 100;
325 if (PlayerCannotUseSkills) chance -= 20;
326 else {
328 switch (P_SKILL(P_RIDING)) {
329 case P_ISRESTRICTED:
330 case P_UNSKILLED:
331 default:
332 chance -= 20; break;
333 case P_BASIC:
334 break;
335 case P_SKILLED:
336 chance += 25; break;
337 case P_EXPERT:
338 chance += 50; break;
339 case P_MASTER:
340 chance += 75; break;
341 case P_GRAND_MASTER:
342 chance += 100; break;
343 case P_SUPREME_MASTER:
344 chance += 150; break;
349 if ( (Confusion && !Conf_resist) || Fumbling || IsGlib)
350 chance -= 20;
351 /*else */if (uarmg &&
352 (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *)0 &&
353 ( !strcmp(s, "riding gloves") || !strcmp(s, "yezda perchatki") || !strcmp(s, "kopgina qo'lqop") ) )
354 /* Bonus for wearing "riding" (but not fumbling) gloves */
355 chance += 10;
356 /*else */if (uarmf &&
357 (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *)0 &&
358 ( !strcmp(s, "riding boots") || !strcmp(s, "sapogi dlya verkhovoy yezdy") || !strcmp(s, "kopgina chizilmasin") ) )
359 /* ... or for "riding boots" */
360 chance += 10; /* Amy edit: allowed those bonuses to stack. */
361 if (otmp->cursed && otmp->otyp == LEATHER_SADDLE)
362 chance -= 50;
364 /* Make the attempt */
365 if (rn2(100) < chance) {
366 You("put the saddle on %s.", mon_nam(mtmp));
367 if (otmp && otmp->oartifact == ART_SADDLE_OF_REFLECTION) {
368 You("reflect upon your life choices when applying the saddle.");
369 adjattrib(A_WIS, -1, FALSE, TRUE);
371 if (otmp->owornmask) remove_worn_item(otmp, FALSE);
372 freeinv(otmp);
373 /* mpickobj may free otmp it if merges, but we have already
374 checked for a saddle above, so no merger should happen */
375 (void) mpickobj(mtmp, otmp, FALSE);
376 mtmp->misc_worn_check |= W_SADDLE;
377 otmp->owornmask = W_SADDLE;
378 otmp->leashmon = mtmp->m_id;
379 update_mon_intrinsics(mtmp, otmp, TRUE, FALSE);
380 } else
381 pline("%s resists!", Monnam(mtmp));
382 return 1;
386 /*** Riding the monster ***/
388 /* Can we ride this monster? Caller should also check can_saddle() */
389 boolean
390 can_ride(mtmp)
391 struct monst *mtmp;
393 if (!issoviet) return (mtmp->mtame || mtmp->egotype_steed || (FemtrapActiveLarissa && mtmp->data->msound == MS_SHOE) || canalwaysride(mtmp->data) || ((mercedesride(ART_GRAND_THEFT_AUTO, mtmp)) && (mtmp->data->msound == MS_CAR) ) || ((mercedesride(ART_UTTER_USELESSNESS, mtmp)) && (mtmp->data->msound == MS_FART_NORMAL || mtmp->data->msound == MS_FART_QUIET || mtmp->data->msound == MS_FART_LOUD || mtmp->data->msound == MS_STENCH || mtmp->data->msound == MS_SUPERMAN ) ) || (Race_if(PM_SHOE) && mtmp->data->msound == MS_SHOE) );
395 return ((mtmp->mtame || mtmp->egotype_steed || (FemtrapActiveLarissa && mtmp->data->msound == MS_SHOE) || canalwaysride(mtmp->data) || ((mercedesride(ART_GRAND_THEFT_AUTO, mtmp)) && (mtmp->data->msound == MS_CAR) ) || ((mercedesride(ART_UTTER_USELESSNESS, mtmp)) && (mtmp->data->msound == MS_FART_NORMAL || mtmp->data->msound == MS_FART_QUIET || mtmp->data->msound == MS_FART_LOUD || mtmp->data->msound == MS_STENCH || mtmp->data->msound == MS_SUPERMAN ) ) || (Race_if(PM_SHOE) && mtmp->data->msound == MS_SHOE)) && humanoid(youmonst.data) &&
396 !verysmall(youmonst.data) && !bigmonst(youmonst.data) &&
397 (!Underwater || is_swimmer(mtmp->data)) );
400 /* Removed a lot of annoying restrictions that don't serve any purpose anyway other than annoying the player. --Amy */
401 /* In Soviet Russia, you cannot ride freely because seriously, the player isn't supposed to be able to ride. --Amy */
404 doride()
406 boolean forcemount = FALSE;
408 if (u.usteed)
409 dismount_steed(DISMOUNT_BYCHOICE);
410 else if (getdir((char *)0) && isok(u.ux+u.dx, u.uy+u.dy)) {
411 #ifdef WIZARD
412 if (wizard && yn("Force the mount to succeed?") == 'y')
413 forcemount = TRUE;
414 #endif
415 return (mount_steed(m_at(u.ux+u.dx, u.uy+u.dy), forcemount));
416 } else
417 return 0;
418 return 1;
422 /* Start riding, with the given monster */
423 boolean
424 mount_steed(mtmp, force)
425 struct monst *mtmp; /* The animal */
426 boolean force; /* Quietly force this animal */
428 struct obj *otmp;
429 char buf[BUFSZ];
430 struct permonst *ptr;
432 /* Sanity checks */
433 if (u.usteed) {
434 You("are already riding %s.", mon_nam(u.usteed));
435 return (FALSE);
438 /* Is the player in the right form? */
439 if (FunnyHallu && !force) {
440 pline("Maybe you should find a designated driver.");
441 /*return (FALSE); well, if the horse is saddled, a hallucinating player should be able to ride it --Amy*/
443 /* While riding Wounded_legs refers to the steed's,
444 * not the hero's legs.
445 * That opens up a potential abuse where the player
446 * can mount a steed, then dismount immediately to
447 * heal leg damage, because leg damage is always
448 * healed upon dismount (Wounded_legs context switch).
449 * By preventing a hero with Wounded_legs from
450 * mounting a steed, the potential for abuse is
451 * minimized, if not eliminated altogether.
453 if (Wounded_legs) {
454 Your("%s are in no shape for riding.", makeplural(body_part(LEG)));
455 #ifdef WIZARD
456 if (force && wizard && yn("Heal your legs?") == 'y')
457 HWounded_legs = 0;
458 else
459 #endif
460 if (yn("But you can try to get on your steed anyway. Do it?") == 'y') {
461 if (rn2(3)) {
462 losehp(rn1(10,20), "trying an illegal ride", KILLED_BY);
463 pline("Ouch! You slip and hurt yourself a lot!");
464 if (rn2(3)) {
465 pline("Due to your leg injury, you don't manage to swing yourself onto your steed.");
466 return(FALSE);
470 else return (FALSE);
473 if (Upolyd && !Race_if(PM_TRANSFORMER) && (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
474 bigmonst(youmonst.data) || slithy(youmonst.data))) {
475 You("won't fit on a saddle.");
477 if (yn("But you can try to get on your steed anyway. Do it?") == 'y') {
478 if (rn2(3) && !polyskillchance()) { losehp(rn1(10,20), "trying an illegal ride", NO_KILLER_PREFIX);
479 pline("Ouch! You slip and hurt yourself a lot!");
480 if (!rn2(20)) badeffect();
481 /*return 1;*/}
483 else {return(FALSE);}
486 if(!force && (near_capacity() > SLT_ENCUMBER)) {
487 You_cant("do that while carrying so much stuff.");
488 return (FALSE);
491 /* Can the player reach and see the monster? */
492 /* Amy edit: boah the vanilla code for that was really shitty... permamimics should be rideable :P */
493 if (!mtmp || (!force && !canspotmon(mtmp))) {
494 pline("I see nobody there.");
495 return (FALSE);
497 if (u.uswallow || u.ustuck || u.utrap ||
498 !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) {
499 if (!(u.uswallow || u.ustuck || u.utrap))
500 You("are unable to swing your %s over.", body_part(LEG));
501 else
502 You("are stuck here for now.");
503 return (FALSE);
506 if (Punished) {
507 You("are unable to swing your %s over.", body_part(LEG));
508 if (yn("But you can try to get on your steed anyway. Do it?") == 'y') {
509 if (rn2(3)) {
510 losehp(rn1(10,20), "trying an illegal ride", NO_KILLER_PREFIX);
511 pline("Ouch! You slip and hurt yourself a lot!");
514 else {
515 return(FALSE);
519 /* Is this a valid monster? */
520 otmp = which_armor(mtmp, W_SADDLE);
521 if (!otmp) {
522 pline("%s is not saddled.", Monnam(mtmp));
523 return (FALSE);
525 ptr = mtmp->data;
526 /* Amy edit: you should be able to ride a cockatrice as long as your body is sufficiently covered in clothing
527 * or also if you're highly skilled (making high riding skill more useful in the process) */
528 if (touch_petrifies(ptr) && (PlayerCannotUseSkills || (P_SKILL(P_RIDING) < P_EXPERT)) && (!Stone_resistance || (!IntStone_resistance && !rn2(20)) ) && !(uarmg && !FingerlessGloves && uarmu && uarm && uarmc) ) {
529 static char kbuf[BUFSZ];
531 You("touch %s.", mon_nam(mtmp));
532 sprintf(kbuf, "attempting to ride a petrifying monster");
533 instapetrify(kbuf);
535 if (!(mtmp->mtame || mtmp->egotype_steed || (FemtrapActiveLarissa && mtmp->data->msound == MS_SHOE) || canalwaysride(mtmp->data) || ((mercedesride(ART_GRAND_THEFT_AUTO, mtmp)) && (mtmp->data->msound == MS_CAR) ) || ((mercedesride(ART_UTTER_USELESSNESS, mtmp)) && (mtmp->data->msound == MS_FART_NORMAL || mtmp->data->msound == MS_FART_QUIET || mtmp->data->msound == MS_FART_LOUD || mtmp->data->msound == MS_STENCH || mtmp->data->msound == MS_SUPERMAN ) ) || (Race_if(PM_SHOE) && mtmp->data->msound == MS_SHOE)) || mtmp->isminion) {
536 pline("I think %s would mind.", mon_nam(mtmp));
537 return (FALSE);
539 if (mtmp->mtrapped) {
540 struct trap *t = t_at(mtmp->mx, mtmp->my);
542 You_cant("mount %s while %s's trapped in %s.",
543 mon_nam(mtmp), mhe(mtmp),
544 an(defsyms[trap_to_defsym(t->ttyp)].explanation));
545 return (FALSE);
548 if (!force && !(otmp && otmp->otyp == INKA_SADDLE) && !(FemtrapActiveSabrina && mtmp->data == &mons[PM_SABRINA_S_PLATEAU_BOOT]) && !(Role_if(PM_JOCKEY) && !rn2(5)) && !(uwep && uwep->oartifact == ART_DARK_CLAYMORE) && !Role_if(PM_KNIGHT) && !Role_if(PM_CHEVALIER) && mtmp->mtame && !(--mtmp->mtame)) {
549 /* no longer tame */
550 newsym(mtmp->mx, mtmp->my);
551 pline("%s resists%s!", Monnam(mtmp),
552 mtmp->mleashed ? " and its leash comes off" : "");
553 if (mtmp->mleashed) m_unleash(mtmp, FALSE);
554 return (FALSE);
556 if (!force && Underwater && !is_swimmer(ptr)) {
557 You_cant("ride that creature while under water.");
558 return (FALSE);
560 if (!can_saddle(mtmp) || !can_ride(mtmp)) {
561 if (!issoviet) You_cant("ride such a creature.");
562 else pline("Ublyudka, kotoryy nazyvayet sebya sovetskiy ne khochet, chtoby vy yezdit' eto sushchestvo.");
563 return (0);
566 /* Is the player impaired? */
567 if (!force && !is_floater(ptr) && !is_flyer(ptr) &&
568 Levitation && !Lev_at_will) {
569 You("cannot reach %s.", mon_nam(mtmp));
570 return (FALSE);
572 if (!force && !(otmp && otmp->otyp == INKA_SADDLE) && uarm && is_metallic(uarm) &&
573 greatest_erosionX(uarm)) {
574 Your("%s armor is too stiff to be able to mount %s.",
575 uarm->oeroded ? "rusty" : "corroded",
576 mon_nam(mtmp));
577 return (FALSE);
579 if (!force && !(otmp && otmp->otyp == INKA_SADDLE) && ((Confusion && !Conf_resist && rn2(3)) || (Fumbling && rn2(4)) || (IsGlib && rn2(2)) || (Wounded_legs && rn2(3)) ||
580 otmp->cursed || (GushLevel+mtmp->mtame < rnd(MAXULEV/2+5) && ( (!Role_if(PM_KNIGHT) || !rn2(5)) && (!Role_if(PM_CHEVALIER) || !rn2(5)) && (!Role_if(PM_JOCKEY) || !rn2(5)) && (!Role_if(PM_YEOMAN) || !rn2(5)) && ((!Role_if(PM_TRANSVESTITE) && !Role_if(PM_TOPMODEL)) || !rn2(5)) ) ) )) {
581 if (Levitation) {
582 pline("%s slips away from you.", Monnam(mtmp));
583 return FALSE;
585 You("slip while trying to get on %s.", mon_nam(mtmp));
587 sprintf(buf, "slipped while mounting a monster (%s)",
588 /* "a saddled mumak" or "a saddled pony called Dobbin" */
589 x_monnam(mtmp, ARTICLE_A, (char *)0,
590 SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION,
591 TRUE));
592 losehp(rn1(5,10), buf, NO_KILLER_PREFIX);
593 return (FALSE);
596 /* Success */
597 if (!force) {
598 if (Levitation && !is_floater(ptr) && !is_flyer(ptr))
599 /* Must have Lev_at_will at this point */
600 pline("%s magically floats up!", Monnam(mtmp));
601 You("mount %s.", mon_nam(mtmp));
603 if (nogoodsteed(mtmp)) pline("This creature is too weak to carry you.");
604 else if (dedicatedsteed(mtmp)) You_feel("comfortable.");
606 if (otmp && otmp->oartifact == ART_SADDLE_OF_REFLECTION) {
607 You("reflect upon your life choices when climbing the saddle.");
608 adjattrib(A_WIS, -1, FALSE, TRUE);
612 /* setuwep handles polearms differently when you're mounted */
613 if (uwep && is_applypole(uwep)) unweapon = FALSE;
614 u.usteed = mtmp;
615 remove_monster(mtmp->mx, mtmp->my);
616 teleds(mtmp->mx, mtmp->my, TRUE);
617 return (TRUE);
621 /* You and your steed have moved */
622 void
623 exercise_steed()
625 if (!u.usteed)
626 return;
628 /* It takes many turns of riding to exercise skill */
629 /* but not THAT godawfully many - used to be 100, now it's 33 --Amy */
630 if (u.urideturns++ >= 33) {
631 u.urideturns = 0;
632 use_skill(P_RIDING, 1);
634 return;
638 * Try to find a dismount point adjacent to the steed's location.
639 * If all else fails, try enexto(). Use enexto() as a last resort because
640 * enexto() chooses its point randomly, possibly even outside the
641 * room's walls, which is not what we want.
642 * Adapted from mail daemon code.
644 STATIC_OVL boolean
645 landing_spot(spot, reason, forceit)
646 coord *spot; /* landing position (we fill it in) */
647 int reason;
648 int forceit;
650 int i = 0, x, y, distance, min_distance = -1;
651 boolean found = FALSE;
652 struct trap *t;
654 /* avoid known traps (i == 0) and boulders, but allow them as a backup */
655 if (reason != DISMOUNT_BYCHOICE || Stunned || Numbed || Feared || Confusion || Fumbling) i = 1;
656 for (; !found && i < 2; ++i) {
657 for (x = u.ux-1; x <= u.ux+1; x++)
658 for (y = u.uy-1; y <= u.uy+1; y++) {
659 if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
661 if (ACCESSIBLE(levl[x][y].typ) &&
662 !MON_AT(x,y) && !closed_door(x,y)) {
663 distance = distu(x,y);
664 if (min_distance < 0 || distance < min_distance ||
665 (distance == min_distance && rn2(2))) {
666 if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen) &&
667 (!sobj_at(BOULDER, x, y) ||
668 throws_rocks(youmonst.data) || (uarmg && uarmg->oartifact == ART_MOUNTAIN_FISTS) ))) {
669 spot->x = x;
670 spot->y = y;
671 min_distance = distance;
672 found = TRUE;
679 /* If we didn't find a good spot and forceit is on, try enexto(). */
680 if (forceit && min_distance < 0 &&
681 !enexto(spot, u.ux, u.uy, youmonst.data))
682 return FALSE;
684 return found;
687 /* The player kicks or whips the steed */
688 void
689 kick_steed()
691 char He[4];
692 int gallopamount;
693 if (!u.usteed)
694 return;
696 /* [ALI] Various effects of kicking sleeping/paralyzed steeds */
697 if (u.usteed->msleeping || !u.usteed->mcanmove) {
698 /* We assume a message has just been output of the form
699 * "You kick <steed>."
701 strcpy(He, mhe(u.usteed));
702 *He = highc(*He);
703 if ((u.usteed->mcanmove || u.usteed->mfrozen) && !rn2(2)) {
704 if (u.usteed->mcanmove)
705 u.usteed->msleeping = 0;
706 else if (u.usteed->mfrozen > 2)
707 u.usteed->mfrozen -= 2;
708 else {
709 u.usteed->mfrozen = 0;
710 u.usteed->mcanmove = 1;
711 u.usteed->masleep = 0;
713 if (u.usteed->msleeping || !u.usteed->mcanmove)
714 pline("%s stirs.", He);
715 else
716 pline("%s rouses %sself!", He, mhim(u.usteed));
717 } else
718 pline("%s does not respond.", He);
719 return;
722 /* Make the steed less tame and check if it resists */
723 if (u.usteed->mtame && (!Role_if(PM_JOCKEY) || !rn2(3)) ) u.usteed->mtame--;
724 if (!u.usteed->mtame && u.usteed->mleashed) m_unleash(u.usteed, TRUE);
725 if (!u.usteed->mtame || (u.ulevel+u.usteed->mtame < rnd(MAXULEV/2+5))) {
727 if (!mayfalloffsteed()) {
728 newsym(u.usteed->mx, u.usteed->my);
729 dismount_steed(DISMOUNT_THROWN);
730 return;
734 pline("%s gallops!", Monnam(u.usteed));
735 /* here's another thing that should IMHO be better if you have more skill; in vanilla, high riding skill is
736 * borderline useless, but I decided that high skill will make your horse gallop for a loooooong time --Amy */
738 gallopamount = rn1(20, 30);
739 if (!PlayerCannotUseSkills) {
740 switch (P_SKILL(P_RIDING)) {
741 case P_SKILLED: gallopamount *= 2; break;
742 case P_EXPERT: gallopamount *= 4; break;
743 case P_MASTER: gallopamount *= 6; break;
744 case P_GRAND_MASTER: gallopamount *= 8; break;
745 case P_SUPREME_MASTER: gallopamount *= 10; break;
748 if (uarmf && uarmf->oartifact == ART_ARVOGENIA_S_BIKER_HEELS) gallopamount *= 2;
750 u.ugallop += gallopamount;
751 return;
754 /* Stop riding the current steed */
755 void
756 dismount_steed(reason)
757 int reason; /* Player was thrown off etc. */
759 struct monst *mtmp;
760 struct obj *otmp;
761 coord cc;
762 const char *verb = "fall";
763 boolean repair_leg_damage = TRUE;
764 unsigned save_utrap = u.utrap;
765 boolean have_spot = landing_spot(&cc,reason,0);
766 register struct trap *ttmp;
768 mtmp = u.usteed; /* make a copy of steed pointer */
769 /* Sanity check */
770 if (!mtmp) /* Just return silently */
771 return;
773 /* Check the reason for dismounting */
774 otmp = which_armor(mtmp, W_SADDLE);
775 switch (reason) {
776 case DISMOUNT_THROWN:
777 verb = "are thrown";
778 case DISMOUNT_FELL:
779 You("%s off of %s!", verb, mon_nam(mtmp));
780 if (!have_spot) have_spot = landing_spot(&cc,reason,1);
781 losehp(rn1(10,10), "riding accident", KILLED_BY_AN);
782 set_wounded_legs(BOTH_SIDES, HWounded_legs + (int)HWounded_legs + rn1(5,5));
783 repair_leg_damage = FALSE;
784 break;
785 case DISMOUNT_POLY:
786 You("can no longer ride %s.", mon_nam(u.usteed));
787 if (!have_spot) have_spot = landing_spot(&cc,reason,1);
788 break;
789 case DISMOUNT_ENGULFED:
790 /* caller displays message */
791 break;
792 case DISMOUNT_BONES:
793 /* hero has just died... */
794 break;
795 case DISMOUNT_GENERIC:
796 /* no messages, just make it so */
797 break;
798 case DISMOUNT_BYCHOICE:
799 default:
800 if (u.utrap && (ttmp = t_at(u.ux, u.uy)) && ttmp && ttmp->ttyp == FARTING_WEB) {
801 You("can't escape from the farting web.");
802 return;
804 if (otmp && otmp->cursed) {
805 You("can't. The saddle %s cursed.",
806 otmp->bknown ? "is" : "seems to be");
807 otmp->bknown = TRUE;
808 return;
810 if (!have_spot) {
811 You("can't. There isn't anywhere for you to stand.");
812 return;
814 if (!mtmp->mnamelth) {
815 pline("You've been through the dungeon on %s with no name.",
816 an(mtmp->data->mname));
817 if (FunnyHallu)
818 pline("It felt good to get out of the rain.");
819 } else
820 You("dismount %s.", mon_nam(mtmp));
822 if (otmp && otmp->otyp == INKA_SADDLE) {
823 pline("The inka saddle tries unsuccessfully to prevent you from getting off your steed, and rips off your skin in the process...");
824 pline("You and your steed are severely hurt!");
825 losehp(rnd(u.ulevel * 5), "inka saddle", KILLED_BY_AN);
826 if (mtmp && mtmp->mhp > 1) mtmp->mhp /= 2;
829 /* While riding these refer to the steed's legs
830 * so after dismounting they refer to the player's
831 * legs once again.
833 if (repair_leg_damage) HWounded_legs = 0;
835 /* Release the steed and saddle */
836 u.usteed = 0;
837 u.ugallop = 0L;
839 /* Set player and steed's position. Try moving the player first
840 unless we're in the midst of creating a bones file. */
841 if (reason == DISMOUNT_BONES) {
842 /* move the steed to an adjacent square */
843 if (enexto(&cc, u.ux, u.uy, mtmp->data))
844 rloc_to(mtmp, cc.x, cc.y);
845 else /* evidently no room nearby; move steed elsewhere */
846 (void) rloc(mtmp, FALSE);
847 return;
849 if (!DEADMONSTER(mtmp)) {
850 place_monster(mtmp, u.ux, u.uy);
851 if (!u.uswallow && !u.ustuck && have_spot) {
852 struct permonst *mdat = mtmp->data;
854 /* The steed may drop into water/lava */
855 if (!is_flyer(mdat) && (!mtmp->egotype_flying) && !is_floater(mdat) && !is_clinger(mdat)) {
856 if (is_waterypool(u.ux, u.uy) || is_watertunnel(u.ux, u.uy)) {
857 if (!Underwater)
858 pline("%s falls into the %s!", Monnam(mtmp),
859 surface(u.ux, u.uy));
860 if (!is_swimmer(mdat) && !mtmp->egotype_watersplasher && !amphibious(mdat)) {
861 killed(mtmp);
862 adjalign(-5);
864 } else if (is_lava(u.ux, u.uy)) {
865 pline("%s is pulled into the lava!", Monnam(mtmp));
866 if (!likes_lava(mdat)) {
867 killed(mtmp);
868 adjalign(-5);
872 /* Steed dismounting consists of two steps: being moved to another
873 * square, and descending to the floor. We have functions to do
874 * each of these activities, but they're normally called
875 * individually and include an attempt to look at or pick up the
876 * objects on the floor:
877 * teleds() --> spoteffects() --> pickup()
878 * float_down() --> pickup()
879 * We use this kludge to make sure there is only one such attempt.
881 * Clearly this is not the best way to do it. A full fix would
882 * involve having these functions not call pickup() at all, instead
883 * calling them first and calling pickup() afterwards. But it
884 * would take a lot of work to keep this change from having any
885 * unforseen side effects (for instance, you would no longer be
886 * able to walk onto a square with a hole, and autopickup before
887 * falling into the hole).
889 /* [ALI] No need to move the player if the steed died. */
890 if (!DEADMONSTER(mtmp)) {
891 /* Keep steed here, move the player to cc;
892 * teleds() clears u.utrap
894 in_steed_dismounting = TRUE;
895 teleds(cc.x, cc.y, TRUE);
896 in_steed_dismounting = FALSE;
898 /* Put your steed in your trap */
899 if (save_utrap)
900 (void) mintrap(mtmp);
902 /* Couldn't... try placing the steed */
903 } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) {
904 /* Keep player here, move the steed to cc */
905 rloc_to(mtmp, cc.x, cc.y);
906 /* Player stays put */
907 /* Otherwise, kill the steed */
908 } else {
909 killed(mtmp);
910 adjalign(-5);
914 /* Return the player to the floor */
915 if (reason != DISMOUNT_ENGULFED) {
916 in_steed_dismounting = TRUE;
917 (void) float_down(0L, W_SADDLE);
918 in_steed_dismounting = FALSE;
919 flags.botl = 1;
920 (void)encumber_msg();
921 vision_full_recalc = 1;
922 } else
923 flags.botl = 1;
924 /* polearms behave differently when not mounted */
925 if (uwep && is_pole(uwep)) unweapon = TRUE;
926 return;
929 void
930 place_monster(mon, x, y)
931 struct monst *mon;
932 int x, y;
934 if (!mon) {
935 impossible("place_monster: no monster?");
938 if (mon && mon == u.usteed ||
939 /* special case is for convoluted vault guard handling */
940 (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
941 /*impossible("placing bugged monster onto map?");*/
942 return;
944 mon->mx = x, mon->my = y;
945 level.monsters[x][y] = mon;
948 /* will something hit your steed instead of you? --Amy */
949 boolean
950 will_hit_steed()
952 /* if your steed is low on health, attacks should be redirected to it much less often, otherwise they die constantly */
953 if (u.usteed && (u.usteed->mhp < 5 || (u.usteed->mhp <= (u.usteed->mhpmax / 5) ) ) && rn2(5)) return FALSE;
955 if (u.usteed) {
957 if (bmwride(ART_NO_DAMAGE)) return FALSE;
961 if (rn2(100) < u.steedhitchance) return TRUE;
962 else return FALSE;
965 /* does your steed have the saddle that lets you fly? --Amy */
966 boolean
967 flysaddle()
969 if (u.usteed) {
971 if (bmwride(ART_CLOWN_CAR)) return TRUE;
974 return FALSE;
977 /*steed.c*/