/* Can we ride this monster? Caller should also check can_saddle() */ boolean can_ride(struct monst * mtmp) { return (mtmp->mtame && humanoid(youmonst.data) && !verysmall(youmonst.data) && !bigmonst(youmonst.data) && (!Underwater || is_swimmer(mtmp->data))); }
/* Wear the best object of each type that the monster has. During creation, * the monster can put everything on at once; otherwise, wearing takes time. * This doesn't affect monster searching for objects--a monster may very well * search for objects it would not want to wear, because we don't want to * check which_armor() each round. * * We'll let monsters put on shirts and/or suits under worn cloaks, but * not shirts under worn suits. This is somewhat arbitrary, but it's * too tedious to have them remove and later replace outer garments, * and preventing suits under cloaks makes it a little bit too easy for * players to influence what gets worn. Putting on a shirt underneath * already worn body armor is too obviously buggy... */ void m_dowear(struct monst *mon, boolean creation) { #define RACE_EXCEPTION TRUE /* Note the restrictions here are the same as in dowear in do_wear.c * except for the additional restriction on intelligence. (Players * are always intelligent, even if polymorphed). */ if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data)) return; /* give mummies a chance to wear their wrappings * and let skeletons wear their initial armor */ if (mindless(mon->data) && (!creation || (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON]))) return; m_dowear_type(mon, W_AMUL, creation, FALSE); /* can't put on shirt if already wearing suit */ if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM)) m_dowear_type(mon, W_ARMU, creation, FALSE); /* treating small as a special case allows hobbits, gnomes, and kobolds to wear cloaks */ if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL) m_dowear_type(mon, W_ARMC, creation, FALSE); m_dowear_type(mon, W_ARMH, creation, FALSE); if (!MON_WEP(mon) || !bimanual(MON_WEP(mon))) m_dowear_type(mon, W_ARMS, creation, FALSE); m_dowear_type(mon, W_ARMG, creation, FALSE); if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR) m_dowear_type(mon, W_ARMF, creation, FALSE); if (!cantweararm(mon->data)) m_dowear_type(mon, W_ARM, creation, FALSE); else m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION); }
/* true iff the type of monster pass through iron bars */ boolean passes_bars(const struct permonst * mptr) { return (boolean) (passes_walls(mptr) || amorphous(mptr) || is_whirly(mptr) || verysmall(mptr) || (slithy(mptr) && !bigmonst(mptr))); }
void mon_break_armor(struct monst *mon, boolean polyspot) { struct obj *otmp; const struct permonst *mdat = mon->data; boolean vis = cansee(mon->mx, mon->my); boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat)); const char *pronoun = mhim(mon), *ppronoun = mhis(mon); if (breakarm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if ((Is_dragon_scales(otmp) && mdat == Dragon_scales_to_pm(otmp)) || (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp))) ; /* no message here; "the dragon merges with his scaly armor" is odd and the monster's previous form is already gone */ else if (vis) pline("%s breaks out of %s armor!", Monnam(mon), ppronoun); else You_hear("a cracking sound."); m_useup(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (otmp->oartifact) { if (vis) pline("%s %s falls off!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } else { if (vis) pline("%s %s tears apart!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else You_hear("a ripping sound."); m_useup(mon, otmp); } } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) pline("%s shirt rips to shreds!", s_suffix(Monnam(mon))); else You_hear("a ripping sound."); m_useup(mon, otmp); } } else if (sliparm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if (vis) pline("%s armor falls around %s!", s_suffix(Monnam(mon)), pronoun); else You_hear("a thud."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s %s falls, unsupported!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else pline("%s shrinks out of %s %s!", Monnam(mon), ppronoun, cloak_simple_name(otmp)); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) { if (sliparm(mon->data)) pline("%s seeps right through %s shirt!", Monnam(mon), ppronoun); else pline("%s becomes much too small for %s shirt!", Monnam(mon), ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny) { /* [caller needs to handle weapon checks] */ if ((otmp = which_armor(mon, W_ARMG)) != 0) { if (vis) pline("%s drops %s gloves%s!", Monnam(mon), ppronoun, MON_WEP(mon) ? " and weapon" : ""); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMS)) != 0) { if (vis) pline("%s can no longer hold %s shield!", Monnam(mon), ppronoun); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || has_horns(mdat)) { if ((otmp = which_armor(mon, W_ARMH)) != 0 && /* flimsy test for horns matches polyself handling */ (handless_or_tiny || !is_flimsy(otmp))) { if (vis) pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) { if ((otmp = which_armor(mon, W_ARMF)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s boots fall away!", s_suffix(Monnam(mon))); else pline("%s boots %s off %s feet!", s_suffix(Monnam(mon)), verysmall(mdat) ? "slide" : "are pushed", ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (!can_saddle(mon)) { if ((otmp = which_armor(mon, W_SADDLE)) != 0) { if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); if (vis) pline("%s saddle falls off.", s_suffix(Monnam(mon))); } if (mon == u.usteed) goto noride; } else if (mon == u.usteed && !can_ride(mon)) { noride: pline("You can no longer ride %s.", mon_nam(mon)); if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; pline("You touch %s.", mon_nam(u.usteed)); sprintf(buf, "falling off %s", an(u.usteed->data->mname)); instapetrify(buf); } dismount_steed(DISMOUNT_FELL); } return; }
struct obj * mksobj(int otyp, boolean init, boolean artif) { int mndx, tryct; struct obj *otmp; char let = objects[otyp].oc_class; otmp = newobj(0); *otmp = zeroobj; otmp->age = monstermoves; otmp->o_id = flags.ident++; if (!otmp->o_id) otmp->o_id = flags.ident++; /* ident overflowed */ otmp->quan = 1L; otmp->oclass = let; otmp->otyp = otyp; otmp->where = OBJ_FREE; otmp->dknown = index(dknowns, let) ? 0 : 1; if (otmp->otyp == AMULET_OF_YENDOR) otmp->orecursive = FALSE; if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) || otmp->otyp == SHIELD_OF_REFLECTION) otmp->dknown = 0; if (!objects[otmp->otyp].oc_uses_known) otmp->known = 1; if (is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp)) otmp->rknown = 1; #ifdef INVISIBLE_OBJECTS otmp->oinvis = !rn2(1250); #endif if (init) switch (let) { case WEAPON_CLASS: otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L; if(!rn2(11)) { otmp->spe = rne(3); otmp->blessed = rn2(2); } else if(!rn2(10)) { curse(otmp); otmp->spe = -rne(3); } else blessorcurse(otmp, 10); if (is_poisonable(otmp) && !rn2(100)) otmp->opoisoned = 1; if (artif && !rn2(20)) otmp = mk_artifact(otmp, (aligntyp)A_NONE); break; case FOOD_CLASS: otmp->odrained = 0; otmp->oeaten = 0; switch(otmp->otyp) { case CORPSE: /* possibly overridden by mkcorpstat() */ tryct = 50; do otmp->corpsenm = undead_to_corpse(rndmonnum()); while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0)); if (tryct == 0) { /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on this level; let's create an adventurer's corpse instead, then */ otmp->corpsenm = PM_HUMAN; } /* timer set below */ break; case EGG: otmp->corpsenm = NON_PM; /* generic egg */ if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) { mndx = can_be_hatched(rndmonnum()); if (mndx != NON_PM && !dead_species(mndx, TRUE)) { otmp->corpsenm = mndx; /* typed egg */ attach_egg_hatch_timeout(otmp); break; } } break; case TIN: otmp->corpsenm = NON_PM; /* empty (so far) */ if (!rn2(6)) otmp->spe = 1; /* spinach */ else for (tryct = 200; tryct > 0; --tryct) { mndx = undead_to_corpse(rndmonnum()); if (mons[mndx].cnutrit && !(mvitals[mndx].mvflags & G_NOCORPSE)) { otmp->corpsenm = mndx; break; } } blessorcurse(otmp, 10); break; case SLIME_MOLD: otmp->spe = current_fruit; break; case KELP_FROND: otmp->quan = (long) rnd(2); break; } if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING || otmp->otyp == KELP_FROND) break; /* fall into next case */ case GEM_CLASS: if (otmp->otyp == LOADSTONE) curse(otmp); else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6); else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L; else otmp->quan = 1L; break; case TOOL_CLASS: switch(otmp->otyp) { case TALLOW_CANDLE: case WAX_CANDLE: otmp->spe = 1; otmp->age = 20L * /* 400 or 200 */ (long)objects[otmp->otyp].oc_cost; otmp->lamplit = 0; otmp->quan = 1L + (long)(rn2(2) ? rn2(7) : 0); blessorcurse(otmp, 5); break; case BRASS_LANTERN: case OIL_LAMP: otmp->spe = 1; otmp->age = (long) rn1(500,1000); otmp->lamplit = 0; blessorcurse(otmp, 5); break; case MAGIC_LAMP: otmp->spe = 1; otmp->lamplit = 0; blessorcurse(otmp, 2); break; case IRON_SAFE: otmp->olocked = 1; case CHEST: case LARGE_BOX: if (otmp->otyp != IRON_SAFE) { otmp->olocked = !!(rn2(5)); /* clumsy tweak */ } otmp->otrapped = !(rn2(10)); case ICE_BOX: case SACK: case OILSKIN_SACK: case BAG_OF_HOLDING: mkbox_cnts(otmp); break; #ifdef TOURIST case EXPENSIVE_CAMERA: #endif case TINNING_KIT: case MAGIC_MARKER: otmp->spe = rn1(60,20); break; case CAN_OF_GREASE: otmp->spe = rnd(25); blessorcurse(otmp, 10); break; case CRYSTAL_BALL: otmp->spe = rnd(5); blessorcurse(otmp, 2); break; case HORN_OF_PLENTY: case BAG_OF_TRICKS: otmp->spe = rnd(20); break; case FIGURINE: { int tryct2 = 0; do otmp->corpsenm = rndmonnum(); while(is_human(&mons[otmp->corpsenm]) && tryct2++ < 30); blessorcurse(otmp, 4); break; } case BELL_OF_OPENING: otmp->spe = 3; break; case MAGIC_FLUTE: case MAGIC_HARP: case FROST_HORN: case FIRE_HORN: case DRUM_OF_EARTHQUAKE: otmp->spe = rn1(5,4); break; } break; case AMULET_CLASS: if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE; if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == AMULET_OF_CHANGE || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { curse(otmp); } else blessorcurse(otmp, 10); case VENOM_CLASS: case CHAIN_CLASS: case BALL_CLASS: break; case POTION_CLASS: if (otmp->otyp == POT_OIL) otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ /* fall through */ case SCROLL_CLASS: #ifdef MAIL if (otmp->otyp != SCR_MAIL) #endif blessorcurse(otmp, 4); break; case SPBOOK_CLASS: blessorcurse(otmp, 17); break; case ARMOR_CLASS: if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS || otmp->otyp == LEVITATION_BOOTS || otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT || otmp->otyp == GAUNTLETS_OF_FUMBLING || otmp->otyp == TINFOIL_HAT || !rn2(11))) { curse(otmp); otmp->spe = -rne(3); } else if(!rn2(10)) { otmp->blessed = rn2(2); otmp->spe = rne(3); } else blessorcurse(otmp, 10); if (artif && !rn2(40)) otmp = mk_artifact(otmp, (aligntyp)A_NONE); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (moves <= 1 || In_quest(&u.uz))) { #ifdef UNIXPC /* optimizer bitfield bug */ otmp->oerodeproof = 1; otmp->rknown = 1; #else otmp->oerodeproof = otmp->rknown = 1; #endif } break; case WAND_CLASS: if (otmp->otyp == WAN_WISHING) { otmp->spe = (rnf(2,3) ? 1 : rnf(1,2) ? 0 : 2); otmp->recharged = 1; } else { otmp->spe = rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); otmp->recharged = 0; /* used to control recharging */ } blessorcurse(otmp, 17); break; case RING_CLASS: if(objects[otmp->otyp].oc_charged) { blessorcurse(otmp, 3); if(rn2(10)) { if(rn2(10) && bcsign(otmp)) otmp->spe = bcsign(otmp) * rne(3); else otmp->spe = rn2(2) ? rne(3) : -rne(3); } /* make useless +0 rings much less common */ if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3); /* negative rings are usually cursed */ if (otmp->spe < 0 && rn2(5)) curse(otmp); } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION || otmp->otyp == RIN_POLYMORPH || otmp->otyp == RIN_AGGRAVATE_MONSTER || otmp->otyp == RIN_HUNGER || !rn2(9))) { curse(otmp); } break; case ROCK_CLASS: switch (otmp->otyp) { case STATUE: /* possibly overridden by mkcorpstat() */ otmp->corpsenm = rndmonnum(); if (!verysmall(&mons[otmp->corpsenm]) && rn2(level_difficulty()/2 + 10) > 10) (void) add_to_container(otmp, mkobj(SPBOOK_CLASS,FALSE)); } break; case COIN_CLASS: break; /* do nothing */ default: warning("impossible mkobj %d, sym '%c'.", otmp->otyp, objects[otmp->otyp].oc_class); return (struct obj *)0; } /* Some things must get done (timers) even if init = 0 */ switch (otmp->otyp) { case CORPSE: start_corpse_timeout(otmp); break; } /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) otmp = mk_artifact(otmp, (aligntyp)A_NONE); otmp->owt = weight(otmp); return(otmp); }
static void break_armor(void) { struct obj *otmp; if (breakarm(youmonst.data)) { if ((otmp = uarm) != 0) { if (donning(otmp)) cancel_don(); pline("You break out of your armor!"); exercise(A_STR, FALSE); Armor_gone(); useup(otmp); } if ((otmp = uarmc) != 0) { if (otmp->oartifact) { pline("Your %s falls off!", cloak_simple_name(otmp)); Cloak_off(); dropx(otmp); } else { pline("Your %s tears apart!", cloak_simple_name(otmp)); Cloak_off(); useup(otmp); } } if (uarmu) { pline("Your shirt rips to shreds!"); useup(uarmu); } } else if (sliparm(youmonst.data)) { if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) { if (donning(otmp)) cancel_don(); pline("Your armor falls around you!"); Armor_gone(); dropx(otmp); } if ((otmp = uarmc) != 0) { if (is_whirly(youmonst.data)) pline("Your %s falls, unsupported!", cloak_simple_name(otmp)); else pline("You shrink out of your %s!", cloak_simple_name(otmp)); Cloak_off(); dropx(otmp); } if ((otmp = uarmu) != 0) { if (is_whirly(youmonst.data)) pline("You seep right through your shirt!"); else pline("You become much too small for your shirt!"); setworn(NULL, otmp->owornmask & W_ARMU); dropx(otmp); } } if (has_horns(youmonst.data)) { if ((otmp = uarmh) != 0) { if (is_flimsy(otmp) && !donning(otmp)) { char hornbuf[BUFSZ], yourbuf[BUFSZ]; /* Future possiblities: This could damage/destroy helmet */ sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data))); pline("Your %s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"), shk_your(yourbuf, otmp), xname(otmp)); } else { if (donning(otmp)) cancel_don(); pline("Your helmet falls to the %s!", surface(u.ux, u.uy)); Helmet_off(); dropx(otmp); } } } if (nohands(youmonst.data) || verysmall(youmonst.data)) { if ((otmp = uarmg) != 0) { if (donning(otmp)) cancel_don(); /* Drop weapon along with gloves */ pline("You drop your gloves%s!", uwep ? " and weapon" : ""); drop_weapon(0); Gloves_off(); dropx(otmp); } if ((otmp = uarms) != 0) { pline("You can no longer hold your shield!"); Shield_off(); dropx(otmp); } if ((otmp = uarmh) != 0) { if (donning(otmp)) cancel_don(); pline("Your helmet falls to the %s!", surface(u.ux, u.uy)); Helmet_off(); dropx(otmp); } } if (nohands(youmonst.data) || verysmall(youmonst.data) || slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) { if ((otmp = uarmf) != 0) { if (donning(otmp)) cancel_don(); if (is_whirly(youmonst.data)) pline("Your boots fall away!"); else pline("Your boots %s off your feet!", verysmall(youmonst.data) ? "slide" : "are pushed"); Boots_off(); dropx(otmp); } } }
/* try to close a door */ int doclose(const struct nh_cmd_arg *arg) { struct rm *door; struct monst *mtmp; coord cc; schar dx, dy, dz; if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't close anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; cc.x = youmonst.mx + dx; cc.y = youmonst.my + dy; if (!isok(cc.x, cc.y)) return 0; if ((cc.x == youmonst.mx) && (cc.y == youmonst.my)) { pline(msgc_cancelled1, "You are in the way!"); return 1; } if ((mtmp = m_at(level, cc.x, cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp, dx, dy); return 1; } door = &level->locations[cc.x][cc.y]; if (!IS_DOOR(door->typ)) { if (door->typ == DRAWBRIDGE_DOWN) pline(msgc_cancelled, "There is no obvious way to close the drawbridge."); else pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } if (door->doormask == D_NODOOR) { pline(msgc_cancelled, "This doorway has no door."); return 0; } if (obstructed(cc.x, cc.y, msgc_cancelled)) return 0; if (door->doormask == D_BROKEN) { pline(msgc_cancelled, "This door is broken."); return 0; } if (door->doormask & (D_CLOSED | D_LOCKED)) { pline(msgc_cancelled, "This door is already closed."); return 0; } if (door->doormask == D_ISOPEN) { if (verysmall(youmonst.data) && !u.usteed) { pline(msgc_cancelled, "You're too small to push the door closed."); return 0; } if (u.usteed || rn2(25) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline(msgc_actionok, "The door closes."); door->doormask = D_CLOSED; door->mem_door_l = 1; /* map_background here sets the mem_door flags correctly; and it's redundant to both feel_location and newsym with a door. Exception: if we remember an invisible monster on the door square, but in this case, we want to set the memory of a door there anyway because we know there's a door there because we just closed it, and in Nitro this doesn't clash with keeping the I there. */ map_background(cc.x, cc.y, TRUE); if (Blind) feel_location(cc.x, cc.y); /* the hero knows she closed it */ else newsym(cc.x, cc.y); block_point(cc.x, cc.y); /* vision: no longer see there */ } else { exercise(A_STR, TRUE); pline(msgc_failrandom, "The door resists!"); } } return 1; }
/* try to open a door */ int doopen(const struct nh_cmd_arg *arg) { coord cc; struct rm *door; struct monst *mtmp; schar dx, dy, dz; if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't open, close, or unlock anything " "-- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; cc.x = youmonst.mx + dx; cc.y = youmonst.my + dy; if (!isok(cc.x, cc.y)) return 0; if ((cc.x == youmonst.mx) && (cc.y == youmonst.my)) return 0; if ((mtmp = m_at(level, cc.x, cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp, cc.x - youmonst.mx, cc.y - youmonst.my); return 1; } door = &level->locations[cc.x][cc.y]; if (!IS_DOOR(door->typ)) { if (is_db_wall(cc.x, cc.y)) { pline(msgc_cancelled, "There is no obvious way to open the drawbridge."); return 0; } pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } if (door->doormask == D_ISOPEN) { struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); return doclose(&newarg); } if (!(door->doormask & D_CLOSED)) { const char *mesg; switch (door->doormask) { case D_BROKEN: mesg = " is broken"; break; case D_NODOOR: mesg = "way has no door"; break; case D_ISOPEN: mesg = " is already open"; break; default: if (last_command_was("open") && door->mem_door_l) { /* With the "open" command given explicitly (rather than implicitly via doorbumping), unlock the door. */ struct obj *bestpick = get_current_unlock_tool(); struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); if (!bestpick) pline(msgc_cancelled, "You have nothing to unlock that with."); else if (!bestpick->lastused) /* not msgc_controlhelp, or many players would get no message */ pline(msgc_hint, "Use an unlocking tool manually so I know " "which one you want to use."); else return pick_lock(bestpick, &newarg); } door->mem_door_l = 1; map_background(cc.x, cc.y, TRUE); mesg = " is locked"; break; } pline(msgc_cancelled, "This door%s.", mesg); if (Blind) feel_location(cc.x, cc.y); return 0; } if (verysmall(youmonst.data)) { pline(msgc_cancelled, "You're too small to pull the door open."); return 0; } /* door is known to be CLOSED */ if (rnl(20) < (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3) { pline(msgc_actionok, "The door opens."); if (door->doormask & D_TRAPPED) { b_trapped("door", FINGER); door->doormask = D_NODOOR; if (*in_rooms(level, cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); } else door->doormask = D_ISOPEN; if (Blind) feel_location(cc.x, cc.y); /* the hero knows she opened it */ else newsym(cc.x, cc.y); unblock_point(cc.x, cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); door->mem_door_l = 1; map_background(cc.x, cc.y, TRUE); pline(msgc_failrandom, "The door resists!"); } return 1; }
/* * Move for priests and shopkeepers. Called from shk_move() and pri_move(). * Valid returns are 1: moved 0: didn't -1: let m_move do it -2: died. */ int move_special(struct monst *mtmp, boolean in_his_shop, schar appr, boolean uondoor, boolean avoid, xchar omx, xchar omy, xchar gx, xchar gy) { xchar nx, ny, nix, niy; schar i; schar chcnt, cnt; coord poss[9]; long info[9]; long allowflags; struct obj *ib = NULL; if (omx == gx && omy == gy) return 0; if (mtmp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; if (mtmp->isshk) allowflags = ALLOW_SSM; else allowflags = ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; cnt = mfndpos(mtmp, poss, info, allowflags); if (mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) goto pick_move; avoid = FALSE; } #define GDIST(x,y) (dist2(x,y,gx,gy)) pick_move: chcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (IS_ROOM(level->locations[nx][ny].typ) || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) { if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rn2(++chcnt)) || (appr && GDIST(nx, ny) < GDIST(nix, niy))) { nix = nx; niy = ny; } } } if (mtmp->ispriest && avoid && nix == omx && niy == omy && onlineu(omx, omy)) { /* might as well move closer as long it's going to stay lined up */ avoid = FALSE; goto pick_move; } if (nix != omx || niy != omy) { remove_monster(level, omx, omy); place_monster(mtmp, nix, niy); newsym(nix, niy); if (mtmp->isshk && !in_his_shop && inhishop(mtmp)) check_special_room(FALSE); if (ib) { if (cansee(mtmp->mx, mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), distant_name(ib, doname)); obj_extract_self(ib); mpickobj(mtmp, ib); } return 1; } return 0; }
/* Start riding, with the given monster */ boolean mount_steed(struct monst * mtmp, /* The animal */ boolean force) { /* Quietly force this animal */ struct obj *otmp; const struct permonst *ptr; /* Sanity checks */ if (u.usteed) { pline("You are already riding %s.", mon_nam(u.usteed)); return FALSE; } /* Is the player in the right form? */ if (Hallucination && !force) { pline("Maybe you should find a designated driver."); return FALSE; } /* While riding Wounded_legs refers to the steed's, not the hero's legs. That opens up a potential abuse where the player can mount a steed, then dismount immediately to heal leg damage, because leg damage is always healed upon dismount (Wounded_legs context switch). By preventing a hero with Wounded_legs from mounting a steed, the potential for abuse is minimized, if not eliminated altogether. */ if (Wounded_legs) { pline("Your %s are in no shape for riding.", makeplural(body_part(LEG))); if (force && wizard && yn("Heal your legs?") == 'y') LWounded_legs = RWounded_legs = 0; else return FALSE; } if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) || bigmonst(youmonst.data) || slithy(youmonst.data))) { pline("You won't fit on a saddle."); return FALSE; } if (!force && (near_capacity() > SLT_ENCUMBER)) { pline("You can't do that while carrying so much stuff."); return FALSE; } /* Can the player reach and see the monster? */ if (!mtmp || (!force && ((Blind && !Blind_telepat) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT))) { pline("I see nobody there."); return FALSE; } struct test_move_cache cache; init_test_move_cache(&cache); if (Engulfed || u.ustuck || u.utrap || Punished || !test_move(u.ux, u.uy, mtmp->mx - u.ux, mtmp->my - u.uy, 0, TEST_MOVE, &cache)) { if (Punished || !(Engulfed || u.ustuck || u.utrap)) pline("You are unable to swing your %s over.", body_part(LEG)); else pline("You are stuck here for now."); return FALSE; } /* Is this a valid monster? */ otmp = which_armor(mtmp, os_saddle); if (!otmp) { pline("%s is not saddled.", Monnam(mtmp)); return FALSE; } ptr = mtmp->data; if (touch_petrifies(ptr) && !Stone_resistance) { pline("You touch %s.", mon_nam(mtmp)); instapetrify(killer_msg(STONING, msgcat("attempting to ride ", an(mtmp->data->mname)))); } if (!mtmp->mtame || mtmp->isminion) { pline("I think %s would mind.", mon_nam(mtmp)); return FALSE; } if (mtmp->mtrapped) { struct trap *t = t_at(level, mtmp->mx, mtmp->my); pline("You can't mount %s while %s's trapped in %s.", mon_nam(mtmp), mhe(mtmp), t ? an(trapexplain[t->ttyp - 1]) : "ice"); return FALSE; } if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) { /* no longer tame */ newsym(mtmp->mx, mtmp->my); pline("%s resists%s!", Monnam(mtmp), mtmp->mleashed ? " and its leash comes off" : ""); if (mtmp->mleashed) m_unleash(mtmp, FALSE); return FALSE; } if (!force && Underwater && !is_swimmer(ptr)) { pline("You can't ride that creature while under water."); return FALSE; } if (!can_saddle(mtmp) || !can_ride(mtmp)) { pline("You can't ride such a creature."); return 0; } /* Is the player impaired? */ if (!force && !is_floater(ptr) && !is_flyer(ptr) && Levitation && !Lev_at_will) { pline("You cannot reach %s.", mon_nam(mtmp)); return FALSE; } if (!force && uarm && is_metallic(uarm) && greatest_erosion(uarm)) { pline("Your %s armor is too stiff to be able to mount %s.", uarm->oeroded ? "rusty" : "corroded", mon_nam(mtmp)); return FALSE; } if (!force && (Confusion || Fumbling || Glib || Wounded_legs || otmp->cursed || ((u.ulevel + mtmp->mtame < rnd(MAXULEV / 2 + 5)) && (!Role_if(PM_KNIGHT))))) { if (Levitation) { pline("%s slips away from you.", Monnam(mtmp)); return FALSE; } pline("You slip while trying to get on %s.", mon_nam(mtmp)); const char *buf = msgcat( "slipped while mounting ", /* "a saddled mumak" or "a saddled pony called Dobbin" */ x_monnam(mtmp, ARTICLE_A, NULL, SUPPRESS_IT | SUPPRESS_INVISIBLE | SUPPRESS_HALLUCINATION, TRUE)); losehp(rn1(5, 10), buf); return FALSE; } /* Success */ maybewakesteed(mtmp); if (!force) { if (Levitation && !is_floater(ptr) && !is_flyer(ptr)) /* Must have Lev_at_will at this point */ pline("%s magically floats up!", Monnam(mtmp)); pline("You mount %s.", mon_nam(mtmp)); } /* setuwep handles polearms differently when you're mounted */ if (uwep && is_pole(uwep)) u.bashmsg = TRUE; u.usteed = mtmp; remove_monster(level, mtmp->mx, mtmp->my); teleds(mtmp->mx, mtmp->my, TRUE); return TRUE; }
static void break_armor (void) { struct obj *otmp; if (breakarm(youmonst.data)) { if ((otmp = uarm) != 0) { if (donning(otmp)) cancel_don(); You("break out of your armor!"); exercise(A_STR, false); (void) Armor_gone(); useup(otmp); } if ((otmp = uarmc) != 0) { if(otmp->oartifact) { Your("%s falls off!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } else { Your("%s tears apart!", cloak_simple_name(otmp)); (void) Cloak_off(); useup(otmp); } } if (uarmu) { Your("shirt rips to shreds!"); useup(uarmu); } } else if (sliparm(youmonst.data)) { if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) { if (donning(otmp)) cancel_don(); Your("armor falls around you!"); (void) Armor_gone(); dropx(otmp); } if ((otmp = uarmc) != 0) { if (is_whirly(youmonst.data)) Your("%s falls, unsupported!", cloak_simple_name(otmp)); else You("shrink out of your %s!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } if ((otmp = uarmu) != 0) { if (is_whirly(youmonst.data)) You("seep right through your shirt!"); else You("become much too small for your shirt!"); setworn((struct obj *)0, otmp->owornmask & W_ARMU); dropx(otmp); } } if (has_horns(youmonst.data)) { if ((otmp = uarmh) != 0) { if (is_flimsy(otmp) && !donning(otmp)) { /* Future possiblities: This could damage/destroy helmet */ message_object(MSG_YOUR_HORNS_PIERCE_O, otmp); } else { if (donning(otmp)) cancel_don(); Your("helmet falls to the %s!", surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } } if (nohands(youmonst.data) || verysmall(youmonst.data)) { if ((otmp = uarmg) != 0) { if (donning(otmp)) cancel_don(); /* Drop weapon along with gloves */ You("drop your gloves%s!", uwep ? " and weapon" : ""); drop_weapon(0); (void) Gloves_off(); dropx(otmp); } if ((otmp = uarms) != 0) { You("can no longer hold your shield!"); (void) Shield_off(); dropx(otmp); } if ((otmp = uarmh) != 0) { if (donning(otmp)) cancel_don(); Your("helmet falls to the %s!", surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } if (nohands(youmonst.data) || verysmall(youmonst.data) || slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) { if ((otmp = uarmf) != 0) { if (donning(otmp)) cancel_don(); if (is_whirly(youmonst.data)) Your("boots fall away!"); else Your("boots %s off your feet!", verysmall(youmonst.data) ? "slide" : "are pushed"); (void) Boots_off(); dropx(otmp); } } }