Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
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);
}
Exemple #4
0
/* 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;
}
Exemple #5
0
/* 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;
}
Exemple #6
0
/* 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;
}
Exemple #7
0
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;
}
Exemple #8
0
/* 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 */
}
Exemple #9
0
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;
}