/* * Go down one level */ void do_cmd_go_down(void) { int py = p_ptr->py; int px = p_ptr->px; char answer; /* Verify stairs */ if (cave_feat[py][px] != FEAT_MORE) { msg_print("I see no down staircase here."); return; } /* Make certain the player really wants to leave a themed level. -LM- */ if (p_ptr->themed_level) { msg_print("This level will never appear again. Really leave? (y/n)"); answer = inkey(); if ((answer != 'Y') && (answer != 'y')) return; } /* Hack -- take a turn */ p_ptr->energy_use = 100; /* Success */ msgt(MSG_STAIRS_DOWN, "You enter a maze of down staircases."); /* Create a way back */ p_ptr->create_up_stair = TRUE; /* New level */ p_ptr->depth++; /* Use the "simple" RNG to insure that stairs are consistant. */ Rand_quick = TRUE; /* Use the coordinates of the staircase to seed the RNG. */ Rand_value = py * px; /* If the new level is not a quest level, or the bottom of the dungeon, * there is a 50% chance of descending another level. -LM- */ if ((is_quest(p_ptr->depth) == FALSE) && (p_ptr->depth < MAX_DEPTH -1) && (randint1(2) == 1)) { msg_print("The stairs continue down. Go down another level? (y/n)"); answer = inkey(); if ((answer == 'Y') || (answer == 'y')) p_ptr->depth++; } /* Revert to use of the "complex" RNG. */ Rand_quick = FALSE; /* Leaving */ p_ptr->leaving = TRUE; }
void square_add_stairs(struct chunk *c, int y, int x, int depth) { int down = randint0(100) < 50; if (depth == 0) down = 1; else if (is_quest(depth) || depth >= z_info->max_depth - 1) down = 0; square_set_feat(c, y, x, down ? FEAT_MORE : FEAT_LESS); }
/** * Place stairs (of the requested type 'feat' if allowed) at (x, y). * \param c current chunk * \param y co-ordinates * \param x co-ordinates * \param feat stair terrain type * * All stairs from town go down. All stairs on an unfinished quest level go up. */ static void place_stairs(struct chunk *c, int y, int x, int feat) { if (!c->depth) square_set_feat(c, y, x, FEAT_MORE); else if (is_quest(c->depth) || c->depth >= z_info->max_depth - 1) square_set_feat(c, y, x, FEAT_LESS); else square_set_feat(c, y, x, feat); }
/* * Note that "feeling" is set to zero unless some time has passed. * Note that this is done when the level is GENERATED, not entered. */ void do_cmd_feeling(void) { /* Verify the feeling */ if (feeling < 0) feeling = 0; if (feeling > 10) feeling = 10; /* Hooked feelings ? */ if (process_hooks(HOOK_FEELING, "(d)", is_quest(dun_level))) { return; } /* No useful feeling in special levels */ if ((has_flag(dungeon_flags, FLAG_DESC))) { char buf[1024]; if ((has_flag(dungeon_flags, FLAG_SAVE_LEVEL)) || (generate_special_feeling) || ((has_flag(dungeon_flags, FLAG_DESC_ALWAYS)))) { if (!get_level_desc(buf)) msg_print("Someone forgot to describe this level!"); else msg_print(buf); return; } } /* No useful feeling in quests */ if (p_ptr->inside_quest) { msg_print("Looks like a typical quest level."); return; } /* Display feelings in the dungeon, nothing on the surface */ if (dun_level) { /* This could be simplified with a correct p_ptr->town_num */ s32b i, town_level = 0; dungeon_info_type *d_ptr = &d_info[dungeon_type]; /* Is it a town level ? */ for (i = 0; i < TOWN_DUNGEON; i++) { if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i]; } if (town_level) msg_print("You hear the sound of a market."); else msg_print(do_cmd_feeling_text[feeling]); } return; }
/** * Instantiate a player trap */ static int pick_trap(int feat, int trap_level) { int trap_index = 0; feature_type *f_ptr = &f_info[feat]; struct trap_kind *kind; bool trap_is_okay = FALSE; /* Paranoia */ if (!tf_has(f_ptr->flags, TF_TRAP)) return -1; /* Try to create a trap appropriate to the level. Make certain that at * least one trap type can be made on any possible level. -LM- */ while (!trap_is_okay) { /* Pick at random. */ trap_index = randint0(z_info->trap_max); /* Get this trap */ kind = &trap_info[trap_index]; /* Ensure that this is a player trap */ if (!kind->name) continue; if (!trf_has(kind->flags, TRF_TRAP)) continue; /* Require that trap_level not be too low */ if (kind->min_depth > trap_level) continue; /* Assume legal until proven otherwise. */ trap_is_okay = TRUE; /* Floor? */ if (tf_has(f_ptr->flags, TF_FLOOR) && !trf_has(kind->flags, TRF_FLOOR)) trap_is_okay = FALSE; /* Check legality of trapdoors. */ if (trf_has(kind->flags, TRF_DOWN)) { /* No trap doors on quest levels */ if (is_quest(player->depth)) trap_is_okay = FALSE; /* No trap doors on the deepest level */ if (player->depth >= z_info->max_depth - 1) trap_is_okay = FALSE; } } /* Return our chosen trap */ return (trap_index); }
/* * Hack -- instantiate a trap * * XXX XXX XXX This routine should be redone to reflect trap "level". * That is, it does not make sense to have spiked pits at 50 feet. * Actually, it is not this routine, but the "trap instantiation" * code, which should also check for "trap doors" on quest levels. */ void pick_trap(int y, int x) { int feat; static const int min_level[] = { 2, /* Trap door */ 2, /* Open pit */ 2, /* Spiked pit */ 2, /* Poison pit */ 3, /* Summoning rune */ 1, /* Teleport rune */ 2, /* Fire rune */ 2, /* Acid rune */ 2, /* Slow rune */ 6, /* Strength dart */ 6, /* Dexterity dart */ 6, /* Constitution dart */ 2, /* Gas blind */ 1, /* Gas confuse */ 2, /* Gas poison */ 2, /* Gas sleep */ }; /* Paranoia */ if (cave->feat[y][x] != FEAT_INVIS) return; /* Pick a trap */ while (1) { /* Hack -- pick a trap */ feat = FEAT_TRAP_HEAD + randint0(16); /* Check against minimum depth */ if (min_level[feat - FEAT_TRAP_HEAD] > p_ptr->depth) continue; /* Hack -- no trap doors on quest levels */ if ((feat == FEAT_TRAP_HEAD + 0x00) && is_quest(p_ptr->depth)) continue; /* Hack -- no trap doors on the deepest level */ if ((feat == FEAT_TRAP_HEAD + 0x00) && (p_ptr->depth >= MAX_DEPTH-1)) continue; /* Done */ break; } /* Activate the trap */ cave_set_feat(cave, y, x, feat); }
/** * Choose a cave profile * \param depth is the depth of the cave the profile will be used to generate */ const struct cave_profile *choose_profile(int depth) { const struct cave_profile *profile = NULL; /* A bit of a hack, but worth it for now NRM */ if (player->noscore & NOSCORE_JUMPING) { char name[30]; /* Cancel the query */ player->noscore &= ~(NOSCORE_JUMPING); /* Ask debug players for the profile they want */ if (get_string("Profile name (eg classic): ", name, sizeof(name))) profile = find_cave_profile(name); /* If no valid profile name given, fall through */ if (profile) return profile; } /* Make the profile choice */ if (depth == 0) profile = find_cave_profile("town"); else if (is_quest(depth)) /* Quest levels must be normal levels */ profile = find_cave_profile("classic"); else if (labyrinth_check(depth)) profile = find_cave_profile("labyrinth"); else { int perc = randint0(100); size_t i; for (i = 0; i < z_info->profile_max; i++) { profile = &cave_profiles[i]; if (profile->cutoff >= perc) break; } } /* Return the profile or fail horribly */ if (profile) return profile; else quit("Failed to find cave profile!"); return NULL; }
/** * Go down one level */ void do_cmd_go_down(struct command *cmd) { int descend_to = player->depth + 1; /* Verify stairs */ if (!square_isdownstairs(cave, player->py, player->px)) { msg("I see no down staircase here."); return; } /* Paranoia, no descent from z_info->max_depth - 1 */ if (player->depth == z_info->max_depth - 1) { msg("The dungeon does not appear to extend deeper"); return; } /* Warn a force_descend player if they're going to a quest level */ if (OPT(birth_force_descend)) { if (is_quest(player->max_depth + 1) && !get_check("Are you sure you want to descend?")) return; /* Don't overshoot */ descend_to = MIN(player->max_depth + 1, z_info->max_depth - 1); } /* Hack -- take a turn */ player->upkeep->energy_use = z_info->move_energy; /* Success */ msgt(MSG_STAIRS_DOWN, "You enter a maze of down staircases."); /* Create a way back */ player->upkeep->create_up_stair = TRUE; player->upkeep->create_down_stair = FALSE; /* Change level */ dungeon_change_level(descend_to); }
/** * Do d_m's prime check for labyrinths * \param depth is the depth where we're trying to generate a labyrinth */ bool labyrinth_check(int depth) { /* There's a base 2 in 100 to accept the labyrinth */ int chance = 2; /* If we're too shallow then don't do it */ if (depth < 13) return FALSE; /* Don't try this on quest levels, kids... */ if (is_quest(depth)) return FALSE; /* Certain numbers increase the chance of having a labyrinth */ if (depth % 3 == 0) chance += 1; if (depth % 5 == 0) chance += 1; if (depth % 7 == 0) chance += 1; if (depth % 11 == 0) chance += 1; if (depth % 13 == 0) chance += 1; /* Only generate the level if we pass a check */ if (randint0(100) >= chance) return FALSE; /* Successfully ran the gauntlet! */ 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: { inc_timed(TMD_POISONED, damroll(2, 7) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_BLIND: { inc_timed(TMD_BLIND, damroll(4, 25) + 75, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SCARE: { inc_timed(TMD_AFRAID, randint0(10) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_CONFUSE: { inc_timed(TMD_CONFUSED, damroll(4, 5) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_HALLUC: { inc_timed(TMD_IMAGE, randint0(250) + 250, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_PARALYZE: { inc_timed(TMD_PARALYZED, randint0(5) + 5, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SLOW: { if (inc_timed(TMD_SLOW, randint1(25) + 15, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_POISON: { if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BLINDNESS: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_PARANOIA: { if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CONFUSION: { if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_MIND: { if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (clear_timed(TMD_IMAGE, TRUE)) *ident = TRUE; if (!of_has(p_ptr->state.flags, OF_RES_CONFU) && inc_timed(TMD_OPP_CONF, damroll(4, 10), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BODY: { if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_LIGHT: { if (hp_player(20)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (dec_timed(TMD_CUT, 20, TRUE)) *ident = TRUE; if (dec_timed(TMD_CONFUSED, 20, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_SERIOUS: { if (hp_player(40)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CRITICAL: { if (hp_player(60)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(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 (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_FULL2: { if (hp_player(1200)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_TEMP: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL1: { if (hp_player(500)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL2: { if (hp_player(1000)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL3: { if (hp_player(500)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(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(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(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(damroll(5, 5), "stat drain"); (void)do_dec_stat(stat, FALSE); *ident = TRUE; return TRUE; } case EF_LOSE_CON2: { take_hit(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)clear_timed(TMD_POISONED, TRUE); (void)clear_timed(TMD_BLIND, TRUE); (void)clear_timed(TMD_CONFUSED, TRUE); (void)clear_timed(TMD_IMAGE, TRUE); (void)clear_timed(TMD_STUN, TRUE); (void)clear_timed(TMD_CUT, TRUE); (void)clear_timed(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(); 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 (inc_timed(TMD_SINFRA, 100 + damroll(4, 25), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_SINVIS: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (inc_timed(TMD_SINVIS, 12 + damroll(2, 6), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_ESP: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (inc_timed(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); identify_pack(); *ident = TRUE; return TRUE; } case EF_HERO: { dur = randint1(25) + 25; if (hp_player(10)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_HERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHERO: { dur = randint1(25) + 25; if (hp_player(30)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ACID: { if (inc_timed(TMD_OPP_ACID, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ELEC: { if (inc_timed(TMD_OPP_ELEC, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_FIRE: { if (inc_timed(TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_COLD: { if (inc_timed(TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_POIS: { if (inc_timed(TMD_OPP_POIS, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ALL: { if (inc_timed(TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_DETECT_TREASURE: { if (detect_treasure(aware)) *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(OF_RES_DARK, p_ptr->state.flags)) (void)inc_timed(TMD_BLIND, 3 + randint1(5), TRUE, TRUE); unlight_area(10, 3); wieldeds_notice_flag(OF_RES_DARK); *ident = TRUE; return TRUE; } case EF_PROTEVIL: { if (inc_timed(TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SATISFY: { if (set_food(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 (inc_timed(TMD_BLESSED, randint1(12) + 6, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING2: { if (inc_timed(TMD_BLESSED, randint1(24) + 12, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING3: { if (inc_timed(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 = 2; 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, "You sink through the floor..."); dungeon_change_level(target_depth); *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)clear_timed(TMD_AFRAID, TRUE); (void)inc_timed(TMD_BOLD, dur, TRUE, TRUE); (void)inc_timed(TMD_SHERO, dur, TRUE, TRUE); (void)inc_timed(TMD_BLESSED, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_ACID, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_ELEC, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_FIRE, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_COLD, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(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 (set_timed(TMD_FAST, damroll(2, 10) + 20, TRUE)) *ident = TRUE; } else { (void)inc_timed(TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE1: { if (!p_ptr->timed[TMD_FAST]) { if (set_timed(TMD_FAST, randint1(20) + 20, TRUE)) *ident = TRUE; } else { (void)inc_timed(TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE2: { if (!p_ptr->timed[TMD_FAST]) { if (set_timed(TMD_FAST, randint1(75) + 75, TRUE)) *ident = TRUE; } else { (void)inc_timed(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)clear_timed(TMD_AFRAID, TRUE); (void)clear_timed(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 (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(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 (inc_timed(TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (hp_player(50)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(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(5000, "a potion of Death"); *ident = TRUE; return TRUE; } case EF_DRINK_RUIN: { msg("Your nerves and muscles feel weak and lifeless!"); take_hit(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(damroll(50, 20), "a potion of Detonation"); (void)inc_timed(TMD_STUN, 75, TRUE, TRUE); (void)inc_timed(TMD_CUT, 5000, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_DRINK_SALT: { msg("The potion makes you vomit!"); (void)set_food(PY_FOOD_STARVE - 1); (void)clear_timed(TMD_POISONED, TRUE); (void)inc_timed(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)clear_timed(TMD_POISONED, TRUE); (void)hp_player(damroll(4, 8)); *ident = TRUE; return TRUE; } case EF_SHROOM_EMERGENCY: { (void)set_timed(TMD_IMAGE, rand_spread(250, 50), TRUE); (void)set_timed(TMD_OPP_FIRE, rand_spread(30, 10), TRUE); (void)set_timed(TMD_OPP_COLD, rand_spread(30, 10), TRUE); (void)hp_player(200); *ident = TRUE; return TRUE; } case EF_SHROOM_TERROR: { if (set_timed(TMD_TERROR, rand_spread(100, 20), TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_STONE: { if (set_timed(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 (inc_timed(TMD_SPRINT, 100, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_PURGING: { (void)set_food(PY_FOOD_FAINT - 1); if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (clear_timed(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); inc_timed(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); inc_timed(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); inc_timed(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); inc_timed(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(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently down to the next level."); } else { take_hit(damroll(2, 8), "a trap"); } wieldeds_notice_flag(OF_FEATHER); dungeon_change_level(p_ptr->depth + 1); return TRUE; } case EF_TRAP_PIT: { msg("You fall into a pit!"); if (check_state(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the bottom of the pit."); } else { take_hit(damroll(2, 6), "a trap"); } wieldeds_notice_flag(OF_FEATHER); return TRUE; } case EF_TRAP_PIT_SPIKES: { msg("You fall into a spiked pit!"); if (check_state(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)inc_timed(TMD_CUT, randint1(dam), TRUE, TRUE); } take_hit(dam, "a trap"); } wieldeds_notice_flag(OF_FEATHER); return TRUE; } case EF_TRAP_PIT_POISON: { msg("You fall into a spiked pit!"); if (check_state(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)inc_timed(TMD_CUT, randint1(dam * 2), TRUE, TRUE); (void)inc_timed(TMD_POISONED, randint1(dam * 4), TRUE, TRUE); } take_hit(dam, "a trap"); } wieldeds_notice_flag(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); break; } 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(GF_FIRE, dam, RANDOMISE, check_for_resist(GF_FIRE, p_ptr->state.flags, TRUE)); if (dam) { take_hit(dam, "a fire trap"); inven_damage(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(GF_ACID, dam, RANDOMISE, check_for_resist(GF_ACID, p_ptr->state.flags, TRUE)); if (dam) { take_hit(dam, "an acid trap"); inven_damage(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(damroll(1, 4), "a trap"); (void)inc_timed(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(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(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(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)inc_timed(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)inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_POISON: { msg("You are surrounded by a pungent green gas!"); (void)inc_timed(TMD_POISONED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_SLEEP: { msg("You are surrounded by a strange white mist!"); (void)inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE, TRUE); return TRUE; } case EF_XXX: case EF_MAX: break; } /* Not used */ msg("Effect not handled."); return FALSE; }
/** * Generate a random level. * * Confusingly, this function also generate the town level (level 0). * \param c is the level we're going to end up with, in practice the global cave * \param p is the current player struct, in practice the global player */ void cave_generate(struct chunk **c, struct player *p) { const char *error = "no generation"; int y, x, tries = 0; struct chunk *chunk; assert(c); /* Generate */ for (tries = 0; tries < 100 && error; tries++) { struct dun_data dun_body; error = NULL; /* Mark the dungeon as being unready (to avoid artifact loss, etc) */ character_dungeon = FALSE; /* Allocate global data (will be freed when we leave the loop) */ dun = &dun_body; dun->cent = mem_zalloc(z_info->level_room_max * sizeof(struct loc)); dun->door = mem_zalloc(z_info->level_door_max * sizeof(struct loc)); dun->wall = mem_zalloc(z_info->wall_pierce_max * sizeof(struct loc)); dun->tunn = mem_zalloc(z_info->tunn_grid_max * sizeof(struct loc)); /* Choose a profile and build the level */ dun->profile = choose_profile(p->depth); chunk = dun->profile->builder(p); if (!chunk) { error = "Failed to find builder"; mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); continue; } /* Ensure quest monsters */ if (is_quest(chunk->depth)) { int i; for (i = 1; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; int y, x; /* The monster must be an unseen quest monster of this depth. */ if (r_ptr->cur_num > 0) continue; if (!rf_has(r_ptr->flags, RF_QUESTOR)) continue; if (r_ptr->level != chunk->depth) continue; /* Pick a location and place the monster */ find_empty(chunk, &y, &x); place_new_monster(chunk, y, x, r_ptr, TRUE, TRUE, ORIGIN_DROP); } } /* Clear generation flags. */ for (y = 0; y < chunk->height; y++) { for (x = 0; x < chunk->width; x++) { sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_INNER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_OUTER); sqinfo_off(chunk->squares[y][x].info, SQUARE_WALL_SOLID); sqinfo_off(chunk->squares[y][x].info, SQUARE_MON_RESTRICT); } } /* Regenerate levels that overflow their maxima */ if (cave_monster_max(chunk) >= z_info->level_monster_max) error = "too many monsters"; if (error) ROOM_LOG("Generation restarted: %s.", error); mem_free(dun->cent); mem_free(dun->door); mem_free(dun->wall); mem_free(dun->tunn); } if (error) quit_fmt("cave_generate() failed 100 times!"); /* Free the old cave, use the new one */ if (*c) cave_free(*c); *c = chunk; /* Place dungeon squares to trigger feeling (not in town) */ if (player->depth) place_feeling(*c); /* Save the town */ else if (!chunk_find_name("Town")) { struct chunk *town = chunk_write(0, 0, z_info->town_hgt, z_info->town_wid, FALSE, FALSE, FALSE); town->name = string_make("Town"); chunk_list_add(town); } (*c)->feeling = calc_obj_feeling(*c) + calc_mon_feeling(*c); /* Validate the dungeon (we could use more checks here) */ chunk_validate_objects(*c); /* The dungeon is ready */ character_dungeon = TRUE; /* Free old and allocate new known level */ if (cave_k) cave_free(cave_k); cave_k = cave_new(cave->height, cave->width); if (!cave->depth) cave_known(); (*c)->created_at = turn; }
/** * Handle things that need updating once every 10 game turns */ void process_world(struct chunk *c) { int i, y, x; /* Compact the monster list if we're approaching the limit */ if (cave_monster_count(cave) + 32 > z_info->level_monster_max) compact_monsters(64); /* Too many holes in the monster list - compress */ if (cave_monster_count(cave) + 32 < cave_monster_max(cave)) compact_monsters(0); /*** Check the Time ***/ /* Play an ambient sound at regular intervals. */ if (!(turn % ((10L * z_info->day_length) / 4))) play_ambient_sound(); /*** Handle stores and sunshine ***/ if (!player->depth) { /* Daybreak/Nighfall in town */ if (!(turn % ((10L * z_info->day_length) / 2))) { bool dawn; /* Check for dawn */ dawn = (!(turn % (10L * z_info->day_length))); /* Day breaks */ if (dawn) msg("The sun has risen."); /* Night falls */ else msg("The sun has fallen."); /* Illuminate */ cave_illuminate(c, dawn); } } else { /* Update the stores once a day (while in the dungeon). The changes are not actually made until return to town, to avoid giving details away in the knowledge menu. */ if (!(turn % (10L * z_info->store_turns))) daycount++; } /* Check for creature generation */ if (one_in_(z_info->alloc_monster_chance)) (void)pick_and_place_distant_monster(cave, player, z_info->max_sight + 5, true, player->depth); /*** Damage over Time ***/ /* Take damage from poison */ if (player->timed[TMD_POISONED]) take_hit(player, 1, "poison"); /* Take damage from cuts */ if (player->timed[TMD_CUT]) { /* Mortal wound or Deep Gash */ if (player->timed[TMD_CUT] > TMD_CUT_SEVERE) i = 3; /* Severe cut */ else if (player->timed[TMD_CUT] > TMD_CUT_NASTY) i = 2; /* Other cuts */ else i = 1; /* Take damage */ take_hit(player, i, "a fatal wound"); } /*** Check the Food, and Regenerate ***/ /* Digest normally */ if (!(turn % 100)) { /* Basic digestion rate based on speed */ i = turn_energy(player->state.speed) * 2; /* Regeneration takes more food */ if (player_of_has(player, OF_REGEN)) i += 30; /* Slow digestion takes less food */ if (player_of_has(player, OF_SLOW_DIGEST)) i /= 5; /* Minimal digestion */ if (i < 1) i = 1; /* Digest some food */ player_set_food(player, player->food - i); } /* Getting Faint */ if (player->food < PY_FOOD_FAINT) { /* Faint occasionally */ if (!player->timed[TMD_PARALYZED] && one_in_(10)) { /* Message */ msg("You faint from the lack of food."); disturb(player, 1); /* Faint (bypass free action) */ (void)player_inc_timed(player, TMD_PARALYZED, 1 + randint0(5), true, false); } } /* Starve to death (slowly) */ if (player->food < PY_FOOD_STARVE) { /* Calculate damage */ i = (PY_FOOD_STARVE - player->food) / 10; /* Take damage */ take_hit(player, i, "starvation"); } /* Regenerate Hit Points if needed */ if (player->chp < player->mhp) player_regen_hp(player); /* Regenerate mana if needed */ if (player->csp < player->msp) player_regen_mana(player); /* Timeout various things */ decrease_timeouts(); /* Process light */ player_update_light(player); /*** Process Inventory ***/ /* Handle experience draining */ if (player_of_has(player, OF_DRAIN_EXP)) { if ((player->exp > 0) && one_in_(10)) { s32b d = damroll(10, 6) + (player->exp / 100) * z_info->life_drain_percent; player_exp_lose(player, d / 10, false); } equip_learn_flag(player, OF_DRAIN_EXP); } /* Recharge activatable objects and rods */ recharge_objects(); /* Notice things after time */ if (!(turn % 100)) equip_learn_after_time(player); /* Decrease trap timeouts */ for (y = 0; y < cave->height; y++) { for (x = 0; x < cave->width; x++) { struct trap *trap = cave->squares[y][x].trap; while (trap) { if (trap->timeout) { trap->timeout--; if (!trap->timeout) square_light_spot(cave, y, x); } trap = trap->next; } } } /*** Involuntary Movement ***/ /* Delayed Word-of-Recall */ if (player->word_recall) { /* Count down towards recall */ player->word_recall--; /* Activate the recall */ if (!player->word_recall) { /* Disturbing! */ disturb(player, 0); /* Determine the level */ if (player->depth) { msgt(MSG_TPLEVEL, "You feel yourself yanked upwards!"); dungeon_change_level(player, 0); } else { msgt(MSG_TPLEVEL, "You feel yourself yanked downwards!"); /* Force descent to a lower level if allowed */ if (OPT(player, birth_force_descend) && player->max_depth < z_info->max_depth - 1 && !is_quest(player->max_depth)) { player->max_depth = dungeon_get_next_level(player->max_depth, 1); } /* New depth - back to max depth or 1, whichever is deeper */ dungeon_change_level(player, player->max_depth < 1 ? 1: player->max_depth); } } } /* Delayed Deep Descent */ if (player->deep_descent) { /* Count down towards recall */ player->deep_descent--; /* Activate the recall */ if (player->deep_descent == 0) { int target_increment; int target_depth = player->max_depth; /* Calculate target depth */ target_increment = (4 / z_info->stair_skip) + 1; target_depth = dungeon_get_next_level(player->max_depth, target_increment); disturb(player, 0); /* Determine the level */ if (target_depth > player->depth) { msgt(MSG_TPLEVEL, "The floor opens beneath you!"); dungeon_change_level(player, target_depth); } else { /* Otherwise do something disastrous */ msgt(MSG_TPLEVEL, "You are thrown back in an explosion!"); effect_simple(EF_DESTRUCTION, "0", 0, 5, 0, NULL); } } } }
/** * Handle falling off cliffs */ void fall_off_cliff(void) { int i = 0, dam; msg_print("You fall into the darkness!"); /* Where we fell from */ p_ptr->last_stage = p_ptr->stage; /* From the mountaintop */ if (stage_map[p_ptr->stage][LOCALITY] == MOUNTAIN_TOP) { p_ptr->stage = stage_map[p_ptr->stage][DOWN]; p_ptr->depth = stage_map[p_ptr->stage][DEPTH]; /* Reset */ stage_map[256][DOWN] = 0; stage_map[p_ptr->stage][UP] = 0; stage_map[256][DEPTH] = 0; if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); dam = damroll(2, 8); (void) inc_timed(TMD_STUN, damroll(2, 8), TRUE); (void) inc_timed(TMD_CUT, damroll(2, 8), TRUE); } else { dam = damroll(4, 8); (void) inc_timed(TMD_STUN, damroll(4, 8), TRUE); (void) inc_timed(TMD_CUT, damroll(4, 8), TRUE); } take_hit(dam, "falling off a precipice"); } /* Nan Dungortheb */ else { /* Fall at least one level */ for (i = 0; i < 1; i = randint0(3)) { p_ptr->stage = stage_map[p_ptr->stage][SOUTH]; p_ptr->depth++; if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); dam = damroll(2, 8); (void) inc_timed(TMD_STUN, damroll(2, 8), TRUE); (void) inc_timed(TMD_CUT, damroll(2, 8), TRUE); } else { dam = damroll(4, 8); (void) inc_timed(TMD_STUN, damroll(4, 8), TRUE); (void) inc_timed(TMD_CUT, damroll(4, 8), TRUE); } take_hit(dam, "falling off a precipice"); if (p_ptr->depth == 70) break; } /* Check for quests */ if (OPT(adult_dungeon) && is_quest(p_ptr->stage) && (p_ptr->depth < 100)) { int i; monster_race *r_ptr = NULL; /* Find the questor */ for (i = 0; i < z_info->r_max; i++) { r_ptr = &r_info[i]; if ((rf_has(r_ptr->flags, RF_QUESTOR)) && (r_ptr->level == p_ptr->depth)) break; } /* Announce */ msg_format("This level is home to %s.", r_ptr->name); } } /* Leaving */ p_ptr->leaving = TRUE; }
/** * Places some staircases near walls */ void alloc_stairs(int feat, int num, int walls) { int y, x, i, j; feature_type *f_ptr; bool no_down_shaft = (!stage_map[stage_map[p_ptr->stage][DOWN]][DOWN] || is_quest(stage_map[p_ptr->stage][DOWN]) || is_quest(p_ptr->stage)); bool no_up_shaft = (!stage_map[stage_map[p_ptr->stage][UP]][UP]); bool morgy = is_quest(p_ptr->stage) && stage_map[p_ptr->stage][DEPTH] == 100; /* Place "num" stairs */ for (i = 0; i < num; i++) { /* Try hard to place the stair */ for (j = 0; j < 3000; j++) { /* Cut some slack if necessary. */ if ((j > dun->stair_n) && (walls > 2)) walls = 2; if ((j > 1000) && (walls > 1)) walls = 1; if (j > 2000) walls = 0; /* Use the stored stair locations first. */ if (j < dun->stair_n) { y = dun->stair[j].y; x = dun->stair[j].x; } /* Then, search at random. */ else { /* Pick a random grid */ y = randint0(DUNGEON_HGT); x = randint0(DUNGEON_WID); } /* Require "naked" floor grid */ f_ptr = &f_info[cave_feat[y][x]]; if (!(cave_naked_bold(y, x) && tf_has(f_ptr->flags, TF_FLOOR))) continue; /* Require a certain number of adjacent walls */ if (next_to_walls(y, x) < walls) continue; /* If we've asked for a shaft and they're forbidden, fail */ if (no_down_shaft && (feat == FEAT_MORE_SHAFT)) return; if (no_up_shaft && (feat == FEAT_LESS_SHAFT)) return; /* Town or no way up -- must go down */ if ((!p_ptr->depth) || (!stage_map[p_ptr->stage][UP])) { /* Clear previous contents, add down stairs */ if (feat != FEAT_MORE_SHAFT) cave_set_feat(y, x, FEAT_MORE); } /* Bottom of dungeon, Morgoth or underworld -- must go up */ else if ((!stage_map[p_ptr->stage][DOWN]) || underworld || morgy) { /* Clear previous contents, add up stairs */ if (feat != FEAT_LESS_SHAFT) cave_set_feat(y, x, FEAT_LESS); } /* Requested type */ else { /* Clear previous contents, add stairs */ cave_set_feat(y, x, feat); } /* Finished with this staircase. */ break; } } }
/** * Hack -- instantiate a trap * * This function has been altered in Oangband to (in a hard-coded fashion) * control trap level. -LM- */ extern void pick_trap(int y, int x) { int feat = 0; feature_type *f_ptr = &f_info[cave_feat[y][x]]; bool trap_is_okay = FALSE; /* Paranoia */ if ((cave_feat[y][x] != FEAT_INVIS) && (cave_feat[y][x] != FEAT_GRASS_INVIS) && (cave_feat[y][x] != FEAT_TREE_INVIS) && (cave_feat[y][x] != FEAT_TREE2_INVIS)) return; /* Try to create a trap appropriate to the level. Make certain that at * least one trap type can be made on any possible level. -LM- */ while (!(trap_is_okay)) { /* Pick at random. */ feat = FEAT_TRAP_HEAD + randint0(16); /* Assume legal until proven otherwise. */ trap_is_okay = TRUE; /* Check legality. */ switch (feat) { /* trap doors */ case FEAT_TRAP_HEAD + 0x00: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* Hack -- no trap doors on quest levels */ if (is_quest(p_ptr->stage)) trap_is_okay = FALSE; /* Hack -- no trap doors at the bottom of dungeons */ if ((stage_map[p_ptr->stage][STAGE_TYPE] == CAVE) && (!stage_map[p_ptr->stage][DOWN])) trap_is_okay = FALSE; /* No trap doors at level 1 (instadeath risk). */ if (p_ptr->depth < 2) trap_is_okay = FALSE; /* Trap doors only in dungeons or normal wilderness */ if (stage_map[p_ptr->stage][STAGE_TYPE] > CAVE) trap_is_okay = FALSE; /* Trap doors only in dungeons in ironman */ if (OPT(adult_ironman) && (stage_map[p_ptr->stage][STAGE_TYPE] < CAVE)) trap_is_okay = FALSE; break; } /* pits */ case FEAT_TRAP_HEAD + 0x01: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No pits at level 1 (instadeath risk). */ if (p_ptr->depth < 2) trap_is_okay = FALSE; break; } /* stat-reducing darts. */ case FEAT_TRAP_HEAD + 0x02: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No darts above level 8. */ if (p_ptr->depth < 8) trap_is_okay = FALSE; break; } /* discolored spots */ case FEAT_TRAP_HEAD + 0x03: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No discolored spots above level 5. */ if (p_ptr->depth < 5) trap_is_okay = FALSE; break; } /* gas trap */ case FEAT_TRAP_HEAD + 0x04: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* Gas traps can exist anywhere. */ break; } /* summoning rune */ case FEAT_TRAP_HEAD + 0x05: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No summoning runes above level 3. */ if (p_ptr->depth < 3) trap_is_okay = FALSE; break; } /* dungeon alteration */ case FEAT_TRAP_HEAD + 0x06: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No dungeon alteration above level 20. */ if (p_ptr->depth < 20) trap_is_okay = FALSE; break; } /* alter char and reality */ case FEAT_TRAP_HEAD + 0x07: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No alter char and reality above level 60. */ if (p_ptr->depth < 60) trap_is_okay = FALSE; break; } /* move player */ case FEAT_TRAP_HEAD + 0x08: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; break; } /* arrow, bolt, or shot */ case FEAT_TRAP_HEAD + 0x09: { /* No trees */ if (tf_has(f_ptr->flags, TF_TREE)) trap_is_okay = FALSE; /* No arrow, bolt, or shots above level 4. */ if (p_ptr->depth < 4) trap_is_okay = FALSE; break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0A: { /* Need the right trees */ if (cave_feat[y][x] != FEAT_TREE_INVIS) trap_is_okay = FALSE; break; } /* falling tree branch */ case FEAT_TRAP_HEAD + 0x0B: { /* Need the right trees */ if (cave_feat[y][x] != FEAT_TREE2_INVIS) trap_is_okay = FALSE; break; } /* Any other selection is not defined. */ default: { trap_is_okay = FALSE; break; } } } /* Activate the trap */ cave_set_feat(y, x, feat); }
/** * Instantiate a player trap */ static int pick_trap(struct chunk *c, int feat, int trap_level) { int i, pick; int *trap_probs = NULL; int trap_prob_max = 0; /* Paranoia */ if (!feat_is_trap_holding(feat)) return -1; /* No traps in town */ if (c->depth == 0) return -1; /* Get trap probabilities */ trap_probs = mem_zalloc(z_info->trap_max * sizeof(int)); for (i = 0; i < z_info->trap_max; i++) { /* Get this trap */ struct trap_kind *kind = &trap_info[i]; trap_probs[i] = trap_prob_max; /* Ensure that this is a valid player trap */ if (!kind->name) continue; if (!kind->rarity) continue; if (!trf_has(kind->flags, TRF_TRAP)) continue; /* Require that trap_level not be too low */ if (kind->min_depth > trap_level) continue; /* Floor? */ if (feat_is_floor(feat) && !trf_has(kind->flags, TRF_FLOOR)) continue; /* Check legality of trapdoors. */ if (trf_has(kind->flags, TRF_DOWN)) { /* No trap doors on quest levels */ if (is_quest(player->depth)) continue; /* No trap doors on the deepest level */ if (player->depth >= z_info->max_depth - 1) continue; /* No trap doors with persistent levels (for now) */ if (OPT(player, birth_levels_persist)) continue; } /* Trap is okay, store the cumulative probability */ trap_probs[i] += (100 / kind->rarity); trap_prob_max = trap_probs[i]; } /* No valid trap */ if (trap_prob_max == 0) { mem_free(trap_probs); return -1; } /* Pick at random. */ pick = randint0(trap_prob_max); for (i = 0; i < z_info->trap_max; i++) { if (pick < trap_probs[i]) { break; } } mem_free(trap_probs); /* Return our chosen trap */ return i < z_info->trap_max ? i : -1; }