int doride(const struct nh_cmd_arg *arg) { boolean forcemount = FALSE; schar dx, dy, dz; if (u.usteed) dismount_steed(DISMOUNT_BYCHOICE); else if (getargdir(arg, NULL, &dx, &dy, &dz) && isok(u.ux + dx, u.uy + dy)) { if (wizard && yn("Force the mount to succeed?") == 'y') forcemount = TRUE; return mount_steed(m_at(level, u.ux + dx, u.uy + dy), forcemount); } else return 0; return 1; }
int doidtrap(const struct nh_cmd_arg *arg) { struct trap *trap; int x, y, tt; schar dx, dy, dz; if (!getargdir(arg, NULL, &dx, &dy, &dz)) return 0; x = u.ux + dx; y = u.uy + dy; for (trap = level->lev_traps; trap; trap = trap->ntrap) if (trap->tx == x && trap->ty == y) { if (!trap->tseen) break; tt = trap->ttyp; if (dz) { if (dz < 0 ? (tt == TRAPDOOR || tt == HOLE) : tt == ROCKTRAP) break; } /* This command is CMD_NOTIME, pick the RNG accordingly */ tt = what_trap(tt, x, y, rn2_on_display_rng); pline("That is %s%s%s.", an(trapexplain[tt - 1]), !trap->madeby_u ? "" : (tt == WEB) ? " woven" : /* trap doors & spiked pits can't be made by player, and should be considered at least as much "set" as "dug" anyway */ (tt == HOLE || tt == PIT) ? " dug" : " set", !trap->madeby_u ? "" : " by you"); return 0; } pline("I can't see a trap there."); return 0; }
int dotalk(const struct nh_cmd_arg *arg) { struct monst *mtmp; int tx, ty; struct obj *otmp; schar dx; schar dy; schar dz; if (!getargdir(arg, NULL, &dx, &dy, &dz)) { /* decided not to chat */ return 0; } if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(youmonst.data->mname)); return 0; } if (Strangled) { pline("You can't speak. You're choking!"); return 0; } if (Engulfed) { pline("They won't hear you out there."); return 0; } if (Underwater) { pline("Your speech is unintelligible underwater."); return 0; } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != NULL) { /* standing on something in a shop and chatting causes the shopkeeper to describe the price(s). This can inhibit other chatting inside a shop, but that shouldn't matter much. shop_object() returns an object iff inside a shop and the shopkeeper is present and willing (not angry) and able (not asleep) to speak and the position contains any objects other than just gold. */ price_quote(otmp); return 1; } if (u.usteed && dz > 0) { if (!u.usteed->mcanmove || u.usteed->msleeping) { pline("Your steed remains silent..."); return 0; } return domonnoise(u.usteed); } if (dz) { pline("They won't hear you %s there.", dz < 0 ? "up" : "down"); return 0; } if (dx == 0 && dy == 0) { if (u.umonnum == PM_ETTIN) { pline("You discover that your other head makes boring conversation."); return 0; } pline("Talking to yourself is a bad habit for a dungeoneer."); return 0; } tx = u.ux + dx; ty = u.uy + dy; if (!isok(tx, ty)) { pline("You call out into the abyss, but nobody hears you."); return 0; } mtmp = m_at(level, tx, ty); /* Do we try to close a door on the square? We do if a) the square is known by the player to be a doorway, b) there's no invisible-I marker there, c) there's no monster in a chattable state there. */ if (!mtmp || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { int membg = level->locations[tx][ty].mem_bg; if (membg == S_vodoor || membg == S_vcdoor || membg == S_ndoor || membg == S_hodoor || membg == S_hcdoor) { if (!level->locations[tx][ty].mem_invis) { struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); return doclose(&newarg); } } pline("You start talking, but nobody seems to hear you."); return 0; } /* sleeping monsters won't talk, except priests (who wake up) */ if ((!mtmp->mcanmove || mtmp->msleeping) && !mtmp->ispriest) { /* If it is unseen, the player can't tell the difference between not noticing him and just not existing, so skip the message. */ if (canspotmon(mtmp)) pline("%s seems not to notice you.", Monnam(mtmp)); else pline("You start talking, but nobody seems to hear you."); return 0; } /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (mtmp->mtame && mtmp->meating) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); pline("%s is eating noisily.", Monnam(mtmp)); return 0; } return domonnoise(mtmp); }
/* 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; }
/* pick a lock on a chest or door with a given object */ int pick_lock(struct obj *pick, const struct nh_cmd_arg *arg) { int picktyp, c; coord cc; schar dx, dy, dz; struct rm *door; struct obj *otmp; const char *qbuf; 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; picktyp = pick->otyp; pick->lastused = moves; /* Check whether we're resuming an interrupted previous attempt. For a floor pick, we have u.utracked[tos_lock] as a non-zeroobj and dx and dy as 0. For a door, we have u.utracked_location[tl_lock] specifying the location and u.utracked[tos_lock] as &zeroobj. */ if (u.uoccupation_progress[tos_lock] && ((u.utracked_location[tl_lock].x == cc.x && u.utracked_location[tl_lock].y == cc.y && u.utracked[tos_lock] == &zeroobj) || (dx == 0 && dy == 0 && u.utracked[tos_lock] != &zeroobj))) { static const char no_longer[] = "Unfortunately, you can no longer %s %s."; if (nohands(youmonst.data)) { const char *what = (picktyp == LOCK_PICK) ? "pick" : "key"; if (picktyp == CREDIT_CARD) what = "card"; pline(msgc_interrupted, no_longer, "hold the", what); return reset_pick(); } else if (u.utracked[tos_lock] != &zeroobj && !can_reach_floor()) { pline(msgc_interrupted, no_longer, "reach the", "lock"); return reset_pick(); } else { const char *action = lock_action(); if (turnstate.continue_message) pline(msgc_occstart, "You resume your attempt at %s.", action); one_occupation_turn(picklock, "picking the lock", occ_lock); return 1; } } if (nohands(youmonst.data)) { pline(msgc_cancelled, "You can't hold %s -- you have no hands!", doname(pick)); return 0; } if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD && picktyp != SKELETON_KEY)) { impossible("picking lock with object %d?", picktyp); return 0; } if (!dx && !dy) { /* pick lock on a container */ const char *verb; boolean it; int count; if (dz < 0) { pline(msgc_cancelled, "There isn't any sort of lock up %s.", Levitation ? "here" : "there"); return 0; } else if (is_lava(level, youmonst.mx, youmonst.my)) { pline(msgc_cancelled, "Doing that would probably melt your %s.", xname(pick)); return 0; } else if (is_pool(level, youmonst.mx, youmonst.my) && !Underwater) { /* better YAFM - AIS */ pline(msgc_cancelled, "Canals might have locks, but this water doesn't."); return 0; } count = 0; c = 'n'; /* in case there are no boxes here */ for (otmp = level->objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { ++count; if (!can_reach_floor()) { pline(msgc_cancelled, "You can't reach %s from up here.", the(xname(otmp))); return 0; } it = 0; if (otmp->obroken) verb = "fix"; else if (!otmp->olocked) verb = "lock", it = 1; else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; else verb = "pick"; qbuf = msgprintf( "There is %s here, %s %s?", safe_qbuf("", sizeof ("There is here, unlock its lock?"), doname(otmp), an(simple_typename(otmp->otyp)), "a box"), verb, it ? "it" : "its lock"); c = ynq(qbuf); if (c == 'q') return 0; if (c == 'n') continue; if (otmp->obroken) { pline(msgc_cancelled, "You can't fix its broken lock with %s.", doname(pick)); return 0; } else if (picktyp == CREDIT_CARD && !otmp->olocked) { /* credit cards are only good for unlocking */ pline(msgc_cancelled, "You can't do that with %s.", doname(pick)); return 0; } u.utracked[tos_lock] = otmp; u.uoccupation_progress[tos_lock] = 0; break; } if (c != 'y') { if (!count) pline(msgc_cancelled, "There doesn't seem to be any sort of lock here."); return 0; /* decided against all boxes */ } } else { /* pick the lock in a door */ struct monst *mtmp; if (u.utrap && u.utraptype == TT_PIT) { pline(msgc_cancelled, "You can't reach over the edge of the pit."); return 0; } door = &level->locations[cc.x][cc.y]; if ((mtmp = m_at(level, cc.x, cc.y)) && canseemon(mtmp)) { if (picktyp == CREDIT_CARD && (mx_eshk(mtmp) || mtmp->data == &mons[PM_ORACLE])) verbalize(msgc_npcvoice, "No checks, no credit, no problem."); else pline(msgc_mispaste, "I don't think %s would appreciate that.", mon_nam(mtmp)); return 0; } if (mtmp && (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; } if (!IS_DOOR(door->typ)) { if (is_drawbridge_wall(cc.x, cc.y) >= 0) pline(msgc_cancelled, "You %s no lock on the drawbridge.", Blind ? "feel" : "see"); else pline(msgc_mispaste, "You %s no door there.", Blind ? "feel" : "see"); return 0; } switch (door->doormask) { case D_NODOOR: pline(msgc_cancelled, "This doorway has no door."); return 0; case D_ISOPEN: pline(msgc_cancelled, "You cannot lock an open door."); return 0; case D_BROKEN: pline(msgc_cancelled, "This door is broken."); return 0; default: /* credit cards are only good for unlocking */ if (picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) { pline(msgc_cancelled, "You can't lock a door with a credit card."); return 0; } /* At this point, the player knows that the door is a door, and whether it's locked, but not whether it's trapped; to do this, we set the mem_door_l flag and call map_background, which will clear it if necessary (i.e. not a door after all). */ level->locations[cc.x][cc.y].mem_door_l = 1; map_background(cc.x, cc.y, TRUE); u.utracked[tos_lock] = &zeroobj; u.utracked_location[tl_lock] = cc; u.uoccupation_progress[tos_lock] = 0; } } one_occupation_turn(picklock, "picking the lock", occ_lock); return 1; }
int spelleffects(int spell, boolean atme, const struct nh_cmd_arg *arg) { int energy, damage, chance, n, intell; int skill, role_skill; boolean confused = (Confusion != 0); struct obj *pseudo; boolean dummy; coord cc; schar dx = 0, dy = 0, dz = 0; if (!SPELL_IS_FROM_SPELLBOOK(spell)) { /* At the moment, we implement this via calling the code for the shortcut command. Eventually, it would make sense to invert this (and make the shortcut commands wrappers for spelleffects). */ switch (spellid(spell)) { case SPID_PRAY: return dopray(arg); case SPID_TURN: return doturn(arg); case SPID_RLOC: return dotele(arg); case SPID_JUMP: return dojump(arg); case SPID_MONS: return domonability(arg); default: impossible("Unknown spell number %d?", spellid(spell)); return 0; } } /* * Find the skill the hero has in a spell type category. * See spell_skilltype for categories. */ skill = spell_skilltype(spellid(spell)); role_skill = P_SKILL(skill); /* Get the direction or target, if applicable. We want to do this *before* determining spell success, both for interface consistency and to cut down on needless mksobj calls. */ switch (spellid(spell)) { /* These spells ask the user to target a specific space. */ case SPE_CONE_OF_COLD: case SPE_FIREBALL: /* If Skilled or better, get a specific space. */ if (role_skill >= P_SKILLED) { if (throwspell(&dx, &dy, arg)) { dz = 0; break; } else { /* Decided not to target anything. Abort the spell. */ pline("Spell canceled."); return 0; } } /* If not Skilled, fall through. */ /* These spells ask the user to target a direction. */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (atme) dx = dy = dz = 0; else if (!getargdir(arg, NULL, &dx, &dy, &dz)) { /* getdir cancelled, abort */ pline("Spell canceled."); return 0; } break; case SPE_JUMPING: if(!get_jump_coords(arg, &cc, max(role_skill, 1))) { /* No jumping after all, I guess. */ pline("Spell canceled."); return 0; } break; /* The rest of the spells don't have targeting. */ default: break; } /* Spell casting no longer affects knowledge of the spell. A decrement of spell knowledge is done every turn. */ if (spellknow(spell) <= 0) { pline("Your knowledge of this spell is twisted."); pline("It invokes nightmarish images in your mind..."); spell_backfire(spell); return 0; } else if (spellknow(spell) <= 200) { /* 1% */ pline("You strain to recall the spell."); } else if (spellknow(spell) <= 1000) { /* 5% */ pline("Your knowledge of this spell is growing faint."); } energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */ if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { pline("You are too hungry to cast that spell."); return 0; } else if (ACURR(A_STR) < 4) { pline("You lack the strength to cast spells."); return 0; } else if (check_capacity ("Your concentration falters while carrying so much stuff.")) { return 1; } else if (!freehand()) { pline("Your arms are not free to cast!"); return 0; } if (Uhave_amulet) { pline("You feel the amulet draining your energy away."); energy += rnd(2 * energy); } if (energy > u.uen) { pline("You don't have enough energy to cast that spell."); return 0; } else { if (spellid(spell) != SPE_DETECT_FOOD) { int hungr = energy * 2; /* * If hero is a wizard, their current intelligence * (bonuses + temporary + current) * affects hunger reduction in casting a spell. * 1. int = 17-18 no reduction * 2. int = 16 1/4 hungr * 3. int = 15 1/2 hungr * 4. int = 1-14 normal reduction * The reason for this is: * a) Intelligence affects the amount of exertion * in thinking. * b) Wizards have spent their life at magic and * understand quite well how to cast spells. */ intell = acurr(A_INT); if (!Role_if(PM_WIZARD)) intell = 10; if (intell >= 17) hungr = 0; else if (intell == 16) hungr /= 4; else if (intell == 15) hungr /= 2; /* don't put player (quite) into fainting from casting a spell, particularly since they might not even be hungry at the beginning; however, this is low enough that they must eat before casting anything else except detect food */ if (hungr > u.uhunger - 3) hungr = u.uhunger - 3; morehungry(hungr); } } chance = percent_success(spell); if (confused || (rnd(100) > chance)) { pline("You fail to cast the spell correctly."); u.uen -= energy / 2; return 1; } u.uen -= energy; /* pseudo is a temporary "false" object containing the spell stats */ pseudo = mktemp_sobj(level, spellid(spell)); pseudo->blessed = pseudo->cursed = 0; pseudo->quan = 20L; /* do not let useup get it */ switch (pseudo->otyp) { /* * At first spells act as expected. As the hero increases in skill * with the appropriate spell type, some spells increase in their * effects, e.g. more damage, further distance, and so on, without * additional cost to the spellcaster. */ case SPE_CONE_OF_COLD: case SPE_FIREBALL: if (role_skill >= P_SKILLED) { cc.x = dx; cc.y = dy; n = rnd(8) + 1; while (n--) { if (!dx && !dy && !dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) losehp(damage, msgprintf( "zapped %sself with an exploding spell", uhim())); } else { explode(dx, dy, pseudo->otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1 + spell_damage_bonus(), 0, (pseudo->otyp == SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY, NULL, 0); } dx = cc.x + rnd(3) - 2; dy = cc.y + rnd(3) - 2; if (!isok(dx, dy) || !cansee(dx, dy) || IS_STWALL(level->locations[dx][dy].typ) || Engulfed) { /* Spell is reflected back to center */ dx = cc.x; dy = cc.y; } } break; } /* else fall through... */ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_LIGHT: case SPE_DETECT_UNSEEN: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (objects[pseudo->otyp].oc_dir != NODIR) { if (!dx && !dy && !dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { losehp(damage, msgprintf("zapped %sself with a spell", uhim())); } } else weffects(pseudo, dx, dy, dz); } else weffects(pseudo, 0, 0, 0); update_inventory(); /* spell may modify inventory */ break; /* these are all duplicates of scroll effects */ case SPE_REMOVE_CURSE: case SPE_CONFUSE_MONSTER: case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: case SPE_IDENTIFY: seffects(pseudo, &dummy); break; /* these are all duplicates of potion effects */ case SPE_HASTE_SELF: case SPE_DETECT_TREASURE: case SPE_DETECT_MONSTERS: case SPE_LEVITATION: case SPE_RESTORE_ABILITY: /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_INVISIBILITY: peffects(pseudo); break; case SPE_CURE_BLINDNESS: healup(0, 0, FALSE, TRUE); break; case SPE_CURE_SICKNESS: if (Sick) pline("You are no longer ill."); if (Slimed) { pline("The slime disappears!"); Slimed = 0; } healup(0, 0, TRUE, FALSE); break; case SPE_CREATE_FAMILIAR: make_familiar(NULL, u.ux, u.uy, FALSE); break; case SPE_CLAIRVOYANCE: if (!BClairvoyant) do_vicinity_map(); /* at present, only one thing blocks clairvoyance */ else if (uarmh && uarmh->otyp == CORNUTHAUM) pline("You sense a pointy hat on top of your %s.", body_part(HEAD)); break; case SPE_PROTECTION: cast_protection(); break; case SPE_JUMPING: jump_to_coords(&cc); break; default: impossible("Unknown spell %d attempted.", spell); obfree(pseudo, NULL); return 0; } /* gain skill for successful cast */ use_skill(skill, spellev(spell)); obfree(pseudo, NULL); /* now, get rid of it */ return 1; }
/* The player is trying to extract something from his/her instrument. */ static int do_improvisation(struct obj *instr, const struct nh_cmd_arg *arg) { int do_spec = !Confusion; if (!do_spec) pline(msgc_yafm, "What you produce is quite far from music..."); else pline(msgc_occstart, "You start playing %s.", the(xname(instr))); switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "You produce soft music."); put_monsters_to_sleep(youmonst.m_lev * 5); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); if (do_spec) charm_snakes(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case FROST_HORN: /* Idem wand of cold */ case FIRE_HORN: /* Idem wand of fire */ if (do_spec && instr->spe > 0) { schar dx, dy, dz; consume_obj_charge(instr, TRUE); if (!getargdir(arg, NULL, &dx, &dy, &dz)) { pline(msgc_yafm, "%s.", Tobjnam(instr, "vibrate")); break; } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, rn1(6, 6), youmonst.mx, youmonst.my, dx, dy, 0); } makeknown(instr->otyp); break; } /* else FALLTHRU */ case TOOLED_HORN: /* Awaken or scare monsters */ pline(msgc_actionok, "You produce a frightful, grave sound."); awaken_monsters(&youmonst, youmonst.m_lev * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ pline(msgc_actionok, "You extract a loud noise from %s.", the(xname(instr))); awaken_soldiers(&youmonst); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_actionok, "%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((youmonst.m_lev - 1) / 3 + 1); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + youmonst.m_lev > 25); pline(do_spec ? msgc_actionok : msgc_failrandom, "%s %s.", The(xname(instr)), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(youmonst.m_lev * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline(msgc_occstart, "You produce a heavy, thunderous rolling!"); pline_implied(msgc_occstart, "The entire dungeon is shaking around you!"); do_earthquake((youmonst.m_lev - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(&youmonst, ROWNO * COLNO); makeknown(DRUM_OF_EARTHQUAKE); break; } /* else FALLTHRU */ case LEATHER_DRUM: /* Awaken monsters */ pline(msgc_actionok, "You beat a deafening row!"); awaken_monsters(&youmonst, youmonst.m_lev * 40); exercise(A_WIS, FALSE); break; default: impossible("What a weird instrument (%d)!", instr->otyp); break; } return 2; /* That takes time */ }
int use_saddle(struct obj *otmp, const struct nh_cmd_arg *arg) { struct monst *mtmp; const struct permonst *ptr; int chance; const char *s; schar dx, dy, dz; /* Can you use it? */ if (nohands(youmonst.data)) { pline("You have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { pline("You have no free %s.", body_part(HAND)); return 0; } /* Select an animal */ if (Engulfed || Underwater || !getargdir(arg, NULL, &dx, &dy, &dz)) { pline("Never mind."); return 0; } if (!dx && !dy) { pline("Saddle yourself? Very funny..."); return 0; } if (!isok(u.ux + dx, u.uy + dy) || !((mtmp = m_at(level, u.ux + dx, u.uy + dy))) || !canspotmon(mtmp)) { if (knownwormtail(u.ux + dx, u.uy + dy)) pline("It's hard to strap a saddle to a tail."); else pline("I see nobody there."); return 0; } /* Is this a valid monster? */ if (mtmp->misc_worn_check & W_MASK(os_saddle) || which_armor(mtmp, os_saddle)) { pline("%s doesn't need another one.", Monnam(mtmp)); return 0; } ptr = mtmp->data; if (!uarmg && touched_monster(ptr - mons)) { pline("You touch %s.", mon_nam(mtmp)); instapetrify(killer_msg(STONING, msgcat("attempting to saddle ", an(mtmp->data->mname)))); } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; } if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || mtmp->isgd || mtmp->iswiz) { pline("I think %s would mind.", mon_nam(mtmp)); return 0; } if (!can_saddle(mtmp)) { pline("You can't saddle such a creature."); return 0; } /* Calculate your chance */ chance = ACURR(A_DEX) + ACURR(A_CHA) / 2 + 2 * mtmp->mtame; chance += u.ulevel * (mtmp->mtame ? 20 : 5); if (!mtmp->mtame) chance -= 10 * mtmp->m_lev; if (Role_if(PM_KNIGHT)) chance += 20; switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: default: chance -= 20; break; case P_BASIC: break; case P_SKILLED: chance += 15; break; case P_EXPERT: chance += 30; break; } if (Confusion || Fumbling || Glib) chance -= 20; else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != NULL && !strncmp(s, "riding ", 7)) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) chance -= 50; /* steed becomes alert if possible */ maybewakesteed(mtmp); /* Make the attempt */ if (rn2(100) < chance) { pline("You put the saddle on %s.", mon_nam(mtmp)); if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ mpickobj(mtmp, otmp); mtmp->misc_worn_check |= W_MASK(os_saddle); otmp->owornmask = W_MASK(os_saddle); otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; }