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); }
static bool use_staff(object_type *o_ptr, bool *ident) { int py = p_ptr->py; int px = p_ptr->px; int k; bool use_charge = TRUE; /* Analyze the staff */ switch (o_ptr->sval) { case SV_STAFF_DARKNESS: { if (!p_ptr->resist_blind) { if (set_blind(p_ptr->blind + 3 + randint(5))) *ident = TRUE; } if (unlite_area(10, 3)) *ident = TRUE; break; } case SV_STAFF_SLOWNESS: { if (set_slow(p_ptr->slow + randint(30) + 15)) *ident = TRUE; break; } case SV_STAFF_HASTE_MONSTERS: { if (speed_monsters()) *ident = TRUE; break; } case SV_STAFF_SUMMONING: { for (k = 0; k < randint(4); k++) { if (summon_specific(py, px, p_ptr->depth, 0)) { *ident = TRUE; } } break; } case SV_STAFF_TELEPORTATION: { teleport_player(100); *ident = TRUE; break; } case SV_STAFF_IDENTIFY: { if (!ident_spell()) use_charge = FALSE; *ident = TRUE; break; } case SV_STAFF_REMOVE_CURSE: { if (remove_curse()) { if (!p_ptr->blind) { msg_print("The staff glows blue for a moment..."); } *ident = TRUE; } break; } case SV_STAFF_STARLITE: { if (!p_ptr->blind) { msg_print("The end of the staff glows brightly..."); } for (k = 0; k < 8; k++) lite_line(ddd[k]); *ident = TRUE; break; } case SV_STAFF_LITE: { if (lite_area(damroll(2, 8), 2)) *ident = TRUE; break; } case SV_STAFF_MAPPING: { map_area(); *ident = TRUE; break; } case SV_STAFF_DETECT_GOLD: { if (detect_treasure()) *ident = TRUE; if (detect_objects_gold()) *ident = TRUE; break; } case SV_STAFF_DETECT_ITEM: { if (detect_objects_normal()) *ident = TRUE; break; } case SV_STAFF_DETECT_TRAP: { if (detect_traps()) *ident = TRUE; break; } case SV_STAFF_DETECT_DOOR: { if (detect_doors()) *ident = TRUE; if (detect_stairs()) *ident = TRUE; break; } case SV_STAFF_DETECT_INVIS: { if (detect_monsters_invis()) *ident = TRUE; break; } case SV_STAFF_DETECT_EVIL: { if (detect_monsters_evil()) *ident = TRUE; break; } case SV_STAFF_CURE_LIGHT: { if (hp_player(randint(8))) *ident = TRUE; break; } case SV_STAFF_CURING: { if (set_blind(0)) *ident = TRUE; if (set_poisoned(0)) *ident = TRUE; if (set_confused(0)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; break; } case SV_STAFF_HEALING: { if (hp_player(300)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; break; } case SV_STAFF_THE_MAGI: { if (do_res_stat(A_INT)) *ident = TRUE; if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; *ident = TRUE; msg_print("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); p_ptr->window |= (PW_PLAYER_0 | PW_PLAYER_1); } break; } case SV_STAFF_SLEEP_MONSTERS: { if (sleep_monsters()) *ident = TRUE; break; } case SV_STAFF_SLOW_MONSTERS: { if (slow_monsters()) *ident = TRUE; break; } case SV_STAFF_SPEED: { if (!p_ptr->fast) { if (set_fast(randint(30) + 15)) *ident = TRUE; } else { (void)set_fast(p_ptr->fast + 5); } break; } case SV_STAFF_PROBING: { probing(); *ident = TRUE; break; } case SV_STAFF_DISPEL_EVIL: { if (dispel_evil(60)) *ident = TRUE; break; } case SV_STAFF_POWER: { if (dispel_monsters(120)) *ident = TRUE; break; } case SV_STAFF_HOLINESS: { if (dispel_evil(120)) *ident = TRUE; k = 3 * p_ptr->lev; if (set_protevil(p_ptr->protevil + randint(25) + k)) *ident = TRUE; if (set_poisoned(0)) *ident = TRUE; if (set_afraid(0)) *ident = TRUE; if (hp_player(50)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; break; } case SV_STAFF_BANISHMENT: { (void)banishment(); *ident = TRUE; break; } case SV_STAFF_EARTHQUAKES: { earthquake(py, px, 10); *ident = TRUE; break; } case SV_STAFF_DESTRUCTION: { destroy_area(py, px, 15, TRUE); *ident = TRUE; break; } } return (use_charge); }
/* Use a staff. -RAK- */ void use() { int32u i; int j, k, item_val, chance, y, x; register int ident; register struct misc *m_ptr; register inven_type *i_ptr; free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_STAFF, TV_NEVER, &j, &k)) msg_print("You are not carrying any staffs."); else if (get_item(&item_val, "Use which staff?", j, k, 0)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; m_ptr = &py.misc; chance = m_ptr->save + stat_adj(A_INT) - (int)i_ptr->level - 5 + (class_level_adj[m_ptr->pclass][CLA_DEVICE] * m_ptr->lev / 3); if (py.flags.confused > 0) chance = chance / 2; if (chance <= 0) chance = 1; if (randint(chance) < USE_DEVICE) msg_print("You failed to use the staff properly."); else if (i_ptr->p1 > 0) { i = i_ptr->flags; ident = FALSE; (i_ptr->p1)--; switch(i) { case ST_HEALING: ident = hp_player(300); if (py.flags.stun>0) { if (py.flags.stun>50) { py.misc.ptohit+=20; py.misc.ptodam+=20; } else { py.misc.ptohit+=5; py.misc.ptodam+=5; } py.flags.stun=0; ident = TRUE; msg_print("You're head stops stinging."); } if (py.flags.cut>0) { py.flags.cut=0; ident = TRUE; msg_print("You feel better."); } break; case ST_GENOCIDE: genocide(FALSE); ident = TRUE; break; case ST_PROBE: probing(); ident = TRUE; break; case ST_IDENTIFY: ident_spell(); ident = TRUE; break; case ST_HOLYNESS: dispel_creature(EVIL,120); protect_evil(); cure_poison(); remove_fear(); hp_player(50); if (py.flags.stun>0) { if (py.flags.stun>50) { py.misc.ptohit+=20; py.misc.ptodam+=20; } else { py.misc.ptohit+=5; py.misc.ptodam+=5; } py.flags.stun=0; ident = TRUE; msg_print("You're head stops stinging."); } if (py.flags.cut>0) { py.flags.cut=0; ident = TRUE; msg_print("You feel better."); } ident = TRUE; break; case ST_MAGI: if (res_stat(A_INT)) { msg_print("You have a warm feeling."); ident = TRUE; } m_ptr = &py.misc; if (m_ptr->cmana < m_ptr->mana) { m_ptr->cmana = m_ptr->mana; ident = TRUE; msg_print("Your feel your head clear."); prt_cmana(); } break; case ST_POWER: dispel_creature(0xFFFFFFFFL,120); break; case ST_SURROUND: map_area(); ident = TRUE; break; case ST_LIGHT: ident = light_area(char_row, char_col); break; case ST_DR_LC: ident = detect_sdoor(); break; case ST_TRP_LC: ident = detect_trap(); break; case ST_TRE_LC: ident = detect_treasure(); break; case ST_OBJ_LC: ident = detect_object(); break; case ST_TELE: teleport(100); ident = TRUE; break; case ST_EARTH: ident = TRUE; earthquake(); break; case ST_SUMMON: ident = FALSE; for (k = 0; k < randint(4); k++) { y = char_row; x = char_col; ident |= summon_monster(&y, &x, FALSE); } break; case ST_DEST: ident = TRUE; destroy_area(char_row, char_col); break; case ST_STAR: ident = TRUE; starlite(char_row, char_col); break; case ST_HAST_MN: ident = speed_monsters(1); break; case ST_SLOW_MN: ident = speed_monsters(-1); break; case ST_SLEE_MN: ident = sleep_monsters2(); break; case ST_CURE_LT: ident = hp_player(randint(8)); break; case ST_DET_INV: ident = detect_invisible(); break; case ST_SPEED: if (py.flags.fast == 0) ident = TRUE; if (py.flags.fast <= 0) py.flags.fast += randint(30) + 15; else py.flags.fast += randint(5); break; case ST_SLOW: if (py.flags.slow == 0) ident = TRUE; py.flags.slow += randint(30) + 15; break; case ST_REMOVE: if (remove_curse()) { if (py.flags.blind < 1) msg_print("The staff glows blue for a moment.."); ident = TRUE; } break; case ST_DET_EVI: ident = detect_evil(); break; case ST_CURING: if ((cure_blindness()) || (cure_poison()) || (cure_confusion()) || (py.flags.stun>0) || (py.flags.cut>0)) ident = TRUE; if (py.flags.stun>0) { if (py.flags.stun>50) { py.misc.ptohit+=20; py.misc.ptodam+=20; } else { py.misc.ptohit+=5; py.misc.ptodam+=5; } py.flags.stun=0; msg_print("You're head stops stinging."); } else if (py.flags.cut>0) { py.flags.cut=0; msg_print("You feel better."); } break; case ST_DSP_EVI: ident = dispel_creature(EVIL, 60); break; case ST_DARK: ident = unlight_area(char_row, char_col); break; default: msg_print("Internal error in staffs()"); break; } if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } }
/** * Attack the monster at the given location with a single blow. */ static bool py_attack_real(int y, int x, bool *fear) { /* Information about the target of the attack */ monster_type *m_ptr = cave_monster_at(cave, y, x); monster_race *r_ptr = &r_info[m_ptr->r_idx]; char m_name[80]; bool stop = FALSE; /* The weapon used */ object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD]; /* Information about the attack */ int bonus = p_ptr->state.to_h + o_ptr->to_h; int chance = p_ptr->state.skills[SKILL_TO_HIT_MELEE] + bonus * BTH_PLUS_ADJ; bool do_quake = FALSE; bool success = FALSE; /* Default to punching for one damage */ const char *hit_verb = "punch"; int dmg = 1; u32b msg_type = MSG_HIT; /* Extract monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Auto-Recall if possible and visible */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Track a new monster */ if (m_ptr->ml) health_track(p_ptr, m_ptr); /* Handle player fear (only for invisible monsters) */ if (check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) { msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); return FALSE; } /* Disturb the monster */ mon_clear_timed(m_ptr, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, FALSE); /* See if the player hit */ success = test_hit(chance, r_ptr->ac, m_ptr->ml); /* If a miss, skip this hit */ if (!success) { msgt(MSG_MISS, "You miss %s.", m_name); return FALSE; } /* Handle normal weapon */ if (o_ptr->kind) { int i; const struct slay *best_s_ptr = NULL; hit_verb = "hit"; /* Get the best attack from all slays or * brands on all non-launcher equipment */ for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { struct object *obj = &p_ptr->inventory[i]; if (obj->kind) improve_attack_modifier(obj, m_ptr, &best_s_ptr, TRUE, FALSE); } improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr, TRUE, FALSE); if (best_s_ptr != NULL) hit_verb = best_s_ptr->melee_verb; dmg = damroll(o_ptr->dd, o_ptr->ds); dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult; dmg += o_ptr->to_d; dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type); /* Learn by use for the weapon */ object_notice_attack_plusses(o_ptr); if (check_state(p_ptr, OF_IMPACT, p_ptr->state.flags) && dmg > 50) { do_quake = TRUE; wieldeds_notice_flag(p_ptr, OF_IMPACT); } } /* Learn by use for other equipped items */ wieldeds_notice_on_attack(); /* Apply the player damage bonuses */ dmg += p_ptr->state.to_d; /* No negative damage */ if (dmg <= 0) dmg = 0; /* Tell the player what happened */ if (dmg <= 0) msgt(MSG_MISS, "You fail to harm %s.", m_name); else if (msg_type == MSG_HIT) msgt(MSG_HIT, "You %s %s.", hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) msgt(MSG_HIT_GOOD, "You %s %s. %s", hit_verb, m_name, "It was a good hit!"); else if (msg_type == MSG_HIT_GREAT) msgt(MSG_HIT_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a great hit!"); else if (msg_type == MSG_HIT_SUPERB) msgt(MSG_HIT_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a superb hit!"); else if (msg_type == MSG_HIT_HI_GREAT) msgt(MSG_HIT_HI_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a *GREAT* hit!"); else if (msg_type == MSG_HIT_HI_SUPERB) msgt(MSG_HIT_HI_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a *SUPERB* hit!"); /* Complex message */ if (p_ptr->wizard) msg("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Confusion attack */ if (p_ptr->confusing) { p_ptr->confusing = FALSE; msg("Your hands stop glowing."); mon_inc_timed(m_ptr, MON_TMD_CONF, (10 + randint0(p_ptr->lev) / 10), MON_TMD_FLG_NOTIFY, FALSE); } /* Damage, check for fear and death */ stop = mon_take_hit(m_ptr, dmg, fear, NULL); if (stop) (*fear) = FALSE; /* Apply earthquake brand */ if (do_quake) { earthquake(p_ptr->py, p_ptr->px, 10); if (cave->m_idx[y][x] == 0) stop = TRUE; } return stop; }
/* * Attack the player via physical attacks. */ bool make_attack_normal(int m_idx) { monster_type *m_ptr = &mon_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; int ap_cnt; int i, k, tmp, ac, rlev; int do_cut, do_stun; s32b gold; object_type *o_ptr; char o_name[80]; char m_name[80]; char ddesc[80]; bool blinked; /* Not allowed to attack */ if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE); /* Total armor */ ac = p_ptr->ac + p_ptr->to_a; /* Extract the effective monster level */ rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Get the "died from" information (i.e. "a kobold") */ monster_desc(ddesc, sizeof(ddesc), m_ptr, 0x88); /* Assume no blink */ blinked = FALSE; /* Scan through all blows */ for (ap_cnt = 0; ap_cnt < MONSTER_BLOW_MAX; ap_cnt++) { bool visible = FALSE; bool obvious = FALSE; int power = 0; int damage = 0; cptr act = NULL; /* Extract the attack infomation */ int effect = r_ptr->blow[ap_cnt].effect; int method = r_ptr->blow[ap_cnt].method; int d_dice = r_ptr->blow[ap_cnt].d_dice; int d_side = r_ptr->blow[ap_cnt].d_side; /* Hack -- no more attacks */ if (!method) break; /* Handle "leaving" */ if (p_ptr->leaving) break; /* Extract visibility (before blink) */ if (m_ptr->ml) visible = TRUE; /* Extract the attack "power" */ switch (effect) { case RBE_HURT: power = 60; break; case RBE_POISON: power = 5; break; case RBE_UN_BONUS: power = 20; break; case RBE_UN_POWER: power = 15; break; case RBE_EAT_GOLD: power = 5; break; case RBE_EAT_ITEM: power = 5; break; case RBE_EAT_FOOD: power = 5; break; case RBE_EAT_LITE: power = 5; break; case RBE_ACID: power = 0; break; case RBE_ELEC: power = 10; break; case RBE_FIRE: power = 10; break; case RBE_COLD: power = 10; break; case RBE_BLIND: power = 2; break; case RBE_CONFUSE: power = 10; break; case RBE_TERRIFY: power = 10; break; case RBE_PARALYZE: power = 2; break; case RBE_LOSE_STR: power = 0; break; case RBE_LOSE_DEX: power = 0; break; case RBE_LOSE_CON: power = 0; break; case RBE_LOSE_INT: power = 0; break; case RBE_LOSE_WIS: power = 0; break; case RBE_LOSE_CHR: power = 0; break; case RBE_LOSE_ALL: power = 2; break; case RBE_SHATTER: power = 60; break; case RBE_EXP_10: power = 5; break; case RBE_EXP_20: power = 5; break; case RBE_EXP_40: power = 5; break; case RBE_EXP_80: power = 5; break; case RBE_HALLU: power = 10; break; } /* Monster hits player */ if (!effect || check_hit(power, rlev)) { /* Always disturbing */ disturb(1, 0); /* Hack -- Apply "protection from evil" */ if ((p_ptr->protevil > 0) && (r_ptr->flags3 & (RF3_EVIL)) && (p_ptr->lev >= rlev) && ((rand_int(100) + p_ptr->lev) > 50)) { /* Remember the Evil-ness */ if (m_ptr->ml) { l_ptr->flags3 |= (RF3_EVIL); } /* Message */ msg_format("%^s is repelled.", m_name); /* Hack -- Next attack */ continue; } /* Assume no cut or stun */ do_cut = do_stun = 0; /* Describe the attack method */ switch (method) { case RBM_HIT: { act = "hits you."; do_cut = do_stun = 1; break; } case RBM_TOUCH: { act = "touches you."; break; } case RBM_PUNCH: { act = "punches you."; do_stun = 1; break; } case RBM_KICK: { act = "kicks you."; do_stun = 1; break; } case RBM_CLAW: { act = "claws you."; do_cut = 1; break; } case RBM_BITE: { act = "bites you."; do_cut = 1; break; } case RBM_STING: { act = "stings you."; break; } case RBM_XXX1: { act = "XXX1's you."; break; } case RBM_BUTT: { act = "butts you."; do_stun = 1; break; } case RBM_CRUSH: { act = "crushes you."; do_stun = 1; break; } case RBM_ENGULF: { act = "engulfs you."; break; } case RBM_XXX2: { act = "XXX2's you."; break; } case RBM_CRAWL: { act = "crawls on you."; break; } case RBM_DROOL: { act = "drools on you."; break; } case RBM_SPIT: { act = "spits on you."; break; } case RBM_XXX3: { act = "XXX3's on you."; break; } case RBM_GAZE: { act = "gazes at you."; break; } case RBM_WAIL: { act = "wails at you."; break; } case RBM_SPORE: { act = "releases spores at you."; break; } case RBM_XXX4: { act = "projects XXX4's at you."; break; } case RBM_BEG: { act = "begs you for money."; break; } case RBM_INSULT: { act = desc_insult[rand_int(MAX_DESC_INSULT)]; break; } case RBM_MOAN: { act = desc_moan[rand_int(MAX_DESC_MOAN)]; break; } case RBM_XXX5: { act = "XXX5's you."; break; } } /* Message */ if (act) msg_format("%^s %s", m_name, act); /* Hack -- assume all attacks are obvious */ obvious = TRUE; /* Roll out the damage */ damage = damroll(d_dice, d_side); /* Apply appropriate damage */ switch (effect) { case 0: { /* Hack -- Assume obvious */ obvious = TRUE; /* Hack -- No damage */ damage = 0; break; } case RBE_HURT: { /* Obvious */ obvious = TRUE; /* Hack -- Player armor reduces total damage */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ take_hit(damage, ddesc); break; } case RBE_POISON: { /* Take damage */ take_hit(damage, ddesc); /* Take "poison" effect */ if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) { if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5)) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_POIS); break; } case RBE_UN_BONUS: { /* Take damage */ take_hit(damage, ddesc); /* Allow complete resist */ if (!p_ptr->resist_disen) { /* Apply disenchantment */ if (apply_disenchant(0)) obvious = TRUE; } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_DISEN); break; } case RBE_UN_POWER: { /* Take damage */ take_hit(damage, ddesc); /* Find an item */ for (k = 0; k < 10; k++) { /* Pick an item */ i = rand_int(INVEN_PACK); /* Obtain the item */ o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) && (o_ptr->pval > 0)) { /* Calculate healed hitpoints */ int heal = rlev * o_ptr->pval * o_ptr->number; /* Don't heal more than max hp */ heal = MIN(heal, m_ptr->maxhp - m_ptr->hp); /* Message */ msg_print("Energy drains from your pack!"); /* Obvious */ obvious = TRUE; /* Heal */ m_ptr->hp += heal; /* Redraw (later) if needed */ if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); /* Uncharge */ o_ptr->pval = 0; /* Combine / Reorder the pack */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Window stuff */ p_ptr->window |= (PW_INVEN); /* Done */ break; } } break; } case RBE_EAT_GOLD: { /* Take damage */ take_hit(damage, ddesc); /* Obvious */ obvious = TRUE; /* Saving throw (unless paralyzed) based on dex and level */ if (!p_ptr->paralyzed && (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] + p_ptr->lev))) { /* Saving throw message */ msg_print("You quickly protect your money pouch!"); /* Occasional blink anyway */ if (rand_int(3)) blinked = TRUE; } /* Eat gold */ else { gold = (p_ptr->au / 10) + randint(25); if (gold < 2) gold = 2; if (gold > 5000) gold = (p_ptr->au / 20) + randint(3000); if (gold > p_ptr->au) gold = p_ptr->au; p_ptr->au -= gold; if (gold <= 0) { msg_print("Nothing was stolen."); } else if (p_ptr->au) { msg_print("Your purse feels lighter."); msg_format("%ld coins were stolen!", (long)gold); } else { msg_print("Your purse feels lighter."); msg_print("All of your coins were stolen!"); } /* Redraw gold */ p_ptr->redraw |= (PR_GOLD); /* Window stuff */ p_ptr->window |= (PW_PLAYER_0 | PW_PLAYER_1); /* Blink away */ blinked = TRUE; } break; } case RBE_EAT_ITEM: { /* Take damage */ take_hit(damage, ddesc); /* Saving throw (unless paralyzed) based on dex and level */ if (!p_ptr->paralyzed && (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] + p_ptr->lev))) { /* Saving throw message */ msg_print("You grab hold of your backpack!"); /* Occasional "blink" anyway */ blinked = TRUE; /* Obvious */ obvious = TRUE; /* Done */ break; } /* Find an item */ for (k = 0; k < 10; k++) { object_type *i_ptr; object_type object_type_body; /* Pick an item */ i = rand_int(INVEN_PACK); /* Obtain the item */ o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Skip artifacts */ if (artifact_p(o_ptr)) continue; /* Get a description */ object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 3); /* Message */ msg_format("%sour %s (%c) was stolen!", ((o_ptr->number > 1) ? "One of y" : "Y"), o_name, index_to_label(i)); /* Get local object */ i_ptr = &object_type_body; /* Obtain local object */ object_copy(i_ptr, o_ptr); /* Modify number */ i_ptr->number = 1; /* Carry the object */ (void)monster_carry(m_idx, i_ptr); /* Steal the items */ inven_item_increase(i, -1); inven_item_optimize(i); /* Obvious */ obvious = TRUE; /* Blink away */ blinked = TRUE; /* Done */ break; } break; } case RBE_EAT_FOOD: { /* Take damage */ take_hit(damage, ddesc); /* Steal some food */ for (k = 0; k < 10; k++) { /* Pick an item from the pack */ i = rand_int(INVEN_PACK); /* Get the item */ o_ptr = &inventory[i]; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Skip non-food objects */ if (o_ptr->tval != TV_FOOD) continue; /* Get a description */ object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 0); /* Message */ msg_format("%sour %s (%c) was eaten!", ((o_ptr->number > 1) ? "One of y" : "Y"), o_name, index_to_label(i)); /* Steal the items */ inven_item_increase(i, -1); inven_item_optimize(i); /* Obvious */ obvious = TRUE; /* Done */ break; } break; } case RBE_EAT_LITE: { /* Take damage */ take_hit(damage, ddesc); /* Get the lite */ o_ptr = &inventory[INVEN_LITE]; /* Drain fuel */ if ((o_ptr->pval > 0) && (!artifact_p(o_ptr))) { /* Reduce fuel */ o_ptr->pval -= (250 + randint(250)); if (o_ptr->pval < 1) o_ptr->pval = 1; /* Notice */ if (!p_ptr->blind) { msg_print("Your light dims."); obvious = TRUE; } /* Window stuff */ p_ptr->window |= (PW_EQUIP); } break; } case RBE_ACID: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered in acid!"); /* Special damage */ acid_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_ACID); break; } case RBE_ELEC: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are struck by electricity!"); /* Take damage (special) */ elec_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_ELEC); break; } case RBE_FIRE: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are enveloped in flames!"); /* Take damage (special) */ fire_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_FIRE); break; } case RBE_COLD: { /* Obvious */ obvious = TRUE; /* Message */ msg_print("You are covered with frost!"); /* Take damage (special) */ cold_dam(damage, ddesc); /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_COLD); break; } case RBE_BLIND: { /* Take damage */ take_hit(damage, ddesc); /* Increase "blind" */ if (!p_ptr->resist_blind) { if (set_blind(p_ptr->blind + 10 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_BLIND); break; } case RBE_CONFUSE: { /* Take damage */ take_hit(damage, ddesc); /* Increase "confused" */ if (!p_ptr->resist_confu) { if (set_confused(p_ptr->confused + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_CONFU); break; } case RBE_TERRIFY: { /* Take damage */ take_hit(damage, ddesc); /* Increase "afraid" */ if (p_ptr->resist_fear) { msg_print("You stand your ground!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You stand your ground!"); obvious = TRUE; } else { if (set_afraid(p_ptr->afraid + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_FEAR); break; } case RBE_PARALYZE: { /* Hack -- Prevent perma-paralysis via damage */ if (p_ptr->paralyzed && (damage < 1)) damage = 1; /* Take damage */ take_hit(damage, ddesc); /* Increase "paralyzed" */ if (p_ptr->free_act) { msg_print("You are unaffected!"); obvious = TRUE; } else if (rand_int(100) < p_ptr->skill_sav) { msg_print("You resist the effects!"); obvious = TRUE; } else { if (set_paralyzed(p_ptr->paralyzed + 3 + randint(rlev))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_FREE); break; } case RBE_LOSE_STR: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_STR)) obvious = TRUE; break; } case RBE_LOSE_INT: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_INT)) obvious = TRUE; break; } case RBE_LOSE_WIS: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_WIS)) obvious = TRUE; break; } case RBE_LOSE_DEX: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_DEX)) obvious = TRUE; break; } case RBE_LOSE_CON: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CON)) obvious = TRUE; break; } case RBE_LOSE_CHR: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stat) */ if (do_dec_stat(A_CHR)) obvious = TRUE; break; } case RBE_LOSE_ALL: { /* Take damage */ take_hit(damage, ddesc); /* Damage (stats) */ if (do_dec_stat(A_STR)) obvious = TRUE; if (do_dec_stat(A_DEX)) obvious = TRUE; if (do_dec_stat(A_CON)) obvious = TRUE; if (do_dec_stat(A_INT)) obvious = TRUE; if (do_dec_stat(A_WIS)) obvious = TRUE; if (do_dec_stat(A_CHR)) obvious = TRUE; break; } case RBE_SHATTER: { /* Obvious */ obvious = TRUE; /* Hack -- Reduce damage based on the player armor class */ damage -= (damage * ((ac < 150) ? ac : 150) / 250); /* Take damage */ take_hit(damage, ddesc); /* Radius 8 earthquake centered at the monster */ if (damage > 23) earthquake(m_ptr->fy, m_ptr->fx, 8); break; } case RBE_EXP_10: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 95)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(10, 6) + (p_ptr->exp/100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d/10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_20: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 90)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_40: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 75)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_EXP_80: { /* Obvious */ obvious = TRUE; /* Take damage */ take_hit(damage, ddesc); if (p_ptr->hold_life && (rand_int(100) < 50)) { msg_print("You keep hold of your life force!"); } else { s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE; if (p_ptr->hold_life) { msg_print("You feel your life slipping away!"); lose_exp(d / 10); } else { msg_print("You feel your life draining away!"); lose_exp(d); } } break; } case RBE_HALLU: { /* Take damage */ take_hit(damage, ddesc); /* Increase "image" */ if (!p_ptr->resist_chaos) { if (set_image(p_ptr->image + 3 + randint(rlev / 2))) { obvious = TRUE; } } /* Learn about the player */ update_smart_learn(m_idx, DRS_RES_CHAOS); break; } } /* Hack -- only one of cut or stun */ if (do_cut && do_stun) { /* Cancel cut */ if (rand_int(100) < 50) { do_cut = 0; } /* Cancel stun */ else { do_stun = 0; } } /* Handle cut */ if (do_cut) { int k; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(5) + 5; break; case 3: k = randint(20) + 20; break; case 4: k = randint(50) + 50; break; case 5: k = randint(100) + 100; break; case 6: k = 300; break; default: k = 500; break; } /* Apply the cut */ if (k) (void)set_cut(p_ptr->cut + k); } /* Handle stun */ if (do_stun) { int k; /* Critical hit (zero if non-critical) */ tmp = monster_critical(d_dice, d_side, damage); /* Roll for damage */ switch (tmp) { case 0: k = 0; break; case 1: k = randint(5); break; case 2: k = randint(10) + 10; break; case 3: k = randint(20) + 20; break; case 4: k = randint(30) + 30; break; case 5: k = randint(40) + 40; break; case 6: k = 100; break; default: k = 200; break; } /* Apply the stun */ if (k) (void)set_stun(p_ptr->stun + k); } } /* Monster missed player */ else { /* Analyze failed attacks */ switch (method) { case RBM_HIT: case RBM_TOUCH: case RBM_PUNCH: case RBM_KICK: case RBM_CLAW: case RBM_BITE: case RBM_STING: case RBM_XXX1: case RBM_BUTT: case RBM_CRUSH: case RBM_ENGULF: case RBM_XXX2: /* Visible monsters */ if (m_ptr->ml) { /* Disturbing */ disturb(1, 0); /* Message */ msg_format("%^s misses you.", m_name); } break; } } /* Analyze "visible" monsters only */ if (visible) { /* Count "obvious" attacks (and ones that cause damage) */ if (obvious || damage || (l_ptr->blows[ap_cnt] > 10)) { /* Count attacks of this type */ if (l_ptr->blows[ap_cnt] < MAX_UCHAR) { l_ptr->blows[ap_cnt]++; } } } } /* Blink away */ if (blinked) { msg_print("There is a puff of smoke!"); teleport_away(m_idx, MAX_SIGHT * 2 + 5); } /* Always notice cause of death */ if (p_ptr->is_dead && (l_ptr->deaths < MAX_SHORT)) { l_ptr->deaths++; } /* Assume we attacked */ return (TRUE); }
/* * Do an effect, given an object. * Boost is the extent to which skill surpasses difficulty, used as % boost. It * ranges from 0 to 138. */ bool effect_do(effect_type effect, bool *ident, bool aware, int dir, int beam, int boost) { int py = p_ptr->py; int px = p_ptr->px; int dam, chance, dur; if (effect < 1 || effect > EF_MAX) { msg("Bad effect passed to do_effect(). Please report this bug."); return FALSE; } switch (effect) { case EF_POISON: { player_inc_timed(p_ptr, TMD_POISONED, damroll(2, 7) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_BLIND: { player_inc_timed(p_ptr, TMD_BLIND, damroll(4, 25) + 75, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SCARE: { player_inc_timed(p_ptr, TMD_AFRAID, randint0(10) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_CONFUSE: { player_inc_timed(p_ptr, TMD_CONFUSED, damroll(4, 5) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_HALLUC: { player_inc_timed(p_ptr, TMD_IMAGE, randint0(250) + 250, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_PARALYZE: { player_inc_timed(p_ptr, TMD_PARALYZED, randint0(5) + 5, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SLOW: { if (player_inc_timed(p_ptr, TMD_SLOW, randint1(25) + 15, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_POISON: { if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BLINDNESS: { if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_PARANOIA: { if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CONFUSION: { if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_MIND: { if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_IMAGE, TRUE)) *ident = TRUE; if (!of_has(p_ptr->state.flags, OF_RES_CONFU) && player_inc_timed(p_ptr, TMD_OPP_CONF, damroll(4, 10), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BODY: { if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_LIGHT: { if (hp_player(20)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_dec_timed(p_ptr, TMD_CUT, 20, TRUE)) *ident = TRUE; if (player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_SERIOUS: { if (hp_player(40)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CRITICAL: { if (hp_player(60)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_FULL: { int amt = (p_ptr->mhp * 35) / 100; if (amt < 300) amt = 300; if (hp_player(amt)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_FULL2: { if (hp_player(1200)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_TEMP: { if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL1: { if (hp_player(500)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL2: { if (hp_player(1000)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL3: { if (hp_player(500)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_GAIN_EXP: { if (p_ptr->exp < PY_MAX_EXP) { msg("You feel more experienced."); player_exp_gain(p_ptr, 100000L); *ident = TRUE; } return TRUE; } case EF_LOSE_EXP: { if (!check_state(p_ptr, OF_HOLD_LIFE, p_ptr->state.flags) && (p_ptr->exp > 0)) { msg("You feel your memories fade."); player_exp_lose(p_ptr, p_ptr->exp / 4, FALSE); *ident = TRUE; } *ident = TRUE; wieldeds_notice_flag(p_ptr, OF_HOLD_LIFE); return TRUE; } case EF_RESTORE_EXP: { if (restore_level()) *ident = TRUE; return TRUE; } case EF_RESTORE_MANA: { if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); *ident = TRUE; } return TRUE; } case EF_GAIN_STR: case EF_GAIN_INT: case EF_GAIN_WIS: case EF_GAIN_DEX: case EF_GAIN_CON: case EF_GAIN_CHR: { int stat = effect - EF_GAIN_STR; if (do_inc_stat(stat)) *ident = TRUE; return TRUE; } case EF_GAIN_ALL: { if (do_inc_stat(A_STR)) *ident = TRUE; if (do_inc_stat(A_INT)) *ident = TRUE; if (do_inc_stat(A_WIS)) *ident = TRUE; if (do_inc_stat(A_DEX)) *ident = TRUE; if (do_inc_stat(A_CON)) *ident = TRUE; if (do_inc_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_BRAWN: { /* Pick a random stat to decrease other than strength */ int stat = randint0(A_MAX-1) + 1; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_STR); *ident = TRUE; } return TRUE; } case EF_INTELLECT: { /* Pick a random stat to decrease other than intelligence */ int stat = randint0(A_MAX-1); if (stat >= A_INT) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_INT); *ident = TRUE; } return TRUE; } case EF_CONTEMPLATION: { /* Pick a random stat to decrease other than wisdom */ int stat = randint0(A_MAX-1); if (stat >= A_WIS) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_WIS); *ident = TRUE; } return TRUE; } case EF_TOUGHNESS: { /* Pick a random stat to decrease other than constitution */ int stat = randint0(A_MAX-1); if (stat >= A_CON) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_CON); *ident = TRUE; } return TRUE; } case EF_NIMBLENESS: { /* Pick a random stat to decrease other than dexterity */ int stat = randint0(A_MAX-1); if (stat >= A_DEX) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_DEX); *ident = TRUE; } return TRUE; } case EF_PLEASING: { /* Pick a random stat to decrease other than charisma */ int stat = randint0(A_MAX-1); if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_CHR); *ident = TRUE; } return TRUE; } case EF_LOSE_STR: case EF_LOSE_INT: case EF_LOSE_WIS: case EF_LOSE_DEX: case EF_LOSE_CON: case EF_LOSE_CHR: { int stat = effect - EF_LOSE_STR; take_hit(p_ptr, damroll(5, 5), "stat drain"); (void)do_dec_stat(stat, FALSE); *ident = TRUE; return TRUE; } case EF_LOSE_CON2: { take_hit(p_ptr, damroll(10, 10), "poisonous food"); (void)do_dec_stat(A_CON, FALSE); *ident = TRUE; return TRUE; } case EF_RESTORE_STR: case EF_RESTORE_INT: case EF_RESTORE_WIS: case EF_RESTORE_DEX: case EF_RESTORE_CON: case EF_RESTORE_CHR: { int stat = effect - EF_RESTORE_STR; if (do_res_stat(stat)) *ident = TRUE; return TRUE; } case EF_CURE_NONORLYBIG: { msg("You feel life flow through your body!"); restore_level(); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_IMAGE, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE); if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; /* Recalculate max. hitpoints */ update_stuff(p_ptr); hp_player(5000); *ident = TRUE; return TRUE; } case EF_RESTORE_ALL: { /* Life, above, also gives these effects */ if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_RESTORE_ST_LEV: { if (restore_level()) *ident = TRUE; if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_TMD_INFRA: { if (player_inc_timed(p_ptr, TMD_SINFRA, 100 + damroll(4, 25), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_SINVIS: { if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_SINVIS, 12 + damroll(2, 6), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_ESP: { if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_TELEPATHY, 12 + damroll(6, 6), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_ENLIGHTENMENT: { msg("An image of your surroundings forms in your mind..."); wiz_light(); *ident = TRUE; return TRUE; } case EF_ENLIGHTENMENT2: { msg("You begin to feel more enlightened..."); message_flush(); wiz_light(); (void)do_inc_stat(A_INT); (void)do_inc_stat(A_WIS); (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); (void)detect_treasure(TRUE, TRUE); identify_pack(); *ident = TRUE; return TRUE; } case EF_HERO: { dur = randint1(25) + 25; if (hp_player(10)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_HERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHERO: { dur = randint1(25) + 25; if (hp_player(30)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ACID: { if (player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ELEC: { if (player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_FIRE: { if (player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_COLD: { if (player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_POIS: { if (player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ALL: { if (player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_DETECT_TREASURE: { if (detect_treasure(aware, FALSE)) *ident = TRUE; return TRUE; } case EF_DETECT_TRAP: { if (detect_traps(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_DOORSTAIR: { if (detect_doorstairs(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_INVIS: { if (detect_monsters_invis(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_EVIL: { if (detect_monsters_evil(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_ALL: { if (detect_all(aware)) *ident = TRUE; return TRUE; } case EF_ENCHANT_TOHIT: { *ident = TRUE; return enchant_spell(1, 0, 0); } case EF_ENCHANT_TODAM: { *ident = TRUE; return enchant_spell(0, 1, 0); } case EF_ENCHANT_WEAPON: { *ident = TRUE; return enchant_spell(randint1(3), randint1(3), 0); } case EF_ENCHANT_ARMOR: { *ident = TRUE; return enchant_spell(0, 0, 1); } case EF_ENCHANT_ARMOR2: { *ident = TRUE; return enchant_spell(0, 0, randint1(3) + 2); } case EF_RESTORE_ITEM: { *ident = TRUE; return restore_item(); } case EF_IDENTIFY: { *ident = TRUE; if (!ident_spell()) return FALSE; return TRUE; } case EF_REMOVE_CURSE: { if (remove_curse()) { if (!p_ptr->timed[TMD_BLIND]) msg("The air around your body glows blue for a moment..."); else msg("You feel as if someone is watching over you."); *ident = TRUE; } return TRUE; } case EF_REMOVE_CURSE2: { remove_all_curse(); *ident = TRUE; return TRUE; } case EF_LIGHT: { if (light_area(damroll(2, 8), 2)) *ident = TRUE; return TRUE; } case EF_SUMMON_MON: { int i; sound(MSG_SUM_MONSTER); for (i = 0; i < randint1(3); i++) { if (summon_specific(py, px, p_ptr->depth, 0, 1)) *ident = TRUE; } return TRUE; } case EF_SUMMON_UNDEAD: { int i; sound(MSG_SUM_UNDEAD); for (i = 0; i < randint1(3); i++) { if (summon_specific(py, px, p_ptr->depth, S_UNDEAD, 1)) *ident = TRUE; } return TRUE; } case EF_TELE_PHASE: { teleport_player(10); *ident = TRUE; return TRUE; } case EF_TELE_LONG: { teleport_player(100); *ident = TRUE; return TRUE; } case EF_TELE_LEVEL: { (void)teleport_player_level(); *ident = TRUE; return TRUE; } case EF_CONFUSING: { if (p_ptr->confusing == 0) { msg("Your hands begin to glow."); p_ptr->confusing = TRUE; *ident = TRUE; } return TRUE; } case EF_MAPPING: { map_area(); *ident = TRUE; return TRUE; } case EF_RUNE: { warding_glyph(); *ident = TRUE; return TRUE; } case EF_ACQUIRE: { acquirement(py, px, p_ptr->depth, 1, TRUE); *ident = TRUE; return TRUE; } case EF_ACQUIRE2: { acquirement(py, px, p_ptr->depth, randint1(2) + 1, TRUE); *ident = TRUE; return TRUE; } case EF_ANNOY_MON: { msg("There is a high pitched humming noise."); aggravate_monsters(0); *ident = TRUE; return TRUE; } case EF_CREATE_TRAP: { /* Hack -- no traps in the town */ if (p_ptr->depth == 0) return TRUE; trap_creation(); msg("You hear a low-pitched whistling sound."); *ident = TRUE; return TRUE; } case EF_DESTROY_TDOORS: { if (destroy_doors_touch()) *ident = TRUE; return TRUE; } case EF_RECHARGE: { *ident = TRUE; if (!recharge(60)) return FALSE; return TRUE; } case EF_BANISHMENT: { *ident = TRUE; if (!banishment()) return FALSE; return TRUE; } case EF_DARKNESS: { if (!check_state(p_ptr, OF_RES_DARK, p_ptr->state.flags)) (void)player_inc_timed(p_ptr, TMD_BLIND, 3 + randint1(5), TRUE, TRUE); unlight_area(10, 3); wieldeds_notice_flag(p_ptr, OF_RES_DARK); *ident = TRUE; return TRUE; } case EF_PROTEVIL: { if (player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SATISFY: { if (player_set_food(p_ptr, PY_FOOD_MAX - 1)) *ident = TRUE; return TRUE; } case EF_CURSE_WEAPON: { if (curse_weapon()) *ident = TRUE; return TRUE; } case EF_CURSE_ARMOR: { if (curse_armor()) *ident = TRUE; return TRUE; } case EF_BLESSING: { if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(12) + 6, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING2: { if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(24) + 12, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING3: { if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(48) + 24, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RECALL: { set_recall(); *ident = TRUE; return TRUE; } case EF_DEEP_DESCENT: { int i, target_depth = p_ptr->depth; /* Calculate target depth */ for (i = 5; i > 0; i--) { if (is_quest(target_depth)) break; if (target_depth >= MAX_DEPTH - 1) break; target_depth++; } if (target_depth > p_ptr->depth) { msgt(MSG_TPLEVEL, "The air around you starts to swirl..."); p_ptr->deep_descent = 3 + randint1(4); *ident = TRUE; return TRUE; } else { msgt(MSG_TPLEVEL, "You sense a malevolent presence blocking passage to the levels below."); *ident = TRUE; return FALSE; } } case EF_LOSHASTE: { if (speed_monsters()) *ident = TRUE; return TRUE; } case EF_LOSSLEEP: { if (sleep_monsters(aware)) *ident = TRUE; return TRUE; } case EF_LOSSLOW: { if (slow_monsters()) *ident = TRUE; return TRUE; } case EF_LOSCONF: { if (confuse_monsters(aware)) *ident = TRUE; return TRUE; } case EF_LOSKILL: { (void)mass_banishment(); *ident = TRUE; return TRUE; } case EF_EARTHQUAKES: { earthquake(py, px, 10); *ident = TRUE; return TRUE; } case EF_DESTRUCTION2: { destroy_area(py, px, 15, TRUE); *ident = TRUE; return TRUE; } case EF_ILLUMINATION: { if (light_area(damroll(2, 15), 3)) *ident = TRUE; return TRUE; } case EF_CLAIRVOYANCE: { *ident = TRUE; wiz_light(); (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); return TRUE; } case EF_PROBING: { *ident = probing(); return TRUE; } case EF_STONE_TO_MUD: { if (wall_to_mud(dir)) *ident = TRUE; return TRUE; } case EF_CONFUSE2: { *ident = TRUE; confuse_monster(dir, 20, aware); return TRUE; } case EF_BIZARRE: { *ident = TRUE; ring_of_power(dir); return TRUE; } case EF_STAR_BALL: { int i; *ident = TRUE; for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i], (150 * (100 + boost) / 100), 3); return TRUE; } case EF_RAGE_BLESS_RESIST: { dur = randint1(50) + 50; *ident = TRUE; (void)hp_player(30); (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); (void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(50) + 50, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(50) + 50, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(50) + 50, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(50) + 50, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(50) + 50, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(50) + 50, TRUE, TRUE); return TRUE; } case EF_SLEEPII: { *ident = TRUE; sleep_monsters_touch(aware); return TRUE; } case EF_RESTORE_LIFE: { *ident = TRUE; restore_level(); return TRUE; } case EF_MISSILE: { *ident = TRUE; dam = damroll(3, 4) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_MISSILE, dir, dam); return TRUE; } case EF_DISPEL_EVIL: { *ident = TRUE; dam = p_ptr->lev * 5 * (100 + boost) / 100; dispel_evil(dam); return TRUE; } case EF_DISPEL_EVIL60: { dam = 60 * (100 + boost) / 100; if (dispel_evil(dam)) *ident = TRUE; return TRUE; } case EF_DISPEL_UNDEAD: { dam = 60 * (100 + boost) / 100; if (dispel_undead(dam)) *ident = TRUE; return TRUE; } case EF_DISPEL_ALL: { dam = 120 * (100 + boost) / 100; if (dispel_monsters(dam)) *ident = TRUE; return TRUE; } case EF_HASTE: { if (!p_ptr->timed[TMD_FAST]) { if (player_set_timed(p_ptr, TMD_FAST, damroll(2, 10) + 20, TRUE)) *ident = TRUE; } else { (void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE1: { if (!p_ptr->timed[TMD_FAST]) { if (player_set_timed(p_ptr, TMD_FAST, randint1(20) + 20, TRUE)) *ident = TRUE; } else { (void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE2: { if (!p_ptr->timed[TMD_FAST]) { if (player_set_timed(p_ptr, TMD_FAST, randint1(75) + 75, TRUE)) *ident = TRUE; } else { (void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_FIRE_BOLT: { *ident = TRUE; dam = damroll(9, 8) * (100 + boost) / 100; fire_bolt(GF_FIRE, dir, dam); return TRUE; } case EF_FIRE_BOLT2: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_FIRE, dir, dam); *ident = TRUE; return TRUE; } case EF_FIRE_BOLT3: { dam = damroll(16, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_FIRE, dir, dam); *ident = TRUE; return TRUE; } case EF_FIRE_BOLT72: { dam = 72 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 2); return TRUE; } case EF_FIRE_BALL: { dam = 144 * (100 + boost) / 100; fire_ball(GF_FIRE, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_FIRE_BALL2: { dam = 120 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 3); return TRUE; } case EF_FIRE_BALL200: { dam = 200 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 3); return TRUE; } case EF_COLD_BOLT: { dam = damroll(6, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt_or_beam(beam, GF_COLD, dir, dam); return TRUE; } case EF_COLD_BOLT2: { dam = damroll(12, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_COLD, dir, dam); return TRUE; } case EF_COLD_BALL2: { dam = 200 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 3); return TRUE; } case EF_COLD_BALL50: { dam = 50 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); return TRUE; } case EF_COLD_BALL100: { dam = 100 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); return TRUE; } case EF_COLD_BALL160: { dam = 160 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 3); return TRUE; } case EF_ACID_BOLT: { dam = damroll(5, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_ACID, dir, dam); return TRUE; } case EF_ACID_BOLT2: { dam = damroll(10, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_ACID, dir, dam); *ident = TRUE; return TRUE; } case EF_ACID_BOLT3: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_ACID, dir, dam); *ident = TRUE; return TRUE; } case EF_ACID_BALL: { dam = 120 * (100 + boost) / 100; fire_ball(GF_ACID, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_ELEC_BOLT: { dam = damroll(6, 6) * (100 + boost) / 100; *ident = TRUE; fire_beam(GF_ELEC, dir, dam); return TRUE; } case EF_ELEC_BALL: { dam = 64 * (100 + boost) / 100; fire_ball(GF_ELEC, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_ELEC_BALL2: { dam = 250 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ELEC, dir, dam, 3); return TRUE; } case EF_ARROW: { dam = 150 * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_ARROW, dir, dam); return TRUE; } case EF_REM_FEAR_POIS: { *ident = TRUE; (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); return TRUE; } case EF_STINKING_CLOUD: { dam = 12 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_POIS, dir, dam, 3); return TRUE; } case EF_DRAIN_LIFE1: { dam = 90 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE2: { dam = 120 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE3: { dam = 150 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE4: { dam = 250 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_FIREBRAND: { *ident = TRUE; if (!brand_bolts()) return FALSE; return TRUE; } case EF_MANA_BOLT: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt(GF_MANA, dir, dam); *ident = TRUE; return TRUE; } case EF_MON_HEAL: { if (heal_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_HASTE: { if (speed_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_SLOW: { if (slow_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_CONFUSE: { if (confuse_monster(dir, 10, aware)) *ident = TRUE; return TRUE; } case EF_MON_SLEEP: { if (sleep_monster(dir, aware)) *ident = TRUE; return TRUE; } case EF_MON_CLONE: { if (clone_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_SCARE: { if (fear_monster(dir, 10, aware)) *ident = TRUE; return TRUE; } case EF_LIGHT_LINE: { msg("A line of shimmering blue light appears."); light_line(dir); *ident = TRUE; return TRUE; } case EF_TELE_OTHER: { if (teleport_monster(dir)) *ident = TRUE; return TRUE; } case EF_DISARMING: { if (disarm_trap(dir)) *ident = TRUE; return TRUE; } case EF_TDOOR_DEST: { if (destroy_door(dir)) *ident = TRUE; return TRUE; } case EF_POLYMORPH: { if (poly_monster(dir)) *ident = TRUE; return TRUE; } case EF_STARLIGHT: { int i; if (!p_ptr->timed[TMD_BLIND]) msg("Light shoots in all directions!"); for (i = 0; i < 8; i++) light_line(ddd[i]); *ident = TRUE; return TRUE; } case EF_STARLIGHT2: { int k; for (k = 0; k < 8; k++) strong_light_line(ddd[k]); *ident = TRUE; return TRUE; } case EF_BERSERKER: { dur = randint1(50) + 50; if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SUN_HERO: { (void)light_area(damroll(20, 10), 8); dur = randint1(25) + 25; if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_WONDER: { if (effect_wonder(dir, randint1(100) + p_ptr->lev / 5, beam)) *ident = TRUE; return TRUE; } case EF_WAND_BREATH: { /* table of random ball effects and their damages */ const int breath_types[] = { GF_ACID, 200, GF_ELEC, 160, GF_FIRE, 200, GF_COLD, 160, GF_POIS, 120 }; /* pick a random (type, damage) tuple in the table */ int which = 2 * randint0(sizeof(breath_types) / (2 * sizeof(int))); fire_ball(breath_types[which], dir, breath_types[which + 1], 3); *ident = TRUE; return TRUE; } case EF_STAFF_MAGI: { if (do_res_stat(A_INT)) *ident = TRUE; if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; *ident = TRUE; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); } return TRUE; } case EF_STAFF_HOLY: { dam = 120 * (100 + boost) / 100; if (dispel_evil(dam)) *ident = TRUE; if (player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE; if (hp_player(50)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_DRINK_BREATH: { const int breath_types[] = { GF_FIRE, 80, GF_COLD, 80, }; int which = 2 * randint0(N_ELEMENTS(breath_types) / 2); fire_ball(breath_types[which], dir, breath_types[which + 1], 2); *ident = TRUE; return TRUE; } case EF_DRINK_GOOD: { msg("You feel less thirsty."); *ident = TRUE; return TRUE; } case EF_DRINK_DEATH: { msg("A feeling of Death flows through your body."); take_hit(p_ptr, 5000, "a potion of Death"); *ident = TRUE; return TRUE; } case EF_DRINK_RUIN: { msg("Your nerves and muscles feel weak and lifeless!"); take_hit(p_ptr, damroll(10, 10), "a potion of Ruination"); player_stat_dec(p_ptr, A_DEX, TRUE); player_stat_dec(p_ptr, A_WIS, TRUE); player_stat_dec(p_ptr, A_CON, TRUE); player_stat_dec(p_ptr, A_STR, TRUE); player_stat_dec(p_ptr, A_CHR, TRUE); player_stat_dec(p_ptr, A_INT, TRUE); *ident = TRUE; return TRUE; } case EF_DRINK_DETONATE: { msg("Massive explosions rupture your body!"); take_hit(p_ptr, damroll(50, 20), "a potion of Detonation"); (void)player_inc_timed(p_ptr, TMD_STUN, 75, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_CUT, 5000, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_DRINK_SALT: { msg("The potion makes you vomit!"); player_set_food(p_ptr, PY_FOOD_STARVE - 1); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_inc_timed(p_ptr, TMD_PARALYZED, 4, TRUE, FALSE); *ident = TRUE; return TRUE; } case EF_FOOD_GOOD: { msg("That tastes good."); *ident = TRUE; return TRUE; } case EF_FOOD_WAYBREAD: { msg("That tastes good."); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)hp_player(damroll(4, 8)); *ident = TRUE; return TRUE; } case EF_SHROOM_EMERGENCY: { (void)player_set_timed(p_ptr, TMD_IMAGE, rand_spread(250, 50), TRUE); (void)player_set_timed(p_ptr, TMD_OPP_FIRE, rand_spread(30, 10), TRUE); (void)player_set_timed(p_ptr, TMD_OPP_COLD, rand_spread(30, 10), TRUE); (void)hp_player(200); *ident = TRUE; return TRUE; } case EF_SHROOM_TERROR: { if (player_set_timed(p_ptr, TMD_TERROR, rand_spread(100, 20), TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_STONE: { if (player_set_timed(p_ptr, TMD_STONESKIN, rand_spread(80, 20), TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_DEBILITY: { int stat = one_in_(2) ? A_STR : A_CON; if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); *ident = TRUE; } (void)do_dec_stat(stat, FALSE); *ident = TRUE; return TRUE; } case EF_SHROOM_SPRINTING: { if (player_inc_timed(p_ptr, TMD_SPRINT, 100, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_PURGING: { player_set_food(p_ptr, PY_FOOD_FAINT - 1); if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE; return TRUE; } case EF_RING_ACID: { dam = 70 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ACID, dir, dam, 2); player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_FLAMES: { dam = 80 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 2); player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_ICE: { dam = 75 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_LIGHTNING: { dam = 85 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ELEC, dir, dam, 2); player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_DRAGON_BLUE: { dam = 100 * (100 + boost) / 100; msgt(MSG_BR_ELEC, "You breathe lightning."); fire_ball(GF_ELEC, dir, dam, 2); return TRUE; } case EF_DRAGON_GREEN: { dam = 150 * (100 + boost) / 100; msgt(MSG_BR_GAS, "You breathe poison gas."); fire_ball(GF_POIS, dir, dam, 2); return TRUE; } case EF_DRAGON_RED: { dam = 200 * (100 + boost) / 100; msgt(MSG_BR_FIRE, "You breathe fire."); fire_ball(GF_FIRE, dir, dam, 2); return TRUE; } case EF_DRAGON_MULTIHUED: { static const struct { int msg_sound; const char *msg; int typ; } mh[] = { { MSG_BR_ELEC, "lightning", GF_ELEC }, { MSG_BR_FROST, "frost", GF_COLD }, { MSG_BR_ACID, "acid", GF_ACID }, { MSG_BR_GAS, "poison gas", GF_POIS }, { MSG_BR_FIRE, "fire", GF_FIRE } }; int chance = randint0(5); dam = 250 * (100 + boost) / 100; msgt(mh[chance].msg_sound, "You breathe %s.", mh[chance].msg); fire_ball(mh[chance].typ, dir, dam, 2); return TRUE; } case EF_DRAGON_BRONZE: { dam = 120 * (100 + boost) / 100; msgt(MSG_BR_CONF, "You breathe confusion."); fire_ball(GF_CONFU, dir, dam, 2); return TRUE; } case EF_DRAGON_GOLD: { dam = 130 * (100 + boost) / 100; msgt(MSG_BR_SOUND, "You breathe sound."); fire_ball(GF_SOUND, dir, dam, 2); return TRUE; } case EF_DRAGON_CHAOS: { dam = 220 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 1 ? MSG_BR_CHAOS : MSG_BR_DISEN), "You breathe %s.", ((chance == 1 ? "chaos" : "disenchantment"))); fire_ball((chance == 1 ? GF_CHAOS : GF_DISEN), dir, dam, 2); return TRUE; } case EF_DRAGON_LAW: { dam = 230 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 1 ? MSG_BR_SOUND : MSG_BR_SHARDS), "You breathe %s.", ((chance == 1 ? "sound" : "shards"))); fire_ball((chance == 1 ? GF_SOUND : GF_SHARD), dir, dam, 2); return TRUE; } case EF_DRAGON_BALANCE: { dam = 250 * (100 + boost) / 100; chance = randint0(4); msg("You breathe %s.", ((chance == 1) ? "chaos" : ((chance == 2) ? "disenchantment" : ((chance == 3) ? "sound" : "shards")))); fire_ball(((chance == 1) ? GF_CHAOS : ((chance == 2) ? GF_DISEN : ((chance == 3) ? GF_SOUND : GF_SHARD))), dir, dam, 2); return TRUE; } case EF_DRAGON_SHINING: { dam = 200 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 0 ? MSG_BR_LIGHT : MSG_BR_DARK), "You breathe %s.", ((chance == 0 ? "light" : "darkness"))); fire_ball((chance == 0 ? GF_LIGHT : GF_DARK), dir, dam, 2); return TRUE; } case EF_DRAGON_POWER: { dam = 300 * (100 + boost) / 100; msgt(MSG_BR_ELEMENTS, "You breathe the elements."); fire_ball(GF_MISSILE, dir, dam, 2); return TRUE; } case EF_TRAP_DOOR: { msg("You fall through a trap door!"); if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) { msg("You float gently down to the next level."); } else { take_hit(p_ptr, damroll(2, 8), "a trap"); } wieldeds_notice_flag(p_ptr, OF_FEATHER); dungeon_change_level(p_ptr->depth + 1); return TRUE; } case EF_TRAP_PIT: { msg("You fall into a pit!"); if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the bottom of the pit."); } else { take_hit(p_ptr, damroll(2, 6), "a trap"); } wieldeds_notice_flag(p_ptr, OF_FEATHER); return TRUE; } case EF_TRAP_PIT_SPIKES: { msg("You fall into a spiked pit!"); if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the floor of the pit."); msg("You carefully avoid touching the spikes."); } else { int dam = damroll(2, 6); /* Extra spike damage */ if (one_in_(2)) { msg("You are impaled!"); dam *= 2; (void)player_inc_timed(p_ptr, TMD_CUT, randint1(dam), TRUE, TRUE); } take_hit(p_ptr, dam, "a trap"); } wieldeds_notice_flag(p_ptr, OF_FEATHER); return TRUE; } case EF_TRAP_PIT_POISON: { msg("You fall into a spiked pit!"); if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the floor of the pit."); msg("You carefully avoid touching the spikes."); } else { int dam = damroll(2, 6); /* Extra spike damage */ if (one_in_(2)) { msg("You are impaled on poisonous spikes!"); (void)player_inc_timed(p_ptr, TMD_CUT, randint1(dam * 2), TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_POISONED, randint1(dam * 4), TRUE, TRUE); } take_hit(p_ptr, dam, "a trap"); } wieldeds_notice_flag(p_ptr, OF_FEATHER); return TRUE; } case EF_TRAP_RUNE_SUMMON: { int i; int num = 2 + randint1(3); msgt(MSG_SUM_MONSTER, "You are enveloped in a cloud of smoke!"); /* Remove trap */ cave->info[py][px] &= ~(CAVE_MARK); cave_set_feat(cave, py, px, FEAT_FLOOR); for (i = 0; i < num; i++) (void)summon_specific(py, px, p_ptr->depth, 0, 1); return TRUE; } case EF_TRAP_RUNE_TELEPORT: { msg("You hit a teleport trap!"); teleport_player(100); return TRUE; } case EF_TRAP_SPOT_FIRE: { int dam; msg("You are enveloped in flames!"); dam = damroll(4, 6); dam = adjust_dam(p_ptr, GF_FIRE, dam, RANDOMISE, check_for_resist(p_ptr, GF_FIRE, p_ptr->state.flags, TRUE)); if (dam) { take_hit(p_ptr, dam, "a fire trap"); inven_damage(p_ptr, GF_FIRE, MIN(dam * 5, 300)); } return TRUE; } case EF_TRAP_SPOT_ACID: { int dam; msg("You are splashed with acid!"); dam = damroll(4, 6); dam = adjust_dam(p_ptr, GF_ACID, dam, RANDOMISE, check_for_resist(p_ptr, GF_ACID, p_ptr->state.flags, TRUE)); if (dam) { take_hit(p_ptr, dam, "an acid trap"); inven_damage(p_ptr, GF_ACID, MIN(dam * 5, 300)); } return TRUE; } case EF_TRAP_DART_SLOW: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(p_ptr, damroll(1, 4), "a trap"); (void)player_inc_timed(p_ptr, TMD_SLOW, randint0(20) + 20, TRUE, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_STR: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(p_ptr, damroll(1, 4), "a trap"); (void)do_dec_stat(A_STR, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_DEX: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(p_ptr, damroll(1, 4), "a trap"); (void)do_dec_stat(A_DEX, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_CON: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(p_ptr, damroll(1, 4), "a trap"); (void)do_dec_stat(A_CON, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_GAS_BLIND: { msg("You are surrounded by a black gas!"); (void)player_inc_timed(p_ptr, TMD_BLIND, randint0(50) + 25, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_CONFUSE: { msg("You are surrounded by a gas of scintillating colors!"); (void)player_inc_timed(p_ptr, TMD_CONFUSED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_POISON: { msg("You are surrounded by a pungent green gas!"); (void)player_inc_timed(p_ptr, TMD_POISONED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_SLEEP: { msg("You are surrounded by a strange white mist!"); (void)player_inc_timed(p_ptr, TMD_PARALYZED, randint0(10) + 5, TRUE, TRUE); return TRUE; } case EF_XXX: case EF_MAX: break; } /* Not used */ msg("Effect not handled."); return FALSE; }
/* * The "wonder" effect. * * Returns TRUE if the effect is evident. */ bool effect_wonder(int dir, int die, int beam) { /* 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. */ bool visible = FALSE; int py = p_ptr->py; int px = p_ptr->px; int plev = p_ptr->lev; if (die > 100) { /* above 100 the effect is always visible */ msg("You feel a surge of power!"); visible = TRUE; } if (die < 8) visible = clone_monster(dir); else if (die < 14) visible = speed_monster(dir); else if (die < 26) visible = heal_monster(dir); else if (die < 31) visible = poly_monster(dir); else if (die < 36) visible = fire_bolt_or_beam(beam - 10, GF_MISSILE, dir, damroll(3 + ((plev - 1) / 5), 4)); else if (die < 41) visible = confuse_monster(dir, plev, FALSE); else if (die < 46) visible = fire_ball(GF_POIS, dir, 20 + (plev / 2), 3); else if (die < 51) visible = light_line(dir); else if (die < 56) visible = fire_beam(GF_ELEC, dir, damroll(3+((plev-5)/6), 6)); else if (die < 61) visible = fire_bolt_or_beam(beam-10, GF_COLD, dir, damroll(5+((plev-5)/4), 8)); else if (die < 66) visible = fire_bolt_or_beam(beam, GF_ACID, dir, damroll(6+((plev-5)/4), 8)); else if (die < 71) visible = fire_bolt_or_beam(beam, GF_FIRE, dir, damroll(8+((plev-5)/4), 8)); else if (die < 76) visible = drain_life(dir, 75); else if (die < 81) visible = fire_ball(GF_ELEC, dir, 30 + plev / 2, 2); else if (die < 86) visible = fire_ball(GF_ACID, dir, 40 + plev, 2); else if (die < 91) visible = fire_ball(GF_ICE, dir, 70 + plev, 3); else if (die < 96) visible = fire_ball(GF_FIRE, dir, 80 + plev, 3); /* above 100 'visible' is already true */ else if (die < 101) drain_life(dir, 100 + plev); else if (die < 104) earthquake(py, px, 12); else if (die < 106) destroy_area(py, px, 15, TRUE); else if (die < 108) banishment(); else if (die < 110) dispel_monsters(120); else /* RARE */ { dispel_monsters(150); slow_monsters(); sleep_monsters(TRUE); hp_player(300); } return visible; }
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_OBJECT_DETECTION: { (void)detect_treasure(TRUE, TRUE); break; } case SPELL_CURE_LIGHT_WOUNDS: { heal_player(15, 15); player_dec_timed(p_ptr, TMD_CUT, 20, TRUE); player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE); player_clear_timed(p_ptr, 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)player_clear_timed(p_ptr, 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: { player_set_food(p_ptr, 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(); } 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: { return set_recall(); } 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_TREASURE_DETECTION: { (void)detect_treasure(TRUE, FALSE); 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)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE); break; } case SPELL_RESIST_COLD: { (void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE); break; } case SPELL_ELEMENTAL_BRAND: /* elemental brand */ { return brand_ammo(); } case SPELL_RESIST_POISON: { (void)player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE); break; } case SPELL_RESISTANCE: { int time = randint1(20) + 20; (void)player_inc_timed(p_ptr, TMD_OPP_ACID, time, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_ELEC, time, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_FIRE, time, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_COLD, time, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_POIS, time, TRUE, TRUE); break; } case SPELL_HEROISM: { int dur = randint1(25) + 25; (void)hp_player(10); (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); (void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_HERO, dur, TRUE, TRUE); break; } case SPELL_SHIELD: { (void)player_inc_timed(p_ptr, TMD_SHIELD, randint1(20) + 30, TRUE, TRUE); break; } case SPELL_BERSERKER: { int dur = randint1(25) + 25; (void)hp_player(30); (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); (void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE); break; } case SPELL_HASTE_SELF: { if (!p_ptr->timed[TMD_FAST]) { (void)player_set_timed(p_ptr, TMD_FAST, randint1(20) + plev, TRUE); } else { (void)player_inc_timed(p_ptr, TMD_FAST, randint1(5), TRUE, 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 */ { warding_glyph_spell(); 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_priest_spell(int spell, int dir) { int py = p_ptr->py; int px = p_ptr->px; int plev = p_ptr->lev; int amt; switch (spell) { case PRAYER_DETECT_EVIL: { (void)detect_monsters_evil(TRUE); break; } case PRAYER_CURE_LIGHT_WOUNDS: { (void)heal_player(15, 15); (void)player_dec_timed(p_ptr, TMD_CUT, 20, TRUE); (void)player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); break; } case PRAYER_BLESS: { (void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(12) + 12, TRUE, TRUE); break; } case PRAYER_REMOVE_FEAR: { (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); break; } case PRAYER_CALL_LIGHT: { (void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1); break; } case PRAYER_FIND_TRAPS_DOORS: { (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); break; } case PRAYER_SLOW_POISON: { (void)player_set_timed(p_ptr, TMD_POISONED, p_ptr->timed[TMD_POISONED] / 2, TRUE); break; } case PRAYER_SCARE_MONSTER: { (void)fear_monster(dir, plev, TRUE); break; } case PRAYER_PORTAL: { teleport_player(plev * 3); break; } case PRAYER_CURE_SERIOUS_WOUNDS: { (void)heal_player(20, 25); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); break; } case PRAYER_CHANT: { (void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(24) + 24, TRUE, TRUE); break; } case PRAYER_SANCTUARY: { (void)sleep_monsters_touch(TRUE); break; } case PRAYER_SATISFY_HUNGER: { player_set_food(p_ptr, PY_FOOD_MAX - 1); break; } /* Remove curse has been removed in 3.4 until curses are redone case PRAYER_REMOVE_CURSE: { remove_curse(); break; } */ case PRAYER_RESIST_HEAT_COLD: { (void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE); (void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE); break; } case PRAYER_NEUTRALIZE_POISON: { (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); break; } case PRAYER_ORB_OF_DRAINING: { fire_ball(GF_HOLY_ORB, dir, (damroll(3, 6) + plev + (player_has(PF_ZERO_FAIL) ? (plev / 2) : (plev / 4))), ((plev < 30) ? 2 : 3)); break; } case PRAYER_CURE_CRITICAL_WOUNDS: { (void)heal_player(25, 30); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); break; } case PRAYER_SENSE_INVISIBLE: { (void)player_inc_timed(p_ptr, TMD_SINVIS, randint1(24) + 24, TRUE, TRUE); break; } case PRAYER_PROTECTION_FROM_EVIL: { (void)player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE); break; } case PRAYER_EARTHQUAKE: { earthquake(py, px, 10); break; } case PRAYER_SENSE_SURROUNDINGS: { map_area(); break; } case PRAYER_CURE_MORTAL_WOUNDS: { (void)heal_player(30, 50); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); break; } case PRAYER_TURN_UNDEAD: { (void)turn_undead(TRUE); break; } case PRAYER_PRAYER: { (void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(48) + 48, TRUE, TRUE); break; } case PRAYER_DISPEL_UNDEAD: { (void)dispel_undead(randint1(plev * 3)); break; } case PRAYER_HEAL: { amt = (p_ptr->mhp * 35) / 100; if (amt < 300) amt = 300; (void)hp_player(amt); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); break; } case PRAYER_DISPEL_EVIL: { (void)dispel_evil(randint1(plev * 3)); break; } case PRAYER_GLYPH_OF_WARDING: { warding_glyph_spell(); break; } case PRAYER_HOLY_WORD: { (void)dispel_evil(randint1(plev * 4)); (void)hp_player(1000); (void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); break; } case PRAYER_DETECT_MONSTERS: { (void)detect_monsters_normal(TRUE); break; } case PRAYER_DETECTION: { (void)detect_all(TRUE); break; } case PRAYER_PERCEPTION: { return ident_spell(); } case PRAYER_PROBING: { (void)probing(); break; } case PRAYER_CLAIRVOYANCE: { wiz_light(FALSE); break; } case PRAYER_CURE_SERIOUS_WOUNDS2: { (void)heal_player(20, 25); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); break; } case PRAYER_CURE_MORTAL_WOUNDS2: { (void)heal_player(30, 50); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); (void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE); (void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE); (void)player_clear_timed(p_ptr, TMD_BLIND, TRUE); (void)player_clear_timed(p_ptr, TMD_POISONED, TRUE); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); break; } case PRAYER_HEALING: { (void)hp_player(2000); (void)player_clear_timed(p_ptr, TMD_STUN, TRUE); (void)player_clear_timed(p_ptr, TMD_CUT, TRUE); break; } case PRAYER_RESTORATION: { (void)do_res_stat(A_STR); (void)do_res_stat(A_INT); (void)do_res_stat(A_WIS); (void)do_res_stat(A_DEX); (void)do_res_stat(A_CON); break; } case PRAYER_REMEMBRANCE: { (void)restore_level(); break; } case PRAYER_DISPEL_UNDEAD2: { (void)dispel_undead(randint1(plev * 4)); break; } case PRAYER_DISPEL_EVIL2: { (void)dispel_evil(randint1(plev * 4)); break; } case PRAYER_BANISH_EVIL: { if (banish_evil(100)) { msg("The power of your god banishes evil!"); } break; } case PRAYER_WORD_OF_DESTRUCTION: { destroy_area(py, px, 15, TRUE); break; } case PRAYER_ANNIHILATION: { drain_life(dir, 200); break; } case PRAYER_UNBARRING_WAYS: { (void)destroy_doors_touch(); break; } case PRAYER_RECHARGING: { return recharge(20 + plev); } /* Dispel Curse has been removed in 3.4 until curses are redone case PRAYER_DISPEL_CURSE: { (void)remove_all_curse(); break; } */ case PRAYER_ENCHANT_WEAPON: { return enchant_spell(randint0(4) + 1, randint0(4) + 1, 0); } case PRAYER_ENCHANT_ARMOUR: { return enchant_spell(0, 0, randint0(3) + 2); } case PRAYER_ELEMENTAL_BRAND: { brand_weapon(); break; } case PRAYER_BLINK: { teleport_player(10); break; } case PRAYER_TELEPORT_SELF: { teleport_player(plev * 8); break; } case PRAYER_TELEPORT_OTHER: { (void)teleport_monster(dir); break; } case PRAYER_TELEPORT_LEVEL: { (void)teleport_player_level(); break; } case PRAYER_WORD_OF_RECALL: { return set_recall(); } case PRAYER_ALTER_REALITY: { msg("The world changes!"); /* Leaving */ p_ptr->leaving = TRUE; break; } } /* Success */ return (TRUE); }
/** * Handle player hitting a real trap. Rewritten in Oangband to allow a * greater variety of traps, with effects controlled by dungeon level. * To allow a trap to choose one of a variety of effects consistantly, * the quick RNG is often used, and xy coordinates input as a seed value. */ extern void hit_trap(int y, int x) { int i, j, k, num; int dam = 0; int nastyness, selection; feature_type *f_ptr = &f_info[cave_feat[y][x]]; cptr name = f_ptr->name; /* Use the "simple" RNG to insure that traps are consistant. */ Rand_quick = TRUE; /* Use the coordinates of the trap to seed the RNG. */ Rand_value = y * x; /* Disturb the player */ disturb(0, 0); /* Analyze XXX XXX XXX */ switch (cave_feat[y][x]) { /* trap door. */ case FEAT_TRAP_HEAD + 0x00: { Rand_quick = FALSE; /* Paranoia -NRM- */ if (((stage_map[p_ptr->stage][STAGE_TYPE] == CAVE) || (stage_map[p_ptr->stage][STAGE_TYPE] == VALLEY)) && (!stage_map[p_ptr->stage][DOWN])) { cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); msg_print("The trap fails!"); break; } msg_print("You fall through a trap door!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently down to the next level."); } else { dam = damroll(2, 8); take_hit(dam, name); } /* Remember where we came from */ p_ptr->last_stage = p_ptr->stage; if (!stage_map[p_ptr->stage][DOWN]) { /* Set the ways forward and back */ stage_map[255][UP] = p_ptr->stage; stage_map[p_ptr->stage][DOWN] = 255; stage_map[255][DEPTH] = p_ptr->depth + 1; } /* New stage */ p_ptr->stage = stage_map[p_ptr->stage][DOWN]; /* New depth */ p_ptr->depth = stage_map[p_ptr->stage][DEPTH]; /* Leaving */ p_ptr->leaving = TRUE; Rand_quick = TRUE; break; } /* pits. */ case FEAT_TRAP_HEAD + 0x01: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(20) == 1) nastyness += 20; else if (randint1(5) == 1) nastyness += 10; /* Player is now in pit. */ monster_swap(p_ptr->py, p_ptr->px, y, x); /* Center on player. */ y = p_ptr->py; x = p_ptr->px; /* pit of daggers. */ if ((nastyness > 80) && (randint1(3) != 3)) { msg_print("You fall into a pit of daggers!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid setting off the daggers."); } else { /* a trap of morgul. */ if (randint1(6) == 1) { Rand_quick = FALSE; msg_print ("A single coldly gleaming dagger pierces you deeply!"); msg_print ("You feel a deadly chill slowly withering your soul."); /* activate the Black Breath. */ p_ptr->black_breath = TRUE; /* lots of damage. */ dam = damroll(20, 15); /* undead may be attracted. */ if (randint1(2) == 1) { msg_print ("Undead suddenly appear and call you to them!"); k = randint1(3) + 2; for (i = 0; i < k; i++) { summon_specific(y, x, FALSE, p_ptr->depth, SUMMON_UNDEAD); } } /* morgul-traps are one-time only. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); Rand_quick = TRUE; } else { Rand_quick = FALSE; /* activate the ordinary daggers. */ msg_print("Daggers pierce you everywhere!"); k = randint1(10) + 5; for (i = 0; i < k; i++) { dam += damroll(3, 4); } Rand_quick = TRUE; } /* cut the player. */ (void) inc_timed(TMD_CUT, randint1(dam), TRUE); /* Take the damage. */ take_hit(dam, name); } } /* poisoned spiked pit. */ else if ((nastyness > 55) && (randint1(3) != 3)) { msg_print("You fall into a spiked pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid touching the spikes."); } else { Rand_quick = FALSE; /* Base damage */ dam = damroll(2, 6); /* Extra spike damage */ if (randint0(100) < 85) { bool was_poisoned; msg_print("You are impaled on poisonous spikes!"); dam = dam * (randint1(6) + 3); (void) inc_timed(TMD_CUT, randint1(dam), TRUE); was_poisoned = pois_hit(dam); if (!was_poisoned) msg_print("The poison does not affect you!"); } /* Take the damage */ take_hit(dam, name); Rand_quick = TRUE; } } /* spiked pit. */ else if ((nastyness > 30) && (randint1(3) != 3)) { msg_print("You fall into a spiked pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the floor of the pit."); msg_print("You carefully avoid touching the spikes."); } else { Rand_quick = FALSE; /* Base damage */ dam = damroll(2, 6); /* Extra spike damage */ if (randint0(100) < 85) { msg_print("You are impaled!"); dam = dam * (2 + randint1(4)); (void) inc_timed(TMD_CUT, randint1(dam), TRUE); } /* Take the damage */ take_hit(dam, name); Rand_quick = TRUE; } } /* ordinary pit in all other cases. */ else { msg_print("You fall into a pit!"); if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); msg_print("You float gently to the bottom of the pit."); } else { Rand_quick = FALSE; dam = damroll(2, 6); take_hit(dam, name); Rand_quick = TRUE; } } break; } /* stat-reducing dart traps. */ case FEAT_TRAP_HEAD + 0x02: { /* decide if the dart hits. */ if (check_trap_hit(50 + p_ptr->depth)) { /* select a stat to drain. */ selection = randint0(6); Rand_quick = FALSE; msg_print("A small dart hits you!"); dam = damroll(1, 4); take_hit(dam, name); /* Determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); /* decide how much to drain the stat by. */ if ((nastyness > 50) && (randint1(3) == 1)) { num = randint1(4); } else num = 1; /* drain the stat. */ for (i = 0; i < num; i++) { (void) do_dec_stat(selection); } Rand_quick = TRUE; } else { msg_print("A small dart barely misses you."); } break; } /* discolored spots. */ case FEAT_TRAP_HEAD + 0x03: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(5) == 1) nastyness += 10; /* pick a elemental attack type. */ selection = randint1(4); /* electicity trap. */ if (selection == 1) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are struck by lightning!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You get zapped!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; elec_dam(dam, "an electricity trap"); Rand_quick = TRUE; } /* frost trap. */ if (selection == 2) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are lost within a blizzard!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are coated in frost!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; cold_dam(dam, "a frost trap"); Rand_quick = TRUE; } /* fire trap. */ if (selection == 3) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("You are enveloped in a column of fire!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are surrounded by flames!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; fire_dam(dam, "a fire trap"); Rand_quick = TRUE; } /* acid trap. */ if (selection == 4) { if ((nastyness >= 50) && (randint1(2) == 1)) { Rand_quick = FALSE; msg_print("A cauldron of acid is tipped over your head!"); dam = damroll(6, 30); Rand_quick = TRUE; } else { Rand_quick = FALSE; msg_print("You are splashed with acid!"); dam = damroll(4, 8); Rand_quick = TRUE; } Rand_quick = FALSE; acid_dam(dam, "an acid trap"); Rand_quick = TRUE; } break; } /* gas traps. */ case FEAT_TRAP_HEAD + 0x04: { selection = randint1(4); /* blinding trap. */ if (selection == 1) { msg_print("You are surrounded by a black gas!"); if (!p_ptr->state.no_blind) { Rand_quick = FALSE; (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE); Rand_quick = TRUE; } } else notice_obj(OF_SEEING, 0); /* confusing trap. */ if (selection == 2) { msg_print ("You are surrounded by a gas of scintillating colors!"); if (!p_resist_good(P_RES_CONFU)) { Rand_quick = FALSE; (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); Rand_quick = TRUE; } else notice_other(IF_RES_CONFU, 0); } /* poisoning trap. */ if (selection == 3) { msg_print("You are surrounded by a pungent green gas!"); Rand_quick = FALSE; pois_hit(25); Rand_quick = TRUE; } /* sleeping trap. */ if (selection == 4) { msg_print("You are surrounded by a strange white mist!"); if (!p_ptr->state.free_act) { (void) inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE); } else notice_obj(OF_FREE_ACT, 0); } break; } /* summoning traps. */ case FEAT_TRAP_HEAD + 0x05: { sound(MSG_SUM_MONSTER); /* sometimes summon thieves. */ if ((p_ptr->depth > 8) && (randint1(5) == 1)) { msg_print("You have aroused a den of thieves!"); Rand_quick = FALSE; num = 2 + randint1(3); for (i = 0; i < num; i++) { (void) summon_specific(y, x, FALSE, p_ptr->depth, SUMMON_THIEF); } Rand_quick = TRUE; } /* sometimes summon a nasty unique. */ else if (randint1(8) == 1) { msg_print("You are enveloped in a cloud of smoke!"); Rand_quick = FALSE; (void) summon_specific(y, x, FALSE, p_ptr->depth + 5, SUMMON_UNIQUE); Rand_quick = TRUE; } /* otherwise, the ordinary summon monsters. */ else { msg_print("You are enveloped in a cloud of smoke!"); Rand_quick = FALSE; num = 2 + randint1(3); for (i = 0; i < num; i++) { (void) summon_specific(y, x, FALSE, p_ptr->depth, 0); } Rand_quick = TRUE; } /* these are all one-time traps. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); break; } /* dungeon alteration traps. */ case FEAT_TRAP_HEAD + 0x06: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint1(p_ptr->depth); if (randint1(5) == 1) nastyness += 10; /* make room for alterations. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); /* Everything truely random from here on. */ Rand_quick = FALSE; /* dungeon destruction trap. */ if ((nastyness > 60) && (randint1(12) == 1)) { msg_print ("A ear-splitting howl shatters your mind as the dungeon is smashed by hammer blows!"); (void) destroy_level(FALSE); /* the player is hard-hit. */ (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE); (void) inc_timed(TMD_STUN, randint1(50) + 50, TRUE); dam = damroll(15, 15); take_hit(dam, name); } /* earthquake trap. */ else if ((nastyness > 20) && (randint1(4) == 1)) { msg_print("A tremor shakes the earth around you"); earthquake(y, x, 10, FALSE); } /* falling rock trap. */ else if ((nastyness > 4) && (randint1(2) == 1)) { msg_print("A rock falls on your head."); dam = damroll(2, 10); take_hit(dam, name); (void) inc_timed(TMD_STUN, randint1(10) + 10, TRUE); } /* a few pebbles. */ else { msg_print("A bunch of pebbles rain down on you."); dam = damroll(1, 8); take_hit(dam, name); } Rand_quick = TRUE; break; } /* various char and equipment-alteration traps, lumped together to * avoid any one effect being too common (some of them can be rather * nasty). */ case FEAT_TRAP_HEAD + 0x07: { /* determine how dangerous the trap is allowed to be. */ nastyness = randint0(100); /* these are all one-time traps. */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); /* Everything truely random from here on. */ Rand_quick = FALSE; /* trap of drain wands. */ if (nastyness < 15) { /* Hold the object information. */ object_type *o_ptr; /* Find an item */ for (i = 0; i < 20; i++) { /* Pick an item */ i = randint0(INVEN_PACK - p_ptr->pack_size_reduce); /* Obtain the item */ o_ptr = &p_ptr->inventory[i]; /* use "num" to decide if a item can be uncharged. By * default, assume it can't. */ num = 0; /* Skip non-objects */ if (!o_ptr->k_idx) continue; /* Drain charged wands/staffs/rods */ if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_ROD)) { /* case of charged wands/staffs. */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) && (o_ptr->pval)) num = 1; /* case of charged rods. */ if ((o_ptr->tval == TV_ROD) && (o_ptr->timeout < randcalc(o_ptr->time, 0, MINIMISE))) num = 1; if (num == 1) { /* Message */ msg_print("Energy drains from your pack!"); /* Uncharge */ if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)) o_ptr->pval = 0; if (o_ptr->tval == TV_ROD) o_ptr->timeout = randcalc(o_ptr->time, 0, RANDOMISE) * o_ptr->number * 2; /* Combine / Reorder the pack */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* not more than one inventory slot effected. */ break; } else continue; } } } /* trap of forgetting. */ else if (nastyness < 35) { if (check_save(100)) { msg_print("You hang on to your memories!"); } else if (lose_all_info()) { msg_print("Your memories fade away."); } } /* trap of alter reality. */ else if (nastyness < 50) { if (OPT(adult_ironman)) msg_print("Nothing happens."); else { msg_print("The world changes!"); /* Leaving */ p_ptr->leaving = TRUE; } } /* trap of remold player. */ else if (nastyness < 75) { int max1, cur1, max2, cur2, ii, jj; msg_print("You feel yourself being twisted by wild magic!"); if (check_save(100)) { msg_print("You resist the effects!"); } else { msg_print("Your body starts to scramble..."); /* Pick a pair of stats */ ii = randint0(6); for (jj = ii; jj == ii; jj = randint0(6)) /* loop */ ; max1 = p_ptr->stat_max[ii]; cur1 = p_ptr->stat_cur[ii]; max2 = p_ptr->stat_max[jj]; cur2 = p_ptr->stat_cur[jj]; p_ptr->stat_max[ii] = max2; p_ptr->stat_cur[ii] = cur2; p_ptr->stat_max[jj] = max1; p_ptr->stat_cur[jj] = cur1; p_ptr->update |= (PU_BONUS); } } /* time ball trap. */ else if (nastyness < 90) { msg_print("You feel time itself assault you!"); /* Target the player with a radius 0 ball attack. */ fire_meteor(0, GF_TIME, p_ptr->py, p_ptr->px, 75, 0, TRUE); } /* trap of bugs gone berserk. */ else { /* explain what the dickens is going on. */ msg_print("GRUESOME Gnawing Bugs leap out at you!"); if (!p_resist_good(P_RES_CONFU)) { (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE); } else notice_other(IF_RES_CONFU, 0); if (!p_resist_good(P_RES_CHAOS)) { (void) inc_timed(TMD_IMAGE, randint1(40), TRUE); } else notice_other(IF_RES_CHAOS, 0); /* XXX (hard coded) summon 3-6 bugs. */ k = randint1(4) + 2; for (i = 0; i < k; ++i) { /* Look for a location */ for (j = 0; j < 20; ++j) { /* Pick a (scattered) distance. */ int d = (j / 10) + randint1(3); /* Pick a location */ scatter(&y, &x, y, x, d, 0); /* Require passable terrain */ if (!cave_passable_bold(y, x)) continue; /* Hack -- no summon on glyph of warding */ if (cave_feat[y][x] == FEAT_RUNE_PROTECT) continue; /* Okay */ break; } /* Attempt to place the awake bug */ place_monster_aux(y, x, 453, FALSE, TRUE); } /* herald the arrival of bugs. */ msg_print("AAAAAAAHHHH! THEY'RE EVERYWHERE!"); } Rand_quick = TRUE; break; } /* teleport trap */ case FEAT_TRAP_HEAD + 0x08: { if (stage_map[p_ptr->stage][STAGE_TYPE] >= CAVE) msg_print("You teleport across the dungeon."); else msg_print("You teleport across the wilderness."); Rand_quick = FALSE; teleport_player(250, FALSE); Rand_quick = TRUE; break; } /* murder holes. */ case FEAT_TRAP_HEAD + 0x09: { /* hold the object info. */ object_type *o_ptr; object_type object_type_body; /* hold the missile type and name. */ int sval = 0; int tval = 0; cptr missile_name = ""; /* Determine the missile type and base damage. */ if (randint1(3) == 1) { if (p_ptr->depth < 40) { missile_name = "shot"; dam = damroll(2, 3); tval = TV_SHOT; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker shot"; dam = damroll(3, 7); tval = TV_SHOT; sval = SV_AMMO_HEAVY; } } else if (randint1(2) == 1) { if (p_ptr->depth < 55) { missile_name = "arrow"; dam = damroll(2, 4); tval = TV_ARROW; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker arrow"; dam = damroll(3, 9); tval = TV_ARROW; sval = SV_AMMO_HEAVY; } } else { if (p_ptr->depth < 65) { missile_name = "bolt"; dam = damroll(2, 5); tval = TV_BOLT; sval = SV_AMMO_NORMAL; } else { missile_name = "seeker bolt"; dam = damroll(3, 11); tval = TV_BOLT; sval = SV_AMMO_HEAVY; } } /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { msg_format("A %s hits you from above.", missile_name); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was well-aimed!"); dam *= 1 + randint1(2); } if (randint1(2) == 1) { msg_print("It gouges you!"); dam = 3 * dam / 2; /* cut the player. */ (void) inc_timed(TMD_CUT, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_format("A %s wizzes by your head.", missile_name); /* these will eventually run out of ammo. */ Rand_quick = FALSE; if (randint0(8) == 0) { cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_FLOOR); } Rand_quick = TRUE; /* Get local object */ o_ptr = &object_type_body; /* Make a missile, identify it, and drop it near the player. */ object_prep(o_ptr, lookup_kind(tval, sval), MINIMISE); object_aware(o_ptr); object_known(o_ptr); drop_near(o_ptr, -1, y, x, TRUE); break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0A: { /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { /* Take damage */ dam = damroll(3, 5); msg_print("A branch hits you from above."); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was heavy!"); dam = 3 * dam / 2; /* stun the player. */ (void) inc_timed(TMD_STUN, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_print("A falling branch just misses you."); /* No more */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_TREE); break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0B: { /* determine if the missile hits. */ if (check_trap_hit(75 + p_ptr->depth)) { /* Take damage */ dam = damroll(3, 5); msg_print("A branch hits you from above."); Rand_quick = FALSE; /* critical hits. */ if (randint1(2) == 1) { msg_print("It was heavy!"); dam = 3 * dam / 2; /* stun the player. */ (void) inc_timed(TMD_STUN, randint1(dam), TRUE); } Rand_quick = TRUE; take_hit(dam, name); } /* Explain what just happened. */ else msg_print("A falling branch just misses you."); /* No more */ cave_info[y][x] &= ~(CAVE_MARK); cave_set_feat(y, x, FEAT_TREE2); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0C: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0D: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0E: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } /* undefined trap. */ case FEAT_TRAP_HEAD + 0x0F: { msg_print("A dagger is thrown at you from the shadows!"); dam = damroll(3, 4); take_hit(dam, name); break; } } /* Revert to usage of the complex RNG. */ Rand_quick = FALSE; }
/* * do_cmd_mind calls this function if the player's class * is 'Naturalist'. */ static bool cast_nature_spell(int spell) { /* this will vary based on the spells, and what they depend on */ int plev = p_ptr->lev; int dir; int px = p_ptr->px; int py = p_ptr->py; /* spell code */ switch (spell) { case 0: /* Detect Creatures */ (void)detect_monsters_normal(); break; case 1: /* First Aid */ (void)hp_player(damroll(2, 8)); (void)set_cut(p_ptr->cut - 15); break; case 2: /* Detect Doors + Traps */ (void)detect_traps(); (void)detect_doors(); (void)detect_stairs(); break; case 3: /* Produce Food */ (void)set_food(PY_FOOD_MAX - 1); break; case 4: /* Daylight */ (void)lite_area(damroll(2, (plev / 2)), (plev / 10) + 1); break; case 5: /* Animal Taming */ if (!get_aim_dir(&dir)) return FALSE; (void)charm_animal(dir, plev); break; case 6: /* Resist Environment */ (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20); (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20); (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20); break; case 7: /* Cure Wounds + Poison */ (void)hp_player(damroll(plev, 8)); (void)set_cut(0); (void)set_poisoned(0); break; case 8: /* Stone to Mud */ if (!get_aim_dir(&dir)) return FALSE; (void)wall_to_mud(dir); break; case 9: /* Lightning Bolt */ if (!get_aim_dir(&dir)) return FALSE; fire_bolt_or_beam(100, GF_ELEC, dir, damroll(3 + ((plev - 5) / 4), 8)); break; case 10: /* Ray of Sunlight */ if (!get_aim_dir(&dir)) return FALSE; msg_print("A line of sunlight appears."); (void)lite_line(dir); break; case 11: /* Entangle */ slow_monsters(); break; case 12: /* Stone Skin */ (void)set_shield(p_ptr->shield + randint(20) + 30); break; case 13: /* Resistance True */ (void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20); (void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20); (void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20); (void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20); (void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20); break; case 14: /* Stone Tell */ return identify_fully(); case 15: /* Earthquake */ earthquake(py, px, 10); break; case 16: /* Blizzard */ if (!get_aim_dir(&dir)) return FALSE; fire_ball(GF_COLD, dir, 70 + plev, (plev / 12) + 1); break; case 17: /* Lightning Storm */ if (!get_aim_dir(&dir)) return FALSE; fire_ball(GF_ELEC, dir, 90 + plev, (plev / 12) + 1); break; case 18: /* Whirlpool */ if (!get_aim_dir(&dir)) return FALSE; fire_ball(GF_WATER, dir, 100 + plev, (plev / 12) + 1); break; case 19: /* Call Sunlight */ fire_ball(GF_LITE, 0, 150, 8); wiz_lite(); break; case 20: /* Nature's Wrath */ (void)dispel_monsters(plev * 4); earthquake(py, px, 20 + (plev / 2)); project(0, 1 + plev / 12, py, px, 100 + plev, GF_DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM); break; default: msg_format("You cast an unknown Nature spell: %d.", spell); msg_print(NULL); } return TRUE; }
/* * Attack the monster at the given location * * If no "weapon" is available, then "punch" the monster one time. * * We get blows until energy drops below that required for another blow, or * until the target monster dies. We use a wrapper to work out the number of * blows. We don't allow @ to spend more than 100 energy in one go, to avoid * slower monsters getting double moves. */ bool py_attack_real(int y, int x) { int bonus, chance; monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; object_type *o_ptr; char m_name[80]; bool fear = FALSE; bool do_quake = FALSE; bool dead = FALSE; u32b msg_type = 0; bool success = FALSE; const char *hit_verb = "ERROR"; int dmg = 1; /* Default to punching for one damage */ /* Maybe handle monster melee here -Simon */ if(!rp_ptr->p_monster_index) { hit_verb = "punch"; msg_type = MSG_HIT; } /* * Hack -- if advanced innate attacks are disabled for this race, fall back * on defaults <player>'s 1d1. */ /* TODO: this -Simon */ /* if (p_ptr->flags[NO_INNATE]) { p_ptr = &r_info[0]; } */ /* Extract monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Auto-Recall if possible and visible */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Track a new monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); /* Handle player fear (only for invisible monsters) */ if (p_ptr->state.afraid) { message_format(MSG_AFRAID, 0, "You are too afraid to attack %s!", m_name); return (FALSE); } /* Disturb the monster */ wake_monster(m_ptr); /* Get the weapon */ o_ptr = &p_ptr->inventory[INVEN_WIELD]; /* Calculate the "attack quality" */ bonus = p_ptr->state.to_h + o_ptr->to_h; chance = (p_ptr->state.skills[SKILL_TO_HIT_MELEE] + (bonus * BTH_PLUS_ADJ)); /* Handle innate melee -Simon */ if(!o_ptr->k_idx && rp_ptr->p_monster_index) { for (int num = 0; (num < MONSTER_BLOW_MAX) && !dead; num++) { const slay_t *best_s_ptr = NULL; int type = GF_ARROW, type2 = 0, i; int flg = PROJECT_KILL | PROJECT_STOP | PROJECT_HIDE; // | PROJECT_PASS; TODO: figure out what this is and implement it -Simon char *p = ""; if (!r_info[rp_ptr->p_monster_index].blow[num].method && !dead) continue; /* Test for hit */ if (test_hit(chance, r_info[m_ptr->r_idx].ac, m_ptr->ml)) { int mul = 1; int k = 0; /* Get the method */ switch (r_info[rp_ptr->p_monster_index].blow[num].method) { case RBM_HIT: p = "hit"; break; case RBM_TOUCH: p = "touch"; break; case RBM_PUNCH: p = "punch"; break; case RBM_KICK: p = "kick"; break; case RBM_CLAW: p = "claw"; break; case RBM_BITE: p = "bite"; break; case RBM_STING: p = "sting"; break; case RBM_BUTT: p = "butt"; break; case RBM_CRUSH: p = "crush"; break; case RBM_ENGULF:p = "engulf"; break; case RBM_PECK: p = "peck"; break; case RBM_CRAWL: p = "crawl on"; break; case RBM_DROOL: p = "drool on"; break; case RBM_SPIT: p = "spit on"; break; case RBM_SLIME: p = "slime"; break; case RBM_GAZE: p = "gaze at"; break; case RBM_WAIL: p = "wail at"; break; case RBM_SPORE: p = "release spores at"; break; case RBM_BEG: p = "beg for money"; break; case RBM_INSULT: p = "insult"; break; default: p = "attack"; } /* Get the effect */ switch (r_info[rp_ptr->p_monster_index].blow[num].effect) { case RBE_HURT: type = GF_ARROW; break; case RBE_DISEASE: type = GF_POIS; mul = 2; break; case RBE_POISON: type = GF_POIS; mul = 2; break; case RBE_LOSE_MANA: type = GF_DISENCHANT; break; case RBE_UN_BONUS: type = GF_DISENCHANT; mul = 2; break; case RBE_UN_POWER: type = GF_DISENCHANT; mul = 2; break; /* ? */ case RBE_EAT_LIGHT: type = GF_DARK; mul = 2; break; case RBE_ACID: type = GF_ACID; mul = 2; break; case RBE_ELEC: type = GF_ELEC; mul = 2; break; case RBE_FIRE: type = GF_FIRE; mul = 2; break; case RBE_COLD: type = GF_COLD; mul = 2; break; case RBE_BLIND: type2 = GF_OLD_CONF; break; /* ? */ case RBE_CONFUSE: type2 = GF_OLD_CONF; break; case RBE_TERRIFY: type2 = GF_TURN_ALL; break; /* ? */ case RBE_PARALYZE: type2 = GF_OLD_SLEEP; break; /* ? */ /* Earthquake would be natural, but all monsters * with RBE_SHATTER are already humanoids */ case RBE_SHATTER: type = GF_ARROW; break; case RBE_EXP_10: type = GF_NETHER; mul = 2; break; case RBE_EXP_20: type = GF_NETHER; mul = 2; break; case RBE_EXP_40: type = GF_NETHER; mul = 2; break; case RBE_EXP_80: type = GF_NETHER; mul = 2; break; /* GF_CHAOS will polymorph, so it is bad */ case RBE_HALLU: type = GF_DISENCHANT; mul = 2; break; default: type = GF_ARROW; } k = damroll(r_info[rp_ptr->p_monster_index].blow[num].d_dice, r_info[rp_ptr->p_monster_index].blow[num].d_side); /* Get the best attack from all slays or * brands on all non-launcher equipment */ for (i = INVEN_FINGER; i < INVEN_TOTAL; i++) improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr); if (best_s_ptr != NULL) { if (best_s_ptr->mult > mul) { p = best_s_ptr->melee_verb; mul = best_s_ptr->mult; if (best_s_ptr->resist_flag == RF_IM_ACID) type = GF_ACID; else if (best_s_ptr->resist_flag == RF_IM_ELEC) type = GF_ELEC; else if (best_s_ptr->resist_flag == RF_IM_FIRE) type = GF_FIRE; else if (best_s_ptr->resist_flag == RF_IM_COLD) type = GF_COLD; else if (best_s_ptr->resist_flag == RF_IM_POIS) type = GF_POIS; } } k *= mul; message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", p, m_name); /* Add to-dam bonus only if did some damage */ if (k) k += p_ptr->state.to_d; if (k < 0) k = 0; /* Learn by use for other equipped items */ wieldeds_notice_on_attack(); /* If there is an extra effect, project it also, using 4*level as power */ if (type2) { project(-1, 0, y, x, 4 * p_ptr->lev, type2, flg); } /* Confusion attack */ if (p_ptr->confusing) { /* Message */ if (p_ptr->confusing) msg_print("Your limbs stop glowing."); /* Cancel glowing hands */ p_ptr->confusing = FALSE; /* Confuse the monster */ if (rf_has(r_ptr->flags, RF_NO_CONF)) { if (m_ptr->ml) { rf_on(l_ptr->flags, RF_NO_CONF); } msg_format("%^s is unaffected.", m_name); } else if (randint0(100) < r_ptr->level) { msg_format("%^s appears slightly perplexed.", m_name); } else { msg_format("%^s appears confused.", m_name); m_ptr->confused += 10 + randint0(p_ptr->lev) / 5; } } /* Damage, check for fear and death */ /* Makes elemental attacks do half their damage physically -Simon */ if (type != GF_ARROW) { project(-1, 0, y, x, (k + 1)/2, type, flg); /* Make the physical portion TOP SECRET -Simon */ flg &= ~(PROJECT_AWARE); project(-1, 0, y, x, k/2, GF_ARROW, flg); } else project(-1, 0, y, x, k, type, flg); /* Hack: check if the square is empty after we project the attack into it -Simon */ dead = (cave_m_idx[y][x] == 0); /* Hack -- delay fear messages */ if (fear && m_ptr->ml && !dead) message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } /* Player misses */ else { /* Message */ message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name); } } return (TRUE); } else { /* See if the player hit */ success = test_hit(chance, r_ptr->ac, m_ptr->ml); /* If a miss, skip this hit */ if (!success) { message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name); return (FALSE); } /* Handle normal weapon */ if (o_ptr->k_idx) { int i; const slay_t *best_s_ptr = NULL; hit_verb = "hit"; /* Get the best attack from all slays or * brands on all non-launcher equipment */ for (i = INVEN_FINGER; i < INVEN_TOTAL; i++) improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr); improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) hit_verb = best_s_ptr->melee_verb; dmg = damroll(o_ptr->dd, o_ptr->ds); dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult; if (p_ptr->state.impact && (dmg > 50)) do_quake = TRUE; dmg += o_ptr->to_d; dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type); /* Learn by use for the weapon */ object_notice_attack_plusses(o_ptr); if (do_quake) wieldeds_notice_flag(OF_IMPACT); } /* Learn by use for other equipped items */ wieldeds_notice_on_attack(); /* Apply the player damage bonuses */ dmg += p_ptr->state.to_d; /* No negative damage */ if (dmg <= 0) dmg = 0; /* Tell the player what happened */ if (dmg <= 0) message_format(MSG_MISS, m_ptr->r_idx, "You fail to harm %s.", m_name); else if (msg_type == MSG_HIT) message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) message_format(MSG_HIT_GOOD, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a good hit!"); else if (msg_type == MSG_HIT_GREAT) message_format(MSG_HIT_GREAT, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a great hit!"); else if (msg_type == MSG_HIT_SUPERB) message_format(MSG_HIT_SUPERB, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a superb hit!"); else if (msg_type == MSG_HIT_HI_GREAT) message_format(MSG_HIT_HI_GREAT, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a *GREAT* hit!"); else if (msg_type == MSG_HIT_HI_SUPERB) message_format(MSG_HIT_HI_SUPERB, m_ptr->r_idx, "You %s %s. %s", hit_verb, m_name, "It was a *SUPERB* hit!"); /* Complex message */ if (p_ptr->wizard) msg_format("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Confusion attack */ if (p_ptr->confusing) { /* Cancel glowing hands */ p_ptr->confusing = FALSE; /* Message */ msg_print("Your limbs stop glowing."); /* Update the lore */ if (m_ptr->ml) rf_on(l_ptr->flags, RF_NO_CONF); /* Confuse the monster */ if (rf_has(r_ptr->flags, RF_NO_CONF)) msg_format("%^s is unaffected.", m_name); else if (randint0(100) < r_ptr->level) msg_format("%^s is unaffected.", m_name); else { msg_format("%^s appears confused.", m_name); m_ptr->confused += 10 + randint0(p_ptr->lev) / 5; } } /* Damage, check for fear and death */ dead = mon_take_hit(cave_m_idx[y][x], dmg, &fear, NULL); /* Hack -- delay fear messages */ if (fear && m_ptr->ml) message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); /* Mega-Hack -- apply earthquake brand */ if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10); return (dead); } }
/* Use a staff. -RAK- */ void use() { int32u i; int j, k, item_val, chance, y, x; register int ident; register struct misc *m_ptr; register inven_type *i_ptr; free_turn_flag = TRUE; if (inven_ctr == 0) msg_print("But you are not carrying anything."); else if (!find_range(TV_STAFF, TV_NEVER, &j, &k)) msg_print("You are not carrying any staffs."); else if (get_item(&item_val, "Use which staff?", j, k, CNIL, CNIL)) { i_ptr = &inventory[item_val]; free_turn_flag = FALSE; m_ptr = &py.misc; chance = m_ptr->save + stat_adj(A_INT) - (int)i_ptr->level - 5 + (class_level_adj[m_ptr->pclass][CLA_DEVICE] * m_ptr->lev / 3); if (py.flags.confused > 0) chance = chance / 2; if ((chance < USE_DEVICE) && (randint(USE_DEVICE - chance + 1) == 1)) chance = USE_DEVICE; /* Give everyone a slight chance */ if (chance <= 0) chance = 1; if (randint(chance) < USE_DEVICE) msg_print("You failed to use the staff properly."); else if (i_ptr->p1 > 0) { i = i_ptr->flags; ident = FALSE; (i_ptr->p1)--; while (i != 0) { j = bit_pos(&i) + 1; /* Staffs. */ switch(j) { case 1: ident = light_area(char_row, char_col); break; case 2: ident = detect_sdoor(); break; case 3: ident = detect_trap(); break; case 4: ident = detect_treasure(); break; case 5: ident = detect_object(); break; case 6: teleport(100); ident = TRUE; break; case 7: ident = TRUE; earthquake(); break; case 8: ident = FALSE; for (k = 0; k < randint(4); k++) { y = char_row; x = char_col; ident |= summon_monster(&y, &x, FALSE); } break; case 10: ident = TRUE; destroy_area(char_row, char_col); break; case 11: ident = TRUE; starlite(char_row, char_col); break; case 12: ident = speed_monsters(1); break; case 13: ident = speed_monsters(-1); break; case 14: ident = sleep_monsters2(); break; case 15: ident = hp_player(randint(8)); break; case 16: ident = detect_invisible(); break; case 17: if (py.flags.fast == 0) ident = TRUE; py.flags.fast += randint(30) + 15; break; case 18: if (py.flags.slow == 0) ident = TRUE; py.flags.slow += randint(30) + 15; break; case 19: ident = mass_poly(); break; case 20: if (remove_curse()) { if (py.flags.blind < 1) msg_print("The staff glows blue for a moment.."); ident = TRUE; } break; case 21: ident = detect_evil(); break; case 22: if ((cure_blindness()) || (cure_poison()) || (cure_confusion())) ident = TRUE; break; case 23: ident = dispel_creature(CD_EVIL, 60); break; case 25: ident = unlight_area(char_row, char_col); break; case 32: /* store bought flag */ break; default: msg_print("Internal error in staffs()"); break; } /* End of staff actions. */ } if (ident) { if (!known1_p(i_ptr)) { m_ptr = &py.misc; /* round half-way case up */ m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev; prt_experience(); identify(&item_val); i_ptr = &inventory[item_val]; } }
int main(int argc, char *argv[]) { char *unit_vals[] = { "si" , "mercalli" , "omori" , "g" , NULL }; char *info_vals[] = { "mercalli" , "omori" , NULL }; int i; int n, units, info; double dt, mag; gboolean verbose; double average_quake; double acceleration; double (*convert_func)(double); double (*convert_inv_func)(double); Eh_args *args; args = eh_opts_init( argc , argv ); if ( eh_check_opts( args , NULL , NULL , help_msg )!=0 ) eh_exit(-1); n = eh_get_opt_int ( args , "n" , DEFAULT_N ); dt = eh_get_opt_dbl ( args , "dt" , DEFAULT_DT ); mag = eh_get_opt_dbl ( args , "mag" , DEFAULT_MAG ); verbose = eh_get_opt_bool( args , "v" , FALSE ); units = eh_get_opt_key ( args , "units" , 0 , unit_vals ); info = eh_get_opt_key ( args , "info" , -1 , info_vals ); switch ( info ) { case INFO_MERCALLI: eh_print_message( stderr , mercalli_msg ); eh_exit(0); case INFO_OMORI: eh_print_message( stderr , omori_msg ); eh_exit(0); } if ( verbose ) { fprintf(stderr,"Magnitude : %f\n",mag); fprintf(stderr,"Dt : %f\n",dt); fprintf(stderr,"n : %d\n",n); } switch ( units ) { case SI_UNITS: convert_func = &convert_accel_to_si; convert_inv_func = &convert_si_to_accel; break; case MERCALLI_UNITS: convert_func = &convert_accel_to_mercalli; convert_inv_func = &convert_mercalli_to_accel; break; case OMORI_UNITS: convert_func = &convert_accel_to_omori; convert_inv_func = &convert_omori_to_accel; break; case G_UNITS: convert_func = &convert_accel_to_g; convert_inv_func = &convert_g_to_accel; break; } if ( strcmp(g_basename(argv[0]),"quakeconvert_to")==0 ) { while ( fscanf(stdin,"%lf",&acceleration)==1 ) fprintf(stdout,"%f\n",convert_func(acceleration)); return 0; } else if ( strcmp(g_basename(argv[0]),"quakeconvert_from")==0 ) { while ( fscanf(stdin,"%lf",&acceleration)==1 ) fprintf(stdout,"%f\n",convert_inv_func(acceleration)); return 0; } average_quake = convert_inv_func(mag); for ( i=0 ; i<n ; i++ ) { acceleration = earthquake(exp(-1./average_quake),dt); fprintf(stdout,"%f\n",convert_func(acceleration)); } return 0; }