summaryrefslogtreecommitdiff
path: root/src/powers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/powers.cc')
-rw-r--r--src/powers.cc1220
1 files changed, 1220 insertions, 0 deletions
diff --git a/src/powers.cc b/src/powers.cc
new file mode 100644
index 00000000..f3ffe668
--- /dev/null
+++ b/src/powers.cc
@@ -0,0 +1,1220 @@
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "powers.hpp"
+
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "cmd1.hpp"
+#include "cmd2.hpp"
+#include "cmd7.hpp"
+#include "dungeon_flag.hpp"
+#include "feature_flag.hpp"
+#include "feature_type.hpp"
+#include "files.hpp"
+#include "game.hpp"
+#include "hooks.hpp"
+#include "mimic.hpp"
+#include "monster2.hpp"
+#include "monster3.hpp"
+#include "monster_race.hpp"
+#include "monster_race_flag.hpp"
+#include "monster_type.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "spells1.hpp"
+#include "spells2.hpp"
+#include "stats.hpp"
+#include "tables.hpp"
+#include "util.hpp"
+#include "util.h"
+#include "variable.h"
+#include "variable.hpp"
+#include "xtra2.hpp"
+#include "z-rand.hpp"
+
+/*
+ * Note: return value indicates the amount of mana to use
+ */
+static bool_ power_chance(power_type *x_ptr)
+{
+ bool_ use_hp = FALSE;
+ int diff = x_ptr->diff;
+
+ /* Always true ? */
+ if (!x_ptr->cost) return TRUE;
+
+ /* Not enough mana - use hp */
+ if (p_ptr->csp < x_ptr->cost) use_hp = TRUE;
+
+ /* Power is not available yet */
+ if (p_ptr->lev < x_ptr->level)
+ {
+ msg_format("You need to attain level %d to use this power.", x_ptr->level);
+ energy_use = 0;
+ return (FALSE);
+ }
+
+ /* Too confused */
+ else if (p_ptr->confused)
+ {
+ msg_print("You are too confused to use this power.");
+ energy_use = 0;
+ return (FALSE);
+ }
+
+ /* Risk death? */
+ else if (use_hp && (p_ptr->chp < x_ptr->cost))
+ {
+ if (!(get_check("Really use the power in your weakened state? ")))
+ {
+ energy_use = 0;
+ return (FALSE);
+ }
+ }
+
+ /* Else attempt to do it! */
+
+ if (p_ptr->stun)
+ {
+ diff += p_ptr->stun;
+ }
+ else if (p_ptr->lev > x_ptr->level)
+ {
+ int lev_adj = ((p_ptr->lev - x_ptr->level) / 3);
+ if (lev_adj > 10) lev_adj = 10;
+ diff -= lev_adj;
+ }
+
+ if (diff < 5) diff = 5;
+
+ /* take time and pay the price */
+ if (use_hp)
+ {
+ take_hit(((x_ptr->cost / 2) + (randint(x_ptr->cost / 2))),
+ "concentrating too hard");
+ }
+ else
+ {
+ p_ptr->csp -= (x_ptr->cost / 2 ) + (randint(x_ptr->cost / 2));
+ }
+ energy_use = 100;
+
+ /* Redraw mana and hp */
+ p_ptr->redraw |= (PR_FRAME);
+
+ /* Window stuff */
+ p_ptr->window |= (PW_PLAYER);
+
+ /* Success? */
+ if (randint(p_ptr->stat_cur[x_ptr->stat]) >=
+ ((diff / 2) + randint(diff / 2)))
+ {
+ return (TRUE);
+ }
+
+ flush_on_failure();
+ msg_print("You've failed to concentrate hard enough.");
+
+ return (FALSE);
+}
+
+static void power_activate(int power)
+{
+ auto const &f_info = game->edit_data.f_info;
+ auto const &k_info = game->edit_data.k_info;
+
+ s16b plev = p_ptr->lev;
+ char ch = 0;
+ int amber_power = 0;
+ int dir = 0, dummy;
+ object_type *q_ptr;
+ object_type forge;
+ int ii = 0, ij = 0;
+ /* char out_val[80]; */
+ /* cptr p = "Power of the flame: "; */
+ cptr q, s;
+ power_type *x_ptr = &powers_type[power], x_ptr_foo;
+ int x, y;
+ cave_type *c_ptr;
+
+ /* Break goi/manashield */
+ if (p_ptr->invuln)
+ {
+ set_invuln(0);
+ }
+ if (p_ptr->disrupt_shield)
+ {
+ set_disrupt_shield(0);
+ }
+
+
+ if (!power_chance(x_ptr)) return;
+
+ switch (power)
+ {
+ case PWR_BALROG:
+ {
+ set_mimic(p_ptr->lev / 2, resolve_mimic_name("Balrog"), p_ptr->lev);
+ }
+ break;
+ case PWR_BEAR:
+ {
+ set_mimic(150 + (p_ptr->lev * 10) , resolve_mimic_name("Bear"), p_ptr->lev);
+ }
+ break;
+ case PWR_COMPANION:
+ {
+ if (!can_create_companion())
+ {
+ msg_print("You cannot have more companions.");
+ }
+ else
+ {
+ monster_type *m_ptr;
+ int ii, jj;
+
+ msg_print("Select the friendly monster:");
+ if (!tgt_pt(&ii, &jj)) return;
+
+ if (cave[jj][ii].m_idx)
+ {
+ m_ptr = &m_list[cave[jj][ii].m_idx];
+
+ if (m_ptr->status != MSTATUS_PET)
+ {
+ msg_print("You cannot convert this monster.");
+ return;
+ }
+
+ m_ptr->status = MSTATUS_COMPANION;
+ }
+ }
+ }
+ break;
+ case PWR_MAGIC_MAP:
+ {
+ msg_print("You sense the world around you.");
+ map_area();
+ }
+ break;
+
+ case PWR_PASSWALL:
+ {
+ if (!get_aim_dir(&dir))
+ break;
+ if (passwall(dir, TRUE))
+ msg_print("A passage opens, and you step through.");
+ else
+ msg_print("There is no wall there!");
+ }
+ break;
+
+ case PWR_COOK_FOOD:
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Create the item */
+ object_prep(q_ptr, 21);
+
+ /* Drop the object from heaven */
+ drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
+ msg_print("You cook some food.");
+ }
+ break;
+
+ case PWR_UNFEAR:
+ {
+ msg_print("You play tough.");
+ set_afraid(0);
+ }
+ break;
+
+ case PWR_BERSERK:
+ {
+ msg_print("RAAAGH!");
+ set_afraid(0);
+
+ set_shero(p_ptr->shero + 10 + randint(plev));
+ hp_player(30);
+ }
+ break;
+
+ case PWR_EXPL_RUNE:
+ {
+ msg_print("You carefully set an explosive rune...");
+ explosive_rune();
+ }
+ break;
+
+ case PWR_STM:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You bash at a stone wall.");
+ wall_to_mud(dir);
+ }
+ break;
+
+ case PWR_ROHAN:
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("Use [F]lash aura or [L]ight speed jump? ", &ch))
+ {
+ amber_power = 0;
+ break;
+ }
+
+ if (ch == 'F' || ch == 'f')
+ {
+ amber_power = 1;
+ break;
+ }
+
+ if (ch == 'L' || ch == 'l')
+ {
+ amber_power = 2;
+ break;
+ }
+ }
+
+ if (amber_power == 1)
+ {
+ x_ptr_foo.level = 1;
+ x_ptr_foo.cost = 9;
+ x_ptr_foo.stat = A_CHR;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (!(get_aim_dir(&dir))) break;
+ msg_print("You flash a bright aura.");
+ if (p_ptr->lev < 10)
+ fire_bolt(GF_CONFUSION, dir, plev*2);
+ else
+ fire_ball(GF_CONFUSION, dir, plev*2, 2);
+ }
+ }
+ if (amber_power == 2)
+ {
+ x_ptr_foo.level = 30;
+ x_ptr_foo.cost = 30;
+ x_ptr_foo.stat = A_WIS;
+ x_ptr_foo.diff = 7;
+ if (power_chance(&x_ptr_foo))
+ {
+ set_light_speed(p_ptr->lightspeed + 3);
+ }
+ }
+ break;
+
+
+ case PWR_POIS_DART:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You throw a dart of poison.");
+ fire_bolt(GF_POIS, dir, plev);
+ }
+ break;
+
+ case PWR_DETECT_TD:
+ {
+ msg_print("You examine your surroundings.");
+ detect_doors(DEFAULT_RADIUS);
+ detect_stairs(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_MAGIC_MISSILE:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_print("You cast a magic missile.");
+ fire_bolt_or_beam(10, GF_MISSILE, dir,
+ damroll(3 + ((plev - 1) / 5), 4));
+ }
+ break;
+
+ case PWR_THUNDER:
+ /* Select power to use */
+ while (TRUE)
+ {
+ if (!get_com("Use [T]hunder strike, [R]ide the straight road, go [B]ack in town? ", &ch))
+ {
+ amber_power = 0;
+ break;
+ }
+
+ if (ch == 'T' || ch == 't')
+ {
+ amber_power = 1;
+ break;
+ }
+
+ if (ch == 'R' || ch == 'r')
+ {
+ amber_power = 2;
+ break;
+ }
+
+ if (ch == 'B' || ch == 'b')
+ {
+ amber_power = 3;
+ break;
+ }
+
+ }
+
+ if (amber_power == 1)
+ {
+ x_ptr_foo.level = 1;
+ x_ptr_foo.cost = p_ptr->lev;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_format("You conjure up thunder!");
+ fire_beam(GF_ELEC, dir, p_ptr->lev * 2);
+ fire_beam(GF_SOUND, dir, p_ptr->lev * 2);
+ p_ptr->energy -= 100;
+ }
+ }
+ if (amber_power == 2)
+ {
+ if (dungeon_flags & DF_NO_TELEPORT)
+ {
+ msg_print("No teleport on special levels ...");
+ break;
+ }
+ x_ptr_foo.level = 3;
+ x_ptr_foo.cost = 15;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ msg_print("You enter the straight road and fly beside the world. Where to exit?");
+ if (!tgt_pt(&ii, &ij)) return;
+ p_ptr->energy -= 60 - plev;
+ if (!cave_empty_bold(ij, ii) || (cave[ij][ii].info & CAVE_ICKY) ||
+ (distance(ij, ii, p_ptr->py, p_ptr->px) > plev*20 + 2) || !(cave[ij][ii].info & CAVE_MARK))
+ {
+ msg_print("You fail to exit correctly!");
+ p_ptr->energy -= 100;
+ teleport_player(10);
+ }
+ else teleport_player_to(ij, ii);
+ }
+
+ }
+ if (amber_power == 3)
+ {
+ if (dungeon_flags & DF_NO_TELEPORT)
+ {
+ msg_print("No recall on special levels..");
+ break;
+ }
+ x_ptr_foo.level = 7;
+ x_ptr_foo.cost = 30;
+ x_ptr_foo.stat = A_CON;
+ x_ptr_foo.diff = 6;
+ if (power_chance(&x_ptr_foo))
+ {
+ if (dun_level == 0)
+ msg_print("You are already in town!");
+ else
+ {
+ msg_print("You enter the straight road and fly beside the world.");
+ p_ptr->energy -= 100;
+ p_ptr->word_recall = 1;
+ }
+ }
+ }
+ break;
+
+ case PWR_GROW_TREE:
+ {
+ msg_print("You make the trees grow!");
+ grow_trees((plev / 8 < 1) ? 1 : plev / 8);
+ }
+ break;
+
+ case PWR_DEATHMOLD:
+ do_cmd_immovable_special();
+ break;
+
+ case PWR_BR_COLD:
+ {
+ msg_print("You breathe cold...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_COLD, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_BR_CHAOS:
+ {
+ msg_print("You breathe chaos...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_CHAOS, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_BR_ELEM:
+ {
+ if (!get_aim_dir(&dir)) break;
+ msg_format("You breathe the elements.");
+ fire_ball(GF_MISSILE, dir, (p_ptr->lev)*2,
+ ((p_ptr->lev) / 15) + 1);
+ }
+ break;
+
+ case PWR_SUMMON_MONSTER:
+ {
+ do_cmd_beastmaster();
+ }
+ break;
+
+ case PWR_WRECK_WORLD:
+ msg_print("The power of Eru Iluvatar flows through you!");
+ msg_print("The world changes!");
+
+ autosave_checkpoint();
+ /* Leaving */
+ p_ptr->leaving = TRUE;
+ break;
+
+ case PWR_VAMPIRISM:
+ {
+ /* Only works on adjacent monsters */
+ if (!get_rep_dir(&dir)) break; /* was get_aim_dir */
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You bite into thin air!");
+ break;
+ }
+
+ msg_print("You grin and bare your fangs...");
+ dummy = plev + randint(plev) * MAX(1, plev / 10); /* Dmg */
+ if (drain_life(dir, dummy))
+ {
+ if (p_ptr->food < PY_FOOD_FULL)
+ /* No heal if we are "full" */
+ hp_player(dummy);
+ else
+ msg_print("You were not hungry.");
+ /* Gain nutritional sustenance: 150/hp drained */
+ /* A Food ration gives 5000 food points (by contrast) */
+ /* Don't ever get more than "Full" this way */
+ /* But if we ARE Gorged, it won't cure us */
+ dummy = p_ptr->food + MIN(5000, 100 * dummy);
+ if (p_ptr->food < PY_FOOD_MAX) /* Not gorged already */
+ set_food(dummy >= PY_FOOD_MAX ? PY_FOOD_MAX - 1 : dummy);
+ }
+ else
+ msg_print("Yechh. That tastes foul.");
+ }
+ break;
+
+ case PWR_SCARE:
+ {
+ msg_print("You emit an eldritch howl!");
+ if (!get_aim_dir(&dir)) break;
+ fear_monster(dir, plev);
+ }
+ break;
+
+ case PWR_REST_LIFE:
+ {
+ msg_print("You attempt to restore your lost energies.");
+ restore_level();
+ }
+ break;
+
+ case PWR_HYPNO:
+ {
+ int dir, x, y;
+ cave_type *c_ptr;
+ monster_type *m_ptr;
+ object_type *q_ptr;
+ object_type forge;
+
+ msg_print("Hypnotize which pet?");
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (c_ptr->m_idx)
+ {
+ m_ptr = &m_list[c_ptr->m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ if ((r_ptr->flags & RF_NEVER_MOVE) && (m_ptr->status == MSTATUS_PET) && (!(r_ptr->flags & RF_SPECIAL_GENE)))
+ {
+ q_ptr = &forge;
+ object_prep(q_ptr, lookup_kind(TV_HYPNOS, 1));
+ q_ptr->number = 1;
+ q_ptr->pval = m_ptr->r_idx;
+ q_ptr->pval2 = m_ptr->hp;
+ object_aware(q_ptr);
+ object_known(q_ptr);
+
+ q_ptr->ident |= IDENT_STOREB;
+
+ drop_near(q_ptr, 0, y, x);
+
+ delete_monster(y, x);
+ health_who = 0;
+ }
+ else
+ msg_print("You can only hypnotize monsters that can't move.");
+ }
+ else msg_print("There is no pet here!");
+ }
+ break;
+
+ case PWR_UNHYPNO:
+ {
+ monster_type *m_ptr;
+ int m_idx;
+ int item, x, y, d;
+ object_type *o_ptr;
+
+ cptr q, s;
+
+ /* Get an item */
+ q = "Awaken which monster? ";
+ s = "You have no monster to awaken.";
+ if (!get_item(&item, q, s, (USE_FLOOR), object_filter::TVal(TV_HYPNOS))) return;
+
+ o_ptr = &o_list[0 - item];
+
+ d = 2;
+ while (d < 100)
+ {
+ scatter(&y, &x, p_ptr->py, p_ptr->px, d);
+
+ if (cave_floor_bold(y, x) && (!cave[y][x].m_idx)) break;
+
+ d++;
+ }
+
+ if (d >= 100) return;
+
+ if ((m_idx = place_monster_one(y, x, o_ptr->pval, 0, FALSE, MSTATUS_PET)) == 0) return;
+
+ m_ptr = &m_list[m_idx];
+ m_ptr->hp = o_ptr->pval2;
+
+ floor_item_increase(0 - item, -1);
+ floor_item_describe(0 - item);
+ floor_item_optimize(0 - item);
+ }
+ break;
+
+ case PWR_NECRO:
+ {
+ do_cmd_necromancer();
+ break;
+ }
+ case PWR_INCARNATE:
+ {
+ do_cmd_integrate_body();
+ break;
+ }
+
+ case PWR_SPIT_ACID:
+ {
+ msg_print("You spit acid...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_ACID, dir, p_ptr->lev, 1 + (p_ptr->lev / 30));
+ }
+ break;
+
+ case PWR_BR_FIRE:
+ {
+ msg_print("You breathe fire...");
+ if (get_aim_dir(&dir))
+ fire_ball(GF_FIRE, dir, p_ptr->lev * 2, 1 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_HYPN_GAZE:
+ {
+ msg_print("Your eyes look mesmerising...");
+ if (get_aim_dir(&dir))
+ charm_monster(dir, p_ptr->lev);
+ }
+ break;
+
+ case PWR_TELEKINES:
+ {
+ msg_print("You concentrate...");
+ if (get_aim_dir(&dir))
+ fetch(dir, p_ptr->lev * 10, TRUE);
+ }
+ break;
+
+ case PWR_VTELEPORT:
+ {
+ msg_print("You concentrate...");
+ teleport_player(10 + 4*(p_ptr->lev));
+ }
+ break;
+
+ case PWR_MIND_BLST:
+ {
+ msg_print("You concentrate...");
+ if (!get_aim_dir(&dir)) return;
+ fire_bolt(GF_PSI, dir, damroll(3 + ((p_ptr->lev - 1) / 5), 3));
+ }
+ break;
+
+ case PWR_RADIATION:
+ {
+ msg_print("Radiation flows from your body!");
+ fire_ball(GF_NUKE, 0, (p_ptr->lev * 2), 3 + (p_ptr->lev / 20));
+ }
+ break;
+
+ case PWR_SMELL_MET:
+ {
+ detect_treasure(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_SMELL_MON:
+ {
+ detect_monsters_normal(DEFAULT_RADIUS);
+ }
+ break;
+
+ case PWR_BLINK:
+ {
+ teleport_player(10);
+ }
+ break;
+
+ case PWR_EAT_ROCK:
+ {
+ int x, y, ox, oy;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) break;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (cave_floor_bold(y, x))
+ {
+ msg_print("You bite into thin air!");
+ break;
+ }
+ else if ((f_info[c_ptr->feat].flags & FF_PERMANENT) || (c_ptr->feat == FEAT_MOUNTAIN))
+ {
+ msg_print("Ouch! This wall is harder than your teeth!");
+ break;
+ }
+ else if (c_ptr->m_idx)
+ {
+ msg_print("There's something in the way!");
+ break;
+ }
+ else if (c_ptr->feat == FEAT_TREES)
+ {
+ msg_print("You don't like the woody taste!");
+ break;
+ }
+ else
+ {
+ if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
+ (c_ptr->feat <= FEAT_RUBBLE))
+ {
+ set_food(p_ptr->food + 3000);
+ }
+ else if ((c_ptr->feat >= FEAT_MAGMA) &&
+ (c_ptr->feat <= FEAT_QUARTZ_K))
+ {
+ set_food(p_ptr->food + 5000);
+ }
+ else if ((c_ptr->feat >= FEAT_SANDWALL) &&
+ (c_ptr->feat <= FEAT_SANDWALL_K))
+ {
+ set_food(p_ptr->food + 500);
+ }
+ else
+ {
+ msg_print("This granite is very filling!");
+ set_food(p_ptr->food + 10000);
+ }
+ }
+ wall_to_mud(dir);
+
+ oy = p_ptr->py;
+ ox = p_ptr->px;
+
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ lite_spot(p_ptr->py, p_ptr->px);
+ lite_spot(oy, ox);
+
+ verify_panel();
+
+ p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
+ p_ptr->update |= (PU_DISTANCE);
+ p_ptr->window |= (PW_OVERHEAD);
+ }
+ break;
+
+ case PWR_SWAP_POS:
+ {
+ if (!get_aim_dir(&dir)) return;
+ teleport_swap(dir);
+ }
+ break;
+
+ case PWR_SHRIEK:
+ {
+ fire_ball(GF_SOUND, 0, 4 * p_ptr->lev, 8);
+ aggravate_monsters(0);
+ }
+ break;
+
+ case PWR_ILLUMINE:
+ {
+ lite_area(damroll(2, (p_ptr->lev / 2)), (p_ptr->lev / 10) + 1);
+ }
+ break;
+
+ case PWR_DET_CURSE:
+ {
+ int i;
+
+ for (i = 0; i < INVEN_TOTAL; i++)
+ {
+ object_type *o_ptr = &p_ptr->inventory[i];
+
+ if (!o_ptr->k_idx) continue;
+ if (!cursed_p(o_ptr)) continue;
+
+ if (!o_ptr->sense) o_ptr->sense = SENSE_CURSED;
+ }
+ }
+ break;
+
+ case PWR_POLYMORPH:
+ {
+ do_poly_self();
+ }
+ break;
+
+ case PWR_MIDAS_TCH:
+ {
+ alchemy();
+ }
+ break;
+
+ case PWR_GROW_MOLD:
+ {
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ summon_specific_friendly(p_ptr->py, p_ptr->px, p_ptr->lev, SUMMON_BIZARRE1, FALSE);
+ }
+ }
+ break;
+
+ case PWR_RESIST:
+ {
+ int num = p_ptr->lev / 10;
+ int dur = randint(20) + 20;
+
+ if (rand_int(5) < num)
+ {
+ set_oppose_acid(p_ptr->oppose_acid + dur);
+ num--;
+ }
+ if (rand_int(4) < num)
+ {
+ set_oppose_elec(p_ptr->oppose_elec + dur);
+ num--;
+ }
+ if (rand_int(3) < num)
+ {
+ set_oppose_fire(p_ptr->oppose_fire + dur);
+ num--;
+ }
+ if (rand_int(2) < num)
+ {
+ set_oppose_cold(p_ptr->oppose_cold + dur);
+ num--;
+ }
+ if (num)
+ {
+ set_oppose_pois(p_ptr->oppose_pois + dur);
+ num--;
+ }
+ }
+ break;
+
+ case PWR_EARTHQUAKE:
+ {
+ /* Prevent destruction of quest levels and town */
+ if (!is_quest(dun_level) && dun_level)
+ earthquake(p_ptr->py, p_ptr->px, 10);
+ }
+ break;
+
+ case PWR_EAT_MAGIC:
+ {
+ object_type * o_ptr;
+ int lev, item;
+
+ /* Get an item */
+ q = "Drain which item? ";
+ s = "You have nothing to drain.";
+ if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR), item_tester_hook_recharge())) break;
+
+ o_ptr = get_object(item);
+
+ lev = k_info[o_ptr->k_idx].level;
+
+ if (o_ptr->tval == TV_ROD_MAIN)
+ {
+ if (!o_ptr->timeout)
+ {
+ msg_print("You can't absorb energy from a discharged rod.");
+ }
+ else
+ {
+ p_ptr->csp += o_ptr->timeout;
+ o_ptr->timeout = 0;
+ }
+ }
+ else
+ {
+ if (o_ptr->pval > 0)
+ {
+ p_ptr->csp += o_ptr->pval * lev;
+ o_ptr->pval = 0;
+ }
+ else
+ {
+ msg_print("There's no energy there to absorb!");
+ }
+ o_ptr->ident |= IDENT_EMPTY;
+ }
+
+ if (p_ptr->csp > p_ptr->msp)
+ {
+ p_ptr->csp = p_ptr->msp;
+ }
+
+ p_ptr->notice |= (PN_COMBINE | PN_REORDER);
+ p_ptr->window |= (PW_INVEN);
+ }
+ break;
+
+ case PWR_WEIGH_MAG:
+ {
+ report_magics();
+ }
+ break;
+
+ case PWR_STERILITY:
+ {
+ /* Fake a population explosion. */
+ msg_print("You suddenly have a headache!");
+ take_hit(randint(30) + 30, "the strain of forcing abstinence");
+ num_repro += MAX_REPRO;
+ }
+ break;
+
+ case PWR_PANIC_HIT:
+ {
+ int x, y;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ if (cave[y][x].m_idx)
+ {
+ py_attack(y, x, -1);
+ teleport_player(30);
+ }
+ else
+ {
+ msg_print("You don't see any monster in this direction.");
+ msg_print(NULL);
+ }
+ }
+ break;
+
+ case PWR_DAZZLE:
+ {
+ stun_monsters(p_ptr->lev * 4);
+ confuse_monsters(p_ptr->lev * 4);
+ turn_monsters(p_ptr->lev * 4);
+ }
+ break;
+
+ case PWR_DARKRAY:
+ {
+ if (!get_aim_dir(&dir)) return;
+ fire_beam(GF_LITE, dir, 2*p_ptr->lev);
+ }
+ break;
+
+ case PWR_RECALL:
+ {
+ if (!(dungeon_flags & DF_ASK_LEAVE) || ((dungeon_flags & DF_ASK_LEAVE) && !get_check("Leave this unique level forever? ")))
+ {
+ recall_player(21, 15);
+ }
+ }
+ break;
+
+ case PWR_BANISH:
+ {
+ if (!get_rep_dir(&dir)) return;
+ const int x = p_ptr->px + ddx[dir];
+ const int y = p_ptr->py + ddy[dir];
+ cave_type *c_ptr = &cave[y][x];
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You sense no evil there!");
+ break;
+ }
+
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+ auto const r_ptr = m_ptr->race();
+
+ if (r_ptr->flags & RF_EVIL)
+ {
+ /* Delete the monster, rather than killing it. */
+ delete_monster_idx(c_ptr->m_idx);
+ msg_print("The evil creature vanishes in a puff of sulphurous smoke!");
+ }
+ else
+ {
+ msg_print("Your invocation is ineffectual!");
+ }
+ }
+ break;
+
+ case PWR_COLD_TOUCH:
+ {
+ int x, y;
+ cave_type *c_ptr;
+
+ if (!get_rep_dir(&dir)) return;
+ y = p_ptr->py + ddy[dir];
+ x = p_ptr->px + ddx[dir];
+ c_ptr = &cave[y][x];
+ if (!(c_ptr->m_idx))
+ {
+ msg_print("You wave your hands in the air.");
+ break;
+ }
+ fire_bolt(GF_COLD, dir, 2 * (p_ptr->lev));
+ }
+ break;
+
+ case PWR_LAUNCHER:
+ {
+ /* Gives a multiplier of 2 at first, up to 5 at 48th */
+ p_ptr->throw_mult = 2 + (p_ptr->lev / 16);
+ do_cmd_throw();
+ p_ptr->throw_mult = 1;
+ }
+ break;
+
+ case PWR_DODGE:
+ use_ability_blade();
+ break;
+
+ case POWER_INVISIBILITY:
+ set_invis(20 + randint(30), 30);
+ break;
+
+ case POWER_WEB:
+ /* Warning, beware of f_info changes .. I hate to do that .. */
+ grow_things(16, 1 + (p_ptr->lev / 10));
+ break;
+
+ case POWER_COR_SPACE_TIME:
+ if (p_ptr->corrupt_anti_teleport_stopped)
+ {
+ p_ptr->corrupt_anti_teleport_stopped = FALSE;
+ msg_print("You stop controlling your corruption.");
+ p_ptr->update |= PU_BONUS;
+ }
+ else
+ {
+ p_ptr->corrupt_anti_teleport_stopped = TRUE;
+ msg_print("You start controlling your corruption, teleportation works once more.");
+ p_ptr->update |= PU_BONUS;
+ }
+ break;
+
+ default:
+ abort();
+ break;
+ }
+
+ p_ptr->redraw |= (PR_FRAME);
+ p_ptr->window |= (PW_PLAYER);
+}
+
+/*
+ * Print a batch of power.
+ */
+static void print_power_batch(int *p, int start, int max)
+{
+ char buff[80];
+ power_type* spell;
+ int i = start, j = 0;
+
+ prt(format(" %-31s Level Mana Fail", "Name"), 1, 20);
+
+ for (i = start; i < (start + 20); i++)
+ {
+ if (i >= max) break;
+
+ spell = &powers_type[p[i]];
+
+ sprintf(buff, " %c-%3d) %-30s %5d %4d %s@%d", I2A(j), p[i] + 1, spell->name,
+ spell->level, spell->cost, stat_names[spell->stat], spell->diff);
+
+ prt(buff, 2 + j, 20);
+ j++;
+ }
+ prt("", 2 + j, 20);
+ prt(format("Select a power (a-%c), +/- to scroll:", I2A(j - 1)), 0, 0);
+}
+
+
+/*
+ * List powers and ask to pick one.
+ */
+
+static power_type* select_power(int *x_idx)
+{
+ char which;
+ int max = 0, i, start = 0;
+ power_type* ret;
+ int p[POWER_MAX];
+
+ /* Count the max */
+ for (i = 0; i < POWER_MAX; i++)
+ {
+ if (p_ptr->powers[i])
+ {
+ p[max++] = i;
+ }
+ }
+
+ /* Exit if there aren't powers */
+ if (max == 0)
+ {
+ *x_idx = -1;
+ ret = NULL;
+ msg_print("You don't have any special powers.");
+ }
+ else
+ {
+ character_icky = TRUE;
+ Term_save();
+
+ while (1)
+ {
+ print_power_batch(p, start, max);
+ which = inkey();
+
+ if (which == ESCAPE)
+ {
+ *x_idx = -1;
+ ret = NULL;
+ break;
+ }
+ else if (which == '+')
+ {
+ start += 20;
+ if (start >= max) start -= 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else if (which == '-')
+ {
+ start -= 20;
+ if (start < 0) start += 20;
+ Term_load();
+ character_icky = FALSE;
+ }
+ else
+ {
+ which = tolower(which);
+ if (start + A2I(which) >= max)
+ {
+ bell();
+ continue;
+ }
+ if (start + A2I(which) < 0)
+ {
+ bell();
+ continue;
+ }
+
+ *x_idx = p[start + A2I(which)];
+ ret = &powers_type[p[start + A2I(which)]];
+ break;
+ }
+ }
+ Term_load();
+ character_icky = FALSE;
+ }
+
+ return ret;
+}
+
+/* Ask & execute a power */
+void do_cmd_power()
+{
+ int x_idx;
+ power_type *x_ptr;
+ bool_ push = TRUE;
+
+ /* Get the skill, if available */
+ if (repeat_pull(&x_idx))
+ {
+ if ((x_idx < 0) || (x_idx >= POWER_MAX)) return;
+ x_ptr = &powers_type[x_idx];
+ push = FALSE;
+ }
+ else if (!command_arg) x_ptr = select_power(&x_idx);
+ else
+ {
+ x_idx = command_arg - 1;
+ if ((x_idx < 0) || (x_idx >= POWER_MAX)) return;
+ x_ptr = &powers_type[x_idx];
+ }
+
+ if (x_ptr == NULL) return;
+
+ if (push) repeat_push(x_idx);
+
+ if (p_ptr->powers[x_idx])
+ power_activate(x_idx);
+ else
+ msg_print("You do not have access to this power.");
+}