void _smash_trap_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Smash Trap"); break; case SPELL_DESC: var_set_string(res, "Sets off a trap, then destroy that trap."); break; case SPELL_CAST: { int dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; move_player(dir, easy_disarm, TRUE); var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
static void _excavation_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Excavation"); break; case SPELL_DESC: var_set_string(res, "You break walls on your quest for treasure! This takes a bit more time, though."); break; case SPELL_ENERGY: { int n = 200; if (equip_find_object(TV_DIGGING, SV_ANY)) n -= 120 * p_ptr->lev / 50; else n -= 80 * p_ptr->lev / 50; var_set_int(res, n); } break; case SPELL_CAST: { int dir = 5; bool b = FALSE; if ( get_rep_dir2(&dir) && dir != 5 ) { int x, y; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) { msg_print("You may excavate no further."); } else if ( cave_have_flag_bold(y, x, FF_WALL) || cave_have_flag_bold(y, x, FF_TREE) || cave_have_flag_bold(y, x, FF_CAN_DIG) ) { msg_print("You dig your way to treasure!"); cave_alter_feat(y, x, FF_TUNNEL); teleport_player_to(y, x, TELEPORT_NONMAGICAL); /*??*/ b = TRUE; } else { msg_print("There is nothing to excavate."); } } var_set_bool(res, b); } break; default: default_spell(cmd, res); break; } }
static void _charge_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Charge"); break; case SPELL_DESC: var_set_string(res, "Attacks monster with your weapons normally, then move through counter side of the monster."); break; case SPELL_CAST: { int dir, x, y; var_set_bool(res, FALSE); if (p_ptr->riding) { msg_print("You cannot do it when riding."); return; } if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (!cave[y][x].m_idx) { msg_print("There is no monster there."); return; } py_attack(y, x, 0); if (player_can_enter(cave[y][x].feat, 0) && !is_trap(cave[y][x].feat)) { y += ddy[dir]; x += ddx[dir]; if (player_can_enter(cave[y][x].feat, 0) && !is_trap(cave[y][x].feat) && !cave[y][x].m_idx) { msg_print(NULL); move_player_effect(y, x, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); } } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
bool do_blow(int type) { int x = 0, y = 0; int dir; int m_idx = 0; /* For ergonomics sake, use currently targeted monster. This allows a macro of \e*tmaa or similar to pick an adjacent foe, while \emaa*t won't work, since get_rep_dir2() won't allow a target. */ if (use_old_target && target_okay()) { y = target_row; x = target_col; m_idx = cave[y][x].m_idx; if (m_idx) { if (m_list[m_idx].cdis > 1) m_idx = 0; else dir = 5; } } if (!m_idx) { if (!get_rep_dir2(&dir)) return FALSE; if (dir == 5) return FALSE; y = py + ddy[dir]; x = px + ddx[dir]; m_idx = cave[y][x].m_idx; if (!m_idx) { msg_print("There is no monster there."); return FALSE; } } if (m_idx) py_attack(y, x, type); return TRUE; }
static void _smash_wall_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Smash"); break; case SPELL_DESC: var_set_string(res, "Destroys adjacent targeted wall, door, tree, or trap."); break; case SPELL_CAST: { int y, x, dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) return; if (cave_have_flag_bold(y, x, FF_HURT_ROCK)) { cave_alter_feat(y, x, FF_HURT_ROCK); p_ptr->update |= PU_FLOW; } else if (cave_have_flag_bold(y, x, FF_TREE)) { cave_set_feat(y, x, one_in_(3) ? feat_brake : feat_grass); } else { int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; project(0, 0, y, x, 0, GF_KILL_DOOR, flg, -1); } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
void awesome_blow_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Awesome Blow"); break; case SPELL_DESC: var_set_string(res, "Attack a monster with a single melee blow. If blow hits, does normal melee damage and propels the monster backwards."); break; case SPELL_CAST: { int y, x, dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (cave[y][x].m_idx) { py_attack(y, x, MELEE_AWESOME_BLOW); } else { msg_print("There is no monster."); return; } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
static void _stone_smash_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Stone Smash"); break; case SPELL_DESC: var_set_string(res, "Destroys adjacent targeted wall."); break; case SPELL_CAST: { int y, x, dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) return; if (cave_have_flag_bold(y, x, FF_HURT_ROCK)) { cave_alter_feat(y, x, FF_HURT_ROCK); p_ptr->update |= PU_FLOW; } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
/**************************************************************** * Spells ****************************************************************/ static void _kiss_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Kiss"); break; case SPELL_DESC: var_set_string(res, "Attempt to charm an adjacent monster."); break; case SPELL_COST_EXTRA: var_set_int(res, p_ptr->lev * 2); break; case SPELL_CAST: { int y, x, dir = 0, m_idx; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; m_idx = cave[y][x].m_idx; if (m_idx) { monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; char desc[MAX_NLEN]; monster_desc(desc, m_ptr, 0); if ((r_ptr->flags1 & RF1_UNIQUE) || mon_save_p(m_ptr->r_idx, A_CHR)) { set_monster_csleep(m_idx, 0); if (is_hostile(m_ptr)) { switch (randint1(10)) { case 1: msg_format("%^s says 'Impudent Strumpet!'", desc); break; case 2: msg_format("%^s says 'Ewwww! Gross!!'", desc); break; case 3: msg_format("%^s says 'You ain't my type!'", desc); break; default: msg_format("%^s resists your charms.", desc); } if (allow_ticked_off(r_ptr)) { m_ptr->anger_ct++; } } else msg_format("%^s ignores you.", desc); } else { if (is_pet(m_ptr)) msg_format("%^s slobbers on you affectionately.", desc); else if (is_friendly(m_ptr)) { set_pet(m_ptr); msg_format("%^s is charmed!", desc); } else { set_friendly(m_ptr); msg_format("%^s suddenly becomes friendly.", desc); } } var_set_bool(res, TRUE); } else { msg_print("There is no monster."); } break; } default: default_spell(cmd, res); break; } }
void banish_evil_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Banish Evil"); break; case SPELL_DESC: var_set_string(res, "Attempts to remove a single evil opponent."); break; case SPELL_GAIN_MUT: msg_print("You feel a holy wrath fill you."); break; case SPELL_LOSE_MUT: msg_print("You no longer feel a holy wrath."); break; case SPELL_MUT_DESC: var_set_string(res, "You can send evil creatures directly to Hell."); break; case SPELL_CAST: { int dir = 0; int x, y; cave_type *c_ptr; monster_type *m_ptr; monster_race *r_ptr; if (!get_rep_dir2(&dir)) { var_set_bool(res, FALSE); break; } var_set_bool(res, TRUE); y = py + ddy[dir]; x = px + ddx[dir]; c_ptr = &cave[y][x]; if (!c_ptr->m_idx) { msg_print("You sense no evil there!"); break; } m_ptr = &m_list[c_ptr->m_idx]; r_ptr = &r_info[m_ptr->r_idx]; if ((r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags1 & RF1_QUESTOR) && !(r_ptr->flags1 & RF1_UNIQUE) && !p_ptr->inside_arena && !p_ptr->inside_quest && (r_ptr->level < randint1(p_ptr->lev+50)) && !(m_ptr->mflag2 & MFLAG2_NOGENO)) { /* Delete the monster, rather than killing it. */ delete_monster_idx(c_ptr->m_idx); msg_print("The evil creature vanishes in a puff of sulfurous smoke!"); } else { msg_print("Your invocation is ineffectual!"); if (one_in_(13)) m_ptr->mflag2 |= MFLAG2_NOGENO; } break; } default: default_spell(cmd, res); break; } }
static void _double_crack_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Double Crack"); break; case SPELL_DESC: var_set_string(res, "Attack a monster normally with your whip, and then randomly attack an adjacent monster."); break; case SPELL_CAST: if (_whip_check()) { int dir = 5; bool b = FALSE; if ( get_rep_dir2(&dir) && dir != 5 ) { int x, y; int num = 1; int attempts = 0; /* First we attack where the player selected */ y = py + ddy[dir]; x = px + ddx[dir]; if (in_bounds(y, x) && cave[y][x].m_idx) py_attack(y, x, 0); else msg_print("Your whip cracks in empty air."); /* Now the whip cracks randomly! Note that we favor fighting in hallways, or with ones back up against the wall. */ while (num > 0) { if (attempts > 3 * num) { while (num > 0) { msg_print("Your whip cracks in empty air."); num--; } break; } /* random direction, but we don't penalize for choosing the player (5) */ dir = randint0(9); if (dir == 5) continue; attempts++; y = py + ddy[dir]; x = px + ddx[dir]; if ( !in_bounds(y, x) || cave_have_flag_bold(y, x, FF_WALL) || cave_have_flag_bold(y, x, FF_TREE) || cave_have_flag_bold(y, x, FF_CAN_DIG) ) { continue; } if (cave[y][x].m_idx) py_attack(y, x, 0); else msg_print("Your whip cracks in empty air."); num--; } b = TRUE; } var_set_bool(res, b); } else { msg_print("Whip techniques can only be used if you are fighting with whips."); var_set_bool(res, FALSE); } break; default: default_spell(cmd, res); break; } }
static bool _necro_do_touch(int type, int dice, int sides, int base) { int x, y; int dir = 0; int m_idx = 0; if (!_necro_check_touch()) return FALSE; /* For ergonomics sake, use currently targeted monster. This allows a macro of \e*tmaa or similar to pick an adjacent foe, while \emaa*t won't work, since get_rep_dir2() won't allow a target. */ if (use_old_target && target_okay()) { y = target_row; x = target_col; m_idx = cave[y][x].m_idx; if (m_idx) { if (m_list[m_idx].cdis > 1) m_idx = 0; else dir = 5; /* Hack so that fire_ball() works correctly */ } } if (!m_idx) { if (!get_rep_dir2(&dir)) return FALSE; if (dir == 5) return FALSE; y = py + ddy[dir]; x = px + ddx[dir]; m_idx = cave[y][x].m_idx; if (!m_idx) { msg_print("There is no monster there."); return FALSE; } } if (m_idx) { int dam; monster_type *m_ptr = &m_list[m_idx]; if (!is_hostile(m_ptr) && !(p_ptr->stun || p_ptr->confused || p_ptr->image || IS_SHERO() || !m_ptr->ml)) { if (!get_check("Really hit it? ")) return FALSE; } dam = _necro_damroll(dice, sides, base); on_p_hit_m(m_idx); touch_zap_player(m_idx); if (fire_ball(type, dir, dam, 0)) { if (type == GF_OLD_DRAIN) hp_player(dam); } } return TRUE; }
/********************************************************************** * Spells: Note, we are still using the old "Book Spell System" **********************************************************************/ cptr do_necromancy_spell(int spell, int mode) { bool name = (mode == SPELL_NAME) ? TRUE : FALSE; bool desc = (mode == SPELL_DESC) ? TRUE : FALSE; bool info = (mode == SPELL_INFO) ? TRUE : FALSE; bool cast = (mode == SPELL_CAST) ? TRUE : FALSE; bool fail = (mode == SPELL_FAIL) ? TRUE : FALSE; int plev = p_ptr->lev; switch (spell) { /* Stench of Death */ case 0: if (name) return "Cold Touch"; if (desc) return "Damage an adjacent monster with a chilling touch."; if (info) return _necro_info_damage(2, 6, plev + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_COLD, 2, 6, plev + p_ptr->to_d_spell)) return NULL; break; case 1: if (name) return "Summon Rat"; if (desc) return "Summons a rat to feast on the dead!"; if (cast || fail) _necro_do_summon(SUMMON_RAT, 1, fail); break; case 2: if (name) return "Detect Life"; if (desc) return "Detects all living monsters in your vicinity."; if (info) return info_radius(DETECT_RAD_DEFAULT); if (cast) detect_monsters_living(DETECT_RAD_DEFAULT, "You sense the presence of life around you."); break; case 3: if (name) return "Detect Unlife"; if (desc) return "Detects all nonliving monsters in your vicinity."; if (info) return info_radius(DETECT_RAD_DEFAULT); if (cast) detect_monsters_nonliving(DETECT_RAD_DEFAULT); break; case 4: if (name) return "Poison Touch"; if (desc) return "Damage an adjacent monster with a venomous touch."; if (info) return _necro_info_damage(4, 6, plev + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_POIS, 4, 6, plev + p_ptr->to_d_spell)) return NULL; break; case 5: if (name) return "Summon Bats"; if (desc) return "Summons bats to feast on the living!"; if (cast || fail) _necro_do_summon(SUMMON_BAT, 1 + randint1(2), fail); break; case 6: if (name) return "Eldritch Howl"; if (desc) return "Emit a terrifying howl."; if (cast) project_hack(GF_ELDRITCH_HOWL, spell_power(plev * 3)); break; case 7: if (name) return "Black Touch"; if (desc) return "Damage an adjacent monster with a dark touch."; if (info) return _necro_info_damage(6, 6, plev * 3 / 2 + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_DARK, 6, 6, plev * 3 / 2 + p_ptr->to_d_spell)) return NULL; break; /* Sepulchral Ways */ case 8: if (name) return "Summon Wolves"; if (desc) return "Summons wolves to feast on the living!"; if (cast || fail) _necro_do_summon(SUMMON_WOLF, 1 + randint1(2), fail); break; case 9: if (name) return "Black Cloak"; if (desc) return "You become shrouded in darkness."; if (cast) { set_tim_dark_stalker(spell_power(randint1(plev) + plev), FALSE); } break; case 10: if (name) return "Undead Sight"; if (desc) return "Learn about your nearby surroundings by communing with the dead."; if (info) return info_radius(DETECT_RAD_MAP); if (cast) { map_area(DETECT_RAD_MAP); detect_traps(DETECT_RAD_DEFAULT, TRUE); detect_doors(DETECT_RAD_DEFAULT); detect_stairs(DETECT_RAD_DEFAULT); } break; case 11: if (name) return "Undead Lore"; if (desc) return "Ask the dead to examine an object for you."; if (cast) ident_spell(NULL); break; case 12: if (name) return "Repelling Touch"; if (desc) return "Conjure a foul wind to blow an adjacent monster away."; if (cast) { int y, x, dir; if (!_necro_check_touch()) return NULL; if (!get_rep_dir2(&dir)) return NULL; if (dir == 5) return NULL; y = py + ddy[dir]; x = px + ddx[dir]; if (!cave[y][x].m_idx) { msg_print("There is no monster."); return NULL; } else { int i; int ty = y, tx = x; int oy = y, ox = x; int m_idx = cave[y][x].m_idx; monster_type *m_ptr = &m_list[m_idx]; char m_name[80]; monster_desc(m_name, m_ptr, 0); touch_zap_player(cave[y][x].m_idx); for (i = 0; i < 10; i++) { y += ddy[dir]; x += ddx[dir]; if (cave_empty_bold(y, x)) { ty = y; tx = x; } else break; } if ((ty != oy) || (tx != ox)) { msg_format("A foul wind blows %s away!", m_name); cave[oy][ox].m_idx = 0; cave[ty][tx].m_idx = m_idx; m_ptr->fy = ty; m_ptr->fx = tx; update_mon(m_idx, TRUE); lite_spot(oy, ox); lite_spot(ty, tx); if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)) p_ptr->update |= (PU_MON_LITE); } } } break; case 13: if (name) return "Vampiric Touch"; if (desc) return "Steal life from an adjacent foe."; if (info) return _necro_info_damage(0, 0, plev * 4 + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_OLD_DRAIN, 0, 0, plev * 4 + p_ptr->to_d_spell)) return NULL; break; case 14: if (name) return "Dread of Night"; if (desc) return "Summons Dread to do your bidding. Beware of failure!"; if (cast || fail) _necro_do_summon(SUMMON_DREAD, 1 + randint0(3), fail); break; case 15: if (name) return "Entomb"; if (desc) return "Entombs chosen foe."; if (cast) { int dir; if (!get_fire_dir(&dir)) return NULL; fire_ball_hide(GF_ENTOMB, dir, plev, 0); p_ptr->update |= (PU_FLOW); p_ptr->redraw |= (PR_MAP); } break; /* Return of the Dead */ case 16: if (name) return "Summon Zombies"; if (desc) return "The dead are back and hungry for brains!"; if (cast || fail) _necro_do_summon(SUMMON_ZOMBIE, 2 + randint1(3), fail); break; case 17: if (name) return "Summon Skeletons"; if (desc) return "Summon skeletal assistance."; if (cast || fail) _necro_do_summon(SUMMON_SKELETON, 1 + randint0(3), fail); break; case 18: if (name) return "Summon Ghosts"; if (desc) return "Recall the spirits of slain warriors for unholy servitude."; if (cast || fail) _necro_do_summon(SUMMON_GHOST, 1 + randint0(3), fail); break; case 19: if (name) return "Summon Vampires"; if (desc) return "Its time to command the commanders!"; if (cast || fail) _necro_do_summon(SUMMON_VAMPIRE, 1 + randint0(2), fail); break; case 20: if (name) return "Summon Wraiths"; if (desc) return "Summon wights and wraiths to do your bidding."; if (cast || fail) _necro_do_summon(SUMMON_WIGHT, 1 + randint0(2), fail); break; case 21: if (name) return "Summon Liches"; if (desc) return "Call forth former necromancers."; if (cast || fail) _necro_do_summon(SUMMON_LICH, 1 + randint0(2), fail); break; case 22: if (name) return "Unholy Word"; if (desc) return "Utter an unspeakable word. The morale of your visible evil pets is temporarily boosted and they will serve you with renewed enthusiasm."; if (cast) project_hack(GF_UNHOLY_WORD, plev * 6); break; case 23: if (name) return "Lost Cause"; if (desc) return "Make a last ditch Kamikaze effort for victory!"; if (cast) discharge_minion(); break; /* Necromatic Tome */ case 24: if (name) return "Draining Touch"; if (desc) return "Steal mana from an adjacent foe."; if (info) return _necro_info_damage(5, 5, plev/2 + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_DRAINING_TOUCH, 5, 5, plev/2 + p_ptr->to_d_spell)) return NULL; break; case 25: if (name) return "Unhallow Ground"; if (desc) return "Makes the current square unholy."; if (cast) warding_glyph(); /* TODO: Add new cave feature! */ break; case 26: { int base = spell_power(20); if (name) return "Shield of the Dead"; if (desc) return "Grants temporary protection"; if (info) return info_duration(base, base); if (cast) { set_tim_res_nether(randint1(base) + base, FALSE); set_oppose_pois(randint1(base) + base, FALSE); set_oppose_cold(randint1(base) + base, FALSE); set_shield(randint1(base) + base, FALSE); } break; } case 27: if (name) return "Rending Touch"; if (desc) return "Damage an adjacent monster with a disintegrating touch."; if (info) return _necro_info_damage(20, 20, plev + p_ptr->to_d_spell); if (cast && !_necro_do_touch(GF_DISINTEGRATE, 20, 20, plev + p_ptr->to_d_spell)) return NULL; break; case 28: if (name) return "Repose of the Dead"; if (desc) return "Sleep the sleep of the dead for a few rounds, during which time nothing can awaken you, except perhaps death. When (if?) you wake up, you will be thoroughly refreshed!"; if (cast) { if (!get_check("You will enter a deep slumber. Are you sure?")) return NULL; repose_of_the_dead = TRUE; set_paralyzed(4 + randint1(4), FALSE); } break; case 29: if (name) return "Sepulchral Wind"; if (desc) return "You call forth the wind of the dead. All nearby monsters are blown away!"; { int power = spell_power(plev * 4); if (info) return info_power(power); if (cast) banish_monsters(power); } break; case 30: if (name) return "Deadly Touch"; if (desc) return "Attempt to kill an adjacent monster."; if (cast && !_necro_do_touch(GF_DEATH_TOUCH, 0, 0, plev * 200)) return NULL; break; case 31: if (name) return "Necromancy"; if (desc) return "Bridge the world of the living with the world of the dead! Vast hordes of undead will come forth to serve the one true necromancer!"; if (cast) { int i; int sp_sides = 20 + plev; int sp_base = plev; int power = spell_power(plev); power += randint1(power); for (i = 0; i < 18; i++) { int attempt = 10; int my, mx, what; while (attempt--) { scatter(&my, &mx, py, px, 4, 0); /* Require empty grids */ if (cave_empty_bold2(my, mx)) break; } if (attempt < 0) continue; switch (randint1(4)) { case 1: what = SUMMON_LICH; break; case 2: what = SUMMON_WIGHT; break; case 3: what = SUMMON_VAMPIRE; break; case 4: default: what = SUMMON_GHOST; break; } summon_specific(-1, my, mx, power, what, (PM_ALLOW_GROUP | PM_FORCE_PET | PM_HASTE)); } set_fast(randint1(sp_sides) + sp_base, FALSE); } break; } return ""; }
static void _bite_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Vampiric Bite"); break; case SPELL_DESC: var_set_string(res, "As a vampire, you must feed on fresh blood in order to sustain your unlife!"); break; case SPELL_INFO: var_set_string(res, info_damage(0, 0, _bite_amt())); break; case SPELL_CAST: var_set_bool(res, FALSE); if (d_info[dungeon_type].flags1 & DF1_NO_MELEE) { msg_print("Something prevents you from attacking."); return; } else { int x = 0, y = 0, amt, m_idx = 0; int dir = 0; if (use_old_target && target_okay()) { y = target_row; x = target_col; m_idx = cave[y][x].m_idx; if (m_idx) { if (m_list[m_idx].cdis > 1) m_idx = 0; else dir = 5; } } if (!m_idx) { if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; m_idx = cave[y][x].m_idx; if (!m_idx) { msg_print("There is no monster there."); return; } } var_set_bool(res, TRUE); msg_print("You grin and bare your fangs..."); amt = _bite_amt(); vampiric_drain_hack = TRUE; if (project(0, 0, y, x, amt, GF_OLD_DRAIN, PROJECT_STOP | PROJECT_KILL | PROJECT_THRU, -1)) { vampire_feed(amt); } else msg_print("Yechh. That tastes foul."); vampiric_drain_hack = FALSE; } break; case SPELL_COST_EXTRA: var_set_int(res, MIN(_bite_amt() / 10, 29)); break; default: default_spell(cmd, res); break; } }