Esempio n. 1
0
static boolean
dospellmenu(const char *prompt,
            int splaction,  /* SPELLMENU_CAST, SPELLMENU_VIEW, or
                               spl_book[] index */
            int *spell_no)
{
    int i, n, how, count = 0;
    struct nh_menuitem items[MAXSPELL + 1];
    const int *selected;

    set_menuitem(&items[count++], 0, MI_HEADING,
                 "Name\tLevel\tCategory\tFail\tMemory", 0, FALSE);
    for (i = 0; i < MAXSPELL; i++) {
        if (spellid(i) == NO_SPELL)
            continue;
        const char *buf = SPELL_IS_FROM_SPELLBOOK(i) ?
            msgprintf("%s\t%-d%s\t%s\t%-d%%\t%-d%%", spellname(i), spellev(i),
                      spellknow(i) ? " " : "*",
                      spelltypemnemonic(spell_skilltype(spellid(i))),
                      100 - percent_success(i),
                      (spellknow(i) * 100 + (KEEN - 1)) / KEEN) :
            msgprintf("%s\t--\t%s\t?\t--", spellname(i),
                      (spellid(i) == SPID_PRAY || spellid(i) == SPID_TURN) ?
                      "divine" : "ability");
        set_menuitem(&items[count++], i + 1, MI_NORMAL, buf,
                     spelllet_from_no(i), FALSE);
    }

    how = PICK_ONE;
    if (splaction >= 0)
        how = PICK_LETTER;      /* We're swapping spells. */

    n = display_menu(&(struct nh_menulist){.items = items, .icount = count},
Esempio n. 2
0
/*
 * Add SPID_* values to the player's spellbook, and remove those which are no
 * longer necessary.
 *
 * SPID_PRAY always exists;
 * SPID_TURN exists according to the player's role.
 *
 * The other three change dynamically:
 *
 * SPID_RLOC: on intrinsic/extrinsic change
 *            (requires Teleportation + xlvl 12, or 8 as a wizard; and/or
 *             Teleportation from polyform specifically)
 * SPID_JUMP: on intrinsic/extrinsic change (requires Jumping)
 * SPID_MONS: on polyform change
 *
 * Thus, we call this function:
 * - At character creation
 * - When levelling up
 * - When polymorphing
 * - When changing equipment
 * - When gaining/losing intrinsic teleportitis
 * This assumes that there's no source of Jumping or Teleportation on a
 * timeout; at present there isn't.
 */
void
update_supernatural_abilities(void)
{
    int i, j;

    /* Look through our spellbook for abilities we no longer have, and delete
       them. */
    for (i = 0; i < MAXSPELL; i++) {
        if (!SPELL_IS_FROM_SPELLBOOK(i) && spellid(i) &&
            !supernatural_ability_available(spellid(i))) {
            spl_book[i].sp_id = 0;
            spl_book[i].sp_know = 0;
            spl_book[i].sp_lev = 0;
        }
    }

    /* For each ability we have, look for it in our spellbook. If we can't find
       it there, assign a letter to it. We default to letters near the end of
       the alphabet, specific to each spell. We might have to use a different
       letter, though, if the one we want is already taken. */
    for (j = -1; j >= -SPID_COUNT; j--) {
        if (!supernatural_ability_available(j))
            continue;
        int best = -1;
        for (i = 0; i < MAXSPELL; i++) {
            /* Later letters are better than earlier ones, apart from the
               last SPID_COUNT which are worth avoiding if possible. Two
               exceptions trump everything: the letter where the spell already
               is; and the preferred letter. */
            if (spellid(i) == j)
                goto next_spid; /* multi-level continue */
            if (spellid(i) == NO_SPELL &&
                (i < MAXSPELL - SPID_COUNT || best == -1 ||
                 spelllet_from_no(i) == SPID_PREFERRED_LETTER[-1-j]))
                best = i;
        }
        if (best == -1)
            panic("too many spells + supernatural abilities");
        spl_book[best].sp_id = j;
        spl_book[best].sp_lev = 0;
        spl_book[best].sp_know = 0;
    next_spid:
        ;
    }
}
Esempio n. 3
0
File: scr.c Progetto: anylonen/omega
void menuspellprint(int i)
{
  int x,y;
  getyx(Menuw,y,x);
  if (y >= ScreenLength - 2) {
    wrefresh(Menuw);
    morewait();
    wclear(Menuw);
    touchwin(Menuw);
  }
  wprintw(Menuw,spellid(i));
  wprintw(Menuw,"(%d)\n",Spells[i].powerdrain);
}  
Esempio n. 4
0
static boolean
getargspell(const struct nh_cmd_arg *arg, int *spell_no)
{
    if (arg->argtype & CMD_ARG_SPELL) {
        char slet = arg->spelllet;
        int sno = spellno_from_let(slet);
        if (sno >= 0 && spellid(sno) != NO_SPELL) {
            *spell_no = sno;
            return TRUE;
        }
    }

    return getspell(spell_no);
}
Esempio n. 5
0
static const char *
spellname(int spell)
{
    int sid = spellid(spell);
    if (SPELL_IS_FROM_SPELLBOOK(spell))
        return OBJ_NAME(objects[sid]);
    else if (sid == SPID_PRAY)
        return "pray for help";
    else if (sid == SPID_TURN)
        return "turn undead";
    else if (sid == SPID_RLOC)
        return "teleportitis";
    else if (sid == SPID_JUMP)
        return "supernatural jump"; /* distinguish from the spell */
    else if (sid == SPID_MONS) {
        struct polyform_ability pa;
        if (has_polyform_ability(youmonst.data, &pa))
            return pa.description;
        panic("SPID_MONS is in spellbook, but #monster is invalid");
    }
    panic("Unknown spell number %d", sid);
}
Esempio n. 6
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;
}
Esempio n. 7
0
/* Handles one turn of book reading. Returns 1 if unfinished, 0 if finshed. */
static int
learn(void)
{
    int i;
    short booktype;
    boolean costly = TRUE;
    boolean already_known = FALSE;
    int first_unknown = MAXSPELL;
    int known_spells = 0;
    const char *splname;

    /* JDS: lenses give 50% faster reading; 33% smaller read time */
    if (u.uoccupation_progress[tos_book] &&
        ublindf && ublindf->otyp == LENSES && rn2(2))
        u.uoccupation_progress[tos_book]++;
    if (Confusion) {    /* became confused while learning */
        confused_book(u.utracked[tos_book]);
        u.utracked[tos_book] = 0;       /* no longer studying */
        helpless(-u.uoccupation_progress[tos_book], hr_busy,
                 "absorbed in a spellbook",
                 "You're finally able to put the book down.");
        u.uoccupation_progress[tos_book] = 0;
        return 0;
    }

    booktype = u.utracked[tos_book]->otyp;
    if (booktype == SPE_BOOK_OF_THE_DEAD) {
        deadbook(u.utracked[tos_book], FALSE);
        u.utracked[tos_book] = 0;
        u.uoccupation_progress[tos_book] = 0;
        return 0;
    }

    /* The book might get cursed while we're reading it. In this case,
       immediately stop reading it, cancel progress, and apply a few turns of
       helplessness. (3.4.3 applies negative spellbook effects but lets you
       memorize the spell anyway; this makes no sense. It destroys the spellbook
       on the "contact poison" result, which makes even less sense.) */
    if (u.utracked[tos_book]->cursed) {
        pline("This book isn't making sense any more.");
        helpless(rn1(5,5), hr_busy,
                 "making sense of a spellbook",
                 "You give up trying to make sense of the spellbook.");
        u.uoccupation_progress[tos_book] = 0;
        u.utracked[tos_book] = 0;
        return 0;
    }

    if (++u.uoccupation_progress[tos_book] < 0)
        return 1;       /* still busy */

    if (ACURR(A_WIS) < 12)
        exercise(A_WIS, TRUE); /* you're studying. */

    splname = msgprintf(objects[booktype].oc_name_known ?
                        "\"%s\"" : "the \"%s\" spell",
                        OBJ_NAME(objects[booktype]));
    for (i = 0; i < MAXSPELL; i++) {
        if (spellid(i) == booktype) {
            already_known = TRUE;
            if (u.utracked[tos_book]->spestudied > MAX_SPELL_STUDY) {
                pline("This spellbook is too faint to be read any more.");
                u.utracked[tos_book]->otyp = booktype = SPE_BLANK_PAPER;
            } else if (spellknow(i) <= 1000) {
                pline("Your knowledge of %s is keener.", splname);
                incrnknow(i);
                u.utracked[tos_book]->spestudied++;
                if (ACURR(A_WIS) < 12)
                    exercise(A_WIS, TRUE); /* extra study */
            } else {    /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */
                pline("You know %s quite well already.", splname);
                if (yn("Do you want to read the book anyway?") == 'y') {
                    pline("You refresh your knowledge of %s.", splname);
                    incrnknow(i);
                    u.utracked[tos_book]->spestudied++;
                } else
                    costly = FALSE;
            }
            /* make book become known even when spell is already known, in case
               amnesia made you forget the book */
            makeknown((int)booktype);
            break;
        } else if (spellid(i) == NO_SPELL &&
                   (i < first_unknown ||
                    i == spellno_from_let(objects[booktype].oc_defletter)))
            first_unknown = i;
        else
            known_spells++;
    }

    if (first_unknown == MAXSPELL && !already_known)
        panic("Too many spells memorized!");

    if (!already_known) {
        spl_book[first_unknown].sp_id = booktype;
        spl_book[first_unknown].sp_lev = objects[booktype].oc_level;
        incrnknow(first_unknown);
        u.utracked[tos_book]->spestudied++;
        pline(known_spells > 0 ? "You add %s to your repertoire." :
              "You learn %s.", splname);
        makeknown((int)booktype);
    }

    if (costly)
        check_unpaid(u.utracked[tos_book]);
    u.utracked[tos_book] = 0;
    return 0;
}