void lightning_bolt_spell(int cmd, variant *res) { int dd = 3 + p_ptr->lev / 4; int ds = 8; switch (cmd) { case SPELL_NAME: var_set_string(res, "Lightning Bolt"); break; case SPELL_DESC: var_set_string(res, "Fires a bolt or beam of electricity."); break; case SPELL_INFO: var_set_string(res, info_damage(dd, spell_power(ds), 0)); break; case SPELL_CAST: { int dir = 0; var_set_bool(res, FALSE); if (!get_aim_dir(&dir)) return; fire_bolt_or_beam(beam_chance(), GF_ELEC, dir, spell_power(damroll(dd, ds))); var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
void acid_bolt_spell(int cmd, variant *res) { int dd = 5 + p_ptr->lev / 4; int ds = 8; switch (cmd) { case SPELL_NAME: var_set_string(res, "Acid Bolt"); break; case SPELL_DESC: var_set_string(res, "Fires a bolt or beam of acid."); break; case SPELL_INFO: var_set_string(res, info_damage(dd, spell_power(ds), spell_power(p_ptr->to_d_spell))); break; case SPELL_CAST: { int dir = 0; var_set_bool(res, FALSE); if (!get_fire_dir(&dir)) return; fire_bolt_or_beam( beam_chance(), GF_ACID, dir, spell_power(damroll(dd, ds) + p_ptr->to_d_spell) ); var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
static void spell_wonder(int Ind, int dir) { /* This spell should become more useful (more controlled) as the player gains experience levels. Thus, add 1/5 of the player's level to the die roll. This eliminates the worst effects later on, while keeping the results quite random. It also allows some potent effects only at high level. */ player_type *p_ptr = Players[Ind]; int py = p_ptr->py; int px = p_ptr->px; int Depth = p_ptr->dun_depth; int plev = p_ptr->lev; int die = randint(100) + plev / 5; int beam = beam_chance(Ind); if (die > 100) msg_print(Ind, "You feel a surge of power!"); if (die < 8) clone_monster(Ind, dir); else if (die < 14) speed_monster(Ind, dir); else if (die < 26) heal_monster(Ind, dir); else if (die < 31) poly_monster(Ind, dir); else if (die < 36) fire_bolt_or_beam(Ind, beam - 10, GF_MISSILE, dir, damroll(3 + ((plev - 1) / 5), 4)); else if (die < 41) confuse_monster(Ind, dir, plev); else if (die < 46) fire_ball(Ind, GF_POIS, dir, 20 + (plev / 2), 3); else if (die < 51) lite_line(Ind, dir); else if (die < 56) fire_beam(Ind, GF_ELEC, dir, damroll(3+((plev-5)/6), 6)); else if (die < 61) fire_bolt_or_beam(Ind, beam-10, GF_COLD, dir, damroll(5+((plev-5)/4), 8)); else if (die < 66) fire_bolt_or_beam(Ind, beam, GF_ACID, dir, damroll(6+((plev-5)/4), 8)); else if (die < 71) fire_bolt_or_beam(Ind, beam, GF_FIRE, dir, damroll(8+((plev-5)/4), 8)); else if (die < 76) drain_life(Ind, dir, 75); else if (die < 81) fire_ball(Ind, GF_ELEC, dir, 30 + plev / 2, 2); else if (die < 86) fire_ball(Ind, GF_ACID, dir, 40 + plev, 2); else if (die < 91) fire_ball(Ind, GF_ICE, dir, 70 + plev, 3); else if (die < 96) fire_ball(Ind, GF_FIRE, dir, 80 + plev, 3); else if (die < 101) drain_life(Ind, dir, 100 + plev); else if (die < 104) earthquake(Depth, py, px, 12); else if (die < 106) destroy_area(Depth, py, px, 15, TRUE); else if (die < 108) banishment(Ind); else if (die < 110) dispel_monsters(Ind, 120); else /* RARE */ { dispel_monsters(Ind, 150); slow_monsters(Ind); sleep_monsters(Ind); hp_player(Ind, 300); } }
static void spell_wonder(int dir) { /* This spell should become more useful (more controlled) as the player gains experience levels. Thus, add 1/5 of the player's level to the die roll. This eliminates the worst effects later on, while keeping the results quite random. It also allows some potent effects only at high level. */ effect_wonder(dir, randint1(100) + p_ptr->lev / 5, beam_chance()); }
static bool cast_mage_spell(int spell, int dir) { int py = p_ptr->py; int px = p_ptr->px; int plev = p_ptr->lev; /* Hack -- chance of "beam" instead of "bolt" */ int beam = beam_chance(); /* Spells. */ switch (spell) { case SPELL_MAGIC_MISSILE: { fire_bolt_or_beam(beam-10, GF_MISSILE, dir, damroll(3 + ((plev - 1) / 5), 4)); break; } case SPELL_DETECT_MONSTERS: { (void)detect_monsters_normal(TRUE); break; } case SPELL_PHASE_DOOR: { teleport_player(10); break; } case SPELL_LIGHT_AREA: { (void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1); break; } case SPELL_TREASURE_DETECTION: { (void)detect_treasure(TRUE); break; } case SPELL_CURE_LIGHT_WOUNDS: { (void)heal_player(15, 15); (void)dec_timed(TMD_CUT, 20, TRUE); (void)dec_timed(TMD_CONFUSED, 20, TRUE); (void)clear_timed(TMD_BLIND, TRUE); break; } case SPELL_FIND_TRAPS_DOORS: { (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); break; } case SPELL_STINKING_CLOUD: { fire_ball(GF_POIS, dir, 10 + (plev / 2), 2); break; } case SPELL_CONFUSE_MONSTER: { (void)confuse_monster(dir, plev, TRUE); break; } case SPELL_LIGHTNING_BOLT: { fire_beam(GF_ELEC, dir, damroll(3+((plev-5)/6), 6)); break; } case SPELL_TRAP_DOOR_DESTRUCTION: { (void)destroy_doors_touch(); break; } case SPELL_SLEEP_MONSTER: { (void)sleep_monster(dir, TRUE); break; } case SPELL_CURE_POISON: { (void)clear_timed(TMD_POISONED, TRUE); break; } case SPELL_TELEPORT_SELF: { teleport_player(plev * 5); break; } case SPELL_SPEAR_OF_LIGHT: { msg("A line of blue shimmering light appears."); light_line(dir); break; } case SPELL_FROST_BOLT: { fire_bolt_or_beam(beam-10, GF_COLD, dir, damroll(5+((plev-5)/4), 8)); break; } case SPELL_TURN_STONE_TO_MUD: { (void)wall_to_mud(dir); break; } case SPELL_SATISFY_HUNGER: { (void)set_food(PY_FOOD_MAX - 1); break; } case SPELL_RECHARGE_ITEM_I: { return recharge(2 + plev / 5); } case SPELL_WONDER: { (void)spell_wonder(dir); break; } case SPELL_POLYMORPH_OTHER: { (void)poly_monster(dir); break; } case SPELL_IDENTIFY: { return ident_spell(); } case SPELL_MASS_SLEEP: { (void)sleep_monsters(TRUE); break; } case SPELL_FIRE_BOLT: { fire_bolt_or_beam(beam, GF_FIRE, dir, damroll(6+((plev-5)/4), 8)); break; } case SPELL_SLOW_MONSTER: { (void)slow_monster(dir); break; } case SPELL_FROST_BALL: { fire_ball(GF_COLD, dir, 30 + (plev), 2); break; } case SPELL_RECHARGE_ITEM_II: /* greater recharging */ { return recharge(50 + plev); } case SPELL_TELEPORT_OTHER: { (void)teleport_monster(dir); break; } case SPELL_BEDLAM: { fire_ball(GF_OLD_CONF, dir, plev, 4); break; } case SPELL_FIRE_BALL: { fire_ball(GF_FIRE, dir, 55 + (plev), 2); break; } case SPELL_WORD_OF_DESTRUCTION: { destroy_area(py, px, 15, TRUE); break; } case SPELL_BANISHMENT: { return banishment(); break; } case SPELL_DOOR_CREATION: { (void)door_creation(); break; } case SPELL_STAIR_CREATION: { (void)stair_creation(); break; } case SPELL_TELEPORT_LEVEL: { (void)teleport_player_level(); break; } case SPELL_EARTHQUAKE: { earthquake(py, px, 10); break; } case SPELL_WORD_OF_RECALL: { set_recall(); break; } case SPELL_ACID_BOLT: { fire_bolt_or_beam(beam, GF_ACID, dir, damroll(8+((plev-5)/4), 8)); break; } case SPELL_CLOUD_KILL: { fire_ball(GF_POIS, dir, 40 + (plev / 2), 3); break; } case SPELL_ACID_BALL: { fire_ball(GF_ACID, dir, 40 + (plev), 2); break; } case SPELL_ICE_STORM: { fire_ball(GF_ICE, dir, 50 + (plev * 2), 3); break; } case SPELL_METEOR_SWARM: { fire_swarm(2 + plev / 20, GF_METEOR, dir, 30 + plev / 2, 1); break; } case SPELL_MANA_STORM: { fire_ball(GF_MANA, dir, 300 + (plev * 2), 3); break; } case SPELL_DETECT_INVISIBLE: { (void)detect_monsters_normal(TRUE); (void)detect_monsters_invis(TRUE); break; } case SPELL_DETECT_ENCHANTMENT: { (void)detect_objects_magic(TRUE); break; } case SPELL_SHOCK_WAVE: { fire_ball(GF_SOUND, dir, 10 + plev, 2); break; } case SPELL_EXPLOSION: { fire_ball(GF_SHARD, dir, 20 + (plev * 2), 2); break; } case SPELL_MASS_BANISHMENT: { (void)mass_banishment(); break; } case SPELL_RESIST_FIRE: { (void)inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE); break; } case SPELL_RESIST_COLD: { (void)inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE); break; } case SPELL_ELEMENTAL_BRAND: /* elemental brand */ { return brand_ammo(); } case SPELL_RESIST_POISON: { (void)inc_timed(TMD_OPP_POIS, randint1(20) + 20, TRUE); break; } case SPELL_RESISTANCE: { int time = randint1(20) + 20; (void)inc_timed(TMD_OPP_ACID, time, TRUE); (void)inc_timed(TMD_OPP_ELEC, time, TRUE); (void)inc_timed(TMD_OPP_FIRE, time, TRUE); (void)inc_timed(TMD_OPP_COLD, time, TRUE); (void)inc_timed(TMD_OPP_POIS, time, TRUE); break; } case SPELL_HEROISM: { (void)hp_player(10); (void)inc_timed(TMD_HERO, randint1(25) + 25, TRUE); (void)clear_timed(TMD_AFRAID, TRUE); break; } case SPELL_SHIELD: { (void)inc_timed(TMD_SHIELD, randint1(20) + 30, TRUE); break; } case SPELL_BERSERKER: { (void)hp_player(30); (void)inc_timed(TMD_SHERO, randint1(25) + 25, TRUE); (void)clear_timed(TMD_AFRAID, TRUE); break; } case SPELL_HASTE_SELF: { if (!p_ptr->timed[TMD_FAST]) { (void)set_timed(TMD_FAST, randint1(20) + plev, TRUE); } else { (void)inc_timed(TMD_FAST, randint1(5), TRUE); } break; } case SPELL_RIFT: { fire_beam(GF_GRAVITY, dir, 40 + damroll(plev, 7)); break; } case SPELL_REND_SOUL: /* rend soul */ { fire_bolt_or_beam(beam / 4, GF_NETHER, dir, damroll(11, plev)); break; } case SPELL_CHAOS_STRIKE: /* chaos strike */ { fire_bolt_or_beam(beam, GF_CHAOS, dir, damroll(13, plev)); break; } case SPELL_RUNE_OF_PROTECTION: /* rune of protection */ { (void)warding_glyph(); break; } case SPELL_ENCHANT_ARMOR: /* enchant armor */ { return enchant_spell(0, 0, randint0(3) + plev / 20); } case SPELL_ENCHANT_WEAPON: /* enchant weapon */ { return enchant_spell(randint0(4) + plev / 20, randint0(4) + plev / 20, 0); } } /* Success */ return (TRUE); }
static bool cast_mage_spell(int Ind, int spell) { player_type *p_ptr = Players[Ind]; object_type *o_ptr; int py = p_ptr->py; int px = p_ptr->px; int Depth = p_ptr->dun_depth; int dir; int plev = p_ptr->lev; /* Hack -- chance of "beam" instead of "bolt" */ int beam = beam_chance(Ind); /* MAngband-specific: Projected */ if (spell >= SPELL_PROJECTED) { if (!get_aim_dir(Ind, &dir)) return (FALSE); (void)project_spell_ball(Ind, dir, spell - SPELL_PROJECTED); return (TRUE); } /* Spells. */ switch (spell) { case SPELL_MAGIC_MISSILE: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s fires a magic missile."); fire_bolt_or_beam(Ind, beam-10, GF_MISSILE, dir, damroll(3 + ((plev - 1) / 5), 4)); break; } case SPELL_DETECT_MONSTERS: { (void)detect_creatures(Ind, TRUE); break; } case SPELL_PHASE_DOOR: { msg_spell("%s blinks away!"); teleport_player(Ind, 10); break; } case SPELL_LIGHT_AREA: { (void)lite_area(Ind, damroll(2, (plev / 2)), (plev / 10) + 1); break; } case SPELL_TREASURE_DETECTION: { (void)detect_treasure(Ind); //(void)detect_objects_gold(Ind); break; } case SPELL_CURE_LIGHT_WOUNDS: { (void)hp_player(Ind, damroll(2, 8)); (void)set_cut(Ind, p_ptr->cut - 15); break; } case SPELL_OBJECT_DETECTION: { (void)detect_objects_normal(Ind); break; } case SPELL_FIND_TRAPS_DOORS: { (void)detect_trap(Ind);//detect_traps(Ind); (void)detect_sdoor(Ind);//detect_doors(Ind); //(void)detect_stairs(Ind); break; } case SPELL_STINKING_CLOUD: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a stinking cloud."); fire_ball(Ind, GF_POIS, dir, 10 + (plev / 2), 2); break; } case SPELL_CONFUSE_MONSTER: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s makes a complicated gesture."); (void)confuse_monster(Ind, dir, plev); break; } case SPELL_LIGHTNING_BOLT: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a lightning bolt."); fire_beam(Ind, GF_ELEC, dir, damroll(3+((plev-5)/6), 6)); break; } case SPELL_TRAP_DOOR_DESTRUCTION: { (void)destroy_doors_touch(Ind); break; } case SPELL_SLEEP_MONSTER: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s gestures and mumbles calmly."); (void)sleep_monster(Ind, dir); break; } case SPELL_CURE_POISON: { (void)set_poisoned(Ind, 0); break; } case SPELL_TELEPORT_SELF: { msg_spell("%s teleports away!"); teleport_player(Ind, plev * 5); break; } case SPELL_SPEAR_OF_LIGHT: /* spear of light */ { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_print(Ind, "A line of blue shimmering light appears."); msg_spell("A line of blue shimmering light appears out of %s's hands."); lite_line(Ind, dir); break; } case SPELL_FROST_BOLT: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a frost bolt."); fire_bolt_or_beam(Ind, beam-10, GF_COLD, dir, damroll(5+((plev-5)/4), 8)); break; } case SPELL_TURN_STONE_TO_MUD: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s makes a moving gesture."); (void)wall_to_mud(Ind, dir); break; } case SPELL_SATISFY_HUNGER: { (void)set_food(Ind, PY_FOOD_MAX - 1); break; } case SPELL_RECHARGE_ITEM_I: { return recharge(Ind, 2 + plev / 5); } case SPELL_WONDER: /* wonder */ { if (!get_aim_dir(Ind, &dir)) return (FALSE); (void)spell_wonder(Ind, dir); break; } case SPELL_POLYMORPH_OTHER: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s discharges an everchanging blast of energy."); (void)poly_monster(Ind, dir); break; } case SPELL_IDENTIFY: { return ident_spell(Ind); } case SPELL_MASS_SLEEP: { (void)sleep_monsters(Ind); break; } case SPELL_FIRE_BOLT: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a fire bolt."); fire_bolt_or_beam(Ind, beam, GF_FIRE, dir, damroll(6+((plev-5)/4), 8)); break; } case SPELL_SLOW_MONSTER: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s makes a lengthy gesture."); (void)slow_monster(Ind, dir); break; } case SPELL_FROST_BALL: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a frost ball."); fire_ball(Ind, GF_COLD, dir, 30 + (plev), 2); break; } case SPELL_RECHARGE_ITEM_II: /* greater recharging */ { return recharge(Ind, 50 + plev); } case SPELL_TELEPORT_OTHER: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s makes a rush gesture."); (void)teleport_monster(Ind, dir); break; } case SPELL_BEDLAM: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s creates confusion."); fire_ball(Ind, GF_OLD_CONF, dir, plev, 4); break; } case SPELL_FIRE_BALL: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a fire ball."); fire_ball(Ind, GF_FIRE, dir, 55 + (plev), 2); break; } case SPELL_WORD_OF_DESTRUCTION: { msg_spell("%s unleashes great power!"); destroy_area(Depth, py, px, 15, TRUE); break; } case SPELL_BANISHMENT: { return banishment(Ind); break; } case SPELL_DOOR_CREATION: { (void)door_creation(Ind); break; } case SPELL_STAIR_CREATION: { (void)stair_creation(Ind); break; } case SPELL_TELEPORT_LEVEL: { (void)teleport_player_level(Ind); break; } case SPELL_EARTHQUAKE: { msg_spell("%s casts a spell, and the ground shakes!"); earthquake(Depth, py, px, 10); break; } case SPELL_WORD_OF_RECALL: { o_ptr = &p_ptr->inventory[get_spell_book(Ind, spell)]; set_recall(Ind, o_ptr); break; } case SPELL_ACID_BOLT: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts an acid bolt."); fire_bolt_or_beam(Ind, beam, GF_ACID, dir, damroll(8+((plev-5)/4), 8)); break; } case SPELL_CLOUD_KILL: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a cloud of death."); fire_ball(Ind, GF_POIS, dir, 40 + (plev / 2), 3); break; } case SPELL_ACID_BALL: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts an acid ball."); fire_ball(Ind, GF_ACID, dir, 40 + (plev), 2); break; } case SPELL_ICE_STORM: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s invokes an ice storm."); fire_ball(Ind, GF_ICE, dir, 50 + (plev * 2), 3); break; } case SPELL_METEOR_SWARM: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a meteor shower."); fire_swarm(Ind, 2 + plev / 20, GF_METEOR, dir, 30 + plev / 2, 1); break; } case SPELL_MANA_STORM: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a mana ball."); fire_ball(Ind, GF_MANA, dir, 300 + (plev * 2), 3); break; } case SPELL_DETECT_INVISIBLE: { (void)detect_invisible(Ind, TRUE); break; } case SPELL_DETECT_ENCHANTMENT: { (void)detect_objects_magic(Ind); break; } case SPELL_SHOCK_WAVE: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a shock wave."); fire_ball(Ind, GF_SOUND, dir, 10 + plev, 2); break; } case SPELL_EXPLOSION: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts an explosion."); fire_ball(Ind, GF_SHARDS, dir, 20 + (plev * 2), 2); break; } case SPELL_MASS_BANISHMENT: { (void)mass_banishment(Ind); break; } case SPELL_RESIST_FIRE: { (void)set_oppose_fire(Ind, p_ptr->oppose_fire + randint(20) + 20); break; } case SPELL_RESIST_COLD: { (void)set_oppose_cold(Ind, p_ptr->oppose_cold + randint(20) + 20); break; } case SPELL_ELEMENTAL_BRAND: /* elemental brand */ { if (!get_item(Ind, &dir, item_test(AMMO))) return (FALSE); (void)brand_ammo(Ind, dir); break; } case SPELL_RESIST_POISON: { (void)set_oppose_pois(Ind, p_ptr->oppose_pois + randint(20) + 20); break; } case SPELL_RESISTANCE: { int time = randint(20) + 20; (void)set_oppose_acid(Ind, p_ptr->oppose_acid + time); (void)set_oppose_elec(Ind, p_ptr->oppose_elec + time); (void)set_oppose_fire(Ind, p_ptr->oppose_fire + time); (void)set_oppose_cold(Ind, p_ptr->oppose_cold + time); (void)set_oppose_pois(Ind, p_ptr->oppose_pois + time); break; } case SPELL_HEROISM: { (void)hp_player(Ind, 10); (void)set_hero(Ind, p_ptr->hero + randint(25) + 25); (void)set_afraid(Ind, 0); break; } case SPELL_SHIELD: { msg_spell("%s forms a mystic shield."); (void)set_shield(Ind, p_ptr->shield + randint(20) + 30); break; } case SPELL_BERSERKER: { msg_spell("%s enters a battle rage!"); (void)hp_player(Ind, 30); (void)set_shero(Ind, p_ptr->shero + randint(25) + 25); (void)set_afraid(Ind, 0); break; } case SPELL_HASTE_SELF: { msg_spell("%s starts moving faster."); if (!p_ptr->fast) { (void)set_fast(Ind, randint(20) + plev); } else { (void)set_fast(Ind, p_ptr->fast + randint(5)); } break; } case SPELL_RIFT: { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("Space warps in a beam from %s."); fire_beam(Ind, GF_GRAVITY, dir, 40 + damroll(plev, 7)); break; } case SPELL_REND_SOUL: /* rend soul */ { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a nether ball."); fire_bolt_or_beam(Ind, beam / 4, GF_NETHER, dir, damroll(11, plev)); break; } case SPELL_CHAOS_STRIKE: /* chaos strike */ { if (!get_aim_dir(Ind, &dir)) return (FALSE); msg_spell("%s casts a ball of chaos."); fire_bolt_or_beam(Ind, beam, GF_CHAOS, dir, damroll(13, plev)); break; } case SPELL_RUNE_OF_PROTECTION: /* rune of protection */ { if (warding_glyph(Ind)) { msg_spell("%s lays down a rune of protection."); } break; } case SPELL_ENCHANT_ARMOR: /* enchant armor */ { return enchant_spell(Ind, 0, 0, rand_int(3) + plev / 20); } case SPELL_ENCHANT_WEAPON: /* enchant weapon */ { return enchant_spell(Ind, rand_int(4) + plev / 20, rand_int(4) + plev / 20, 0); } } /* Success */ return (TRUE); }
/* * Use an object the right way. * * There may be a BIG problem with any "effect" that can cause "changes" * to the inventory. For example, a "scroll of recharging" can cause * a wand/staff to "disappear", moving the inventory up. Luckily, the * scrolls all appear BEFORE the staffs/wands, so this is not a problem. * But, for example, a "staff of recharging" could cause MAJOR problems. * In such a case, it will be best to either (1) "postpone" the effect * until the end of the function, or (2) "change" the effect, say, into * giving a staff "negative" charges, or "turning a staff into a stick". * It seems as though a "rod of recharging" might in fact cause problems. * The basic problem is that the act of recharging (and destroying) an * item causes the inducer of that action to "move", causing "o_ptr" to * no longer point at the correct item, with horrifying results. */ void do_cmd_use(cmd_code code, cmd_arg args[]) { int item = args[0].item; object_type *o_ptr = object_from_item_idx(item); int effect; bool ident = FALSE, used = FALSE; bool was_aware = object_flavor_is_aware(o_ptr); int dir = 5; int px = p_ptr->px, py = p_ptr->py; int snd, boost, level; use_type use; int items_allowed = 0; /* Determine how this item is used. */ if (obj_is_rod(o_ptr)) { if (!obj_can_zap(o_ptr)) { msg("That rod is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_wand(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That wand has no charges."); return; } use = USE_CHARGE; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_staff(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That staff has no charges."); return; } use = USE_CHARGE; snd = MSG_USE_STAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_food(o_ptr)) { use = USE_SINGLE; snd = MSG_EAT; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_potion(o_ptr)) { use = USE_SINGLE; snd = MSG_QUAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_scroll(o_ptr)) { /* Check player can use scroll */ if (!player_can_read()) return; use = USE_SINGLE; snd = MSG_GENERIC; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_activatable(o_ptr)) { if (!obj_can_activate(o_ptr)) { msg("That item is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ACT_ARTIFACT; items_allowed = USE_EQUIP; } else { msg("The item cannot be used at the moment"); } /* Check if item is within player's reach. */ if (items_allowed == 0 || !item_is_available(item, NULL, items_allowed)) { msg("You cannot use that item from its current location."); return; } /* track the object used */ track_object(item); /* Figure out effect to use */ effect = object_effect(o_ptr); /* If the item requires a direction, get one (allow cancelling) */ if (obj_needs_aim(o_ptr)) dir = args[1].direction; /* Check for use if necessary, and execute the effect */ if ((use != USE_CHARGE && use != USE_TIMEOUT) || check_devices(o_ptr)) { int beam = beam_chance(o_ptr->tval); /* Special message for artifacts */ if (o_ptr->artifact) { msgt(snd, "You activate it."); if (o_ptr->artifact->effect_msg) activation_message(o_ptr, o_ptr->artifact->effect_msg); level = o_ptr->artifact->level; } else { /* Make a noise! */ sound(snd); level = o_ptr->kind->level; } /* A bit of a hack to make ID work better. -- Check for "obvious" effects beforehand. */ if (effect_obvious(effect)) object_flavor_aware(o_ptr); /* Boost damage effects if skill > difficulty */ boost = MAX(p_ptr->state.skills[SKILL_DEVICE] - level, 0); /* Do effect */ used = effect_do(effect, &ident, was_aware, dir, beam, boost); /* Quit if the item wasn't used and no knowledge was gained */ if (!used && (was_aware || !ident)) return; } /* If the item is a null pointer or has been wiped, be done now */ if (!o_ptr || !o_ptr->kind) return; if (ident) object_notice_effect(o_ptr); /* Food feeds the player */ if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION) (void)set_food(p_ptr->food + o_ptr->pval[DEFAULT_PVAL]); /* Use the turn */ p_ptr->energy_use = 100; /* Mark as tried and redisplay */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); p_ptr->redraw |= (PR_INVEN | PR_EQUIP | PR_OBJECT); /* * If the player becomes aware of the item's function, then mark it as * aware and reward the player with some experience. Otherwise, mark * it as "tried". */ if (ident && !was_aware) { /* Object level */ int lev = o_ptr->kind->level; object_flavor_aware(o_ptr); if (o_ptr->tval == TV_ROD) object_notice_everything(o_ptr); player_exp_gain(p_ptr, (lev + (p_ptr->lev / 2)) / p_ptr->lev); p_ptr->notice |= PN_SQUELCH; } else if (used) { object_flavor_tried(o_ptr); } /* If there are no more of the item left, then we're done. */ if (!o_ptr->number) return; /* Chargeables act differently to single-used items when not used up */ if (used && use == USE_CHARGE) { /* Use a single charge */ o_ptr->pval[DEFAULT_PVAL]--; /* Describe charges */ if (item >= 0) inven_item_charges(item); else floor_item_charges(0 - item); } else if (used && use == USE_TIMEOUT) { /* Artifacts use their own special field */ if (o_ptr->artifact) o_ptr->timeout = randcalc(o_ptr->artifact->time, 0, RANDOMISE); else o_ptr->timeout += randcalc(o_ptr->kind->time, 0, RANDOMISE); } else if (used && use == USE_SINGLE) { /* Destroy a potion in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a potion on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } } /* Hack to make Glyph of Warding work properly */ if (cave->feat[py][px] == FEAT_GLYPH) { /* Push objects off the grid */ if (cave->o_idx[py][px]) push_object(py, px); } }