/*! * @brief フロアに存在する全モンスターを消去する / * Hack -- Delete all monsters * @return なし */ static void do_cmd_wiz_zap_all(void) { int i; /* Genocide everyone */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip the mount */ if (i == p_ptr->riding) continue; if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) { char m_name[80]; monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name); } /* Delete this monster */ delete_monster_idx(i); } }
// Summon one monster void WizardModeDialog::wiz_banish(void) { int i; /* Banish everyone nearby */ for (i = 1; i < mon_max; i++) { monster_type *m_ptr = &mon_list[i]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip distant monsters */ if (m_ptr->cdis > (MAX_SIGHT+10)) continue; /* Hack -- Skip unique monsters */ if (r_ptr->flags1 & (RF1_UNIQUE)) continue; /* Quest monsters can only be "killed" by the player */ if (m_ptr->mflag & (MFLAG_QUEST)) continue; /* Delete the monster */ delete_monster_idx(i); } /* Update monster list window */ p_ptr->redraw |= PR_WIN_MONLIST | PR_SIDEBAR_MON; handle_stuff(); this->accept(); }
/* * Delete the monster, if any, at a given location */ void delete_monster(int y, int x) { /* Paranoia */ if (!in_bounds(y, x)) return; /* Delete the monster (if any) */ if (cave.m_idx[y][x] > 0) delete_monster_idx(cave.m_idx[y][x]); }
/** * Deletes the monster, if any, at the given location. */ void delete_monster(int y, int x) { assert(cave_in_bounds(cave, y, x)); /* Delete the monster (if any) */ if (cave->m_idx[y][x] > 0) delete_monster_idx(cave->m_idx[y][x]); }
/** * Deletes the monster, if any, at the given location. */ void delete_monster(int y, int x) { assert(square_in_bounds(cave, y, x)); /* Delete the monster (if any) */ if (cave->squares[y][x].mon > 0) delete_monster_idx(cave->squares[y][x].mon); }
/** * This will collect stats on a monster avoiding all unique monsters. * Afterwards it will kill the monsters. */ static bool stats_monster(struct monster *mon, int i) { static int lvl; /* get player depth */ lvl = player->depth; /* Increment monster count */ mon_total[lvl] += addval; /* Increment unique count if appropriate */ if (rf_has(mon->race->flags, RF_UNIQUE)){ /* add to total */ uniq_total[lvl] += addval; /* kill the unique if we're in clearing mode */ if (clearing) mon->race->max_num = 0; /* debugging print that we killed it msg_format("Killed %s",race->name); */ } /* Is it mostly dangerous (10 levels ood or less?)*/ if ((mon->race->level > player->depth) && (mon->race->level <= player->depth + 10)) { mon_ood[lvl] += addval; /* Is it a unique */ if (rf_has(mon->race->flags, RF_UNIQUE)) uniq_ood[lvl] += addval; } /* Is it deadly? */ if (mon->race->level > player->depth + 10){ mon_deadly[lvl] += addval; /* Is it a unique? */ if (rf_has(mon->race->flags, RF_UNIQUE)) uniq_deadly[lvl] += addval; } /* Generate treasure */ monster_death_stats(i); /* remove the monster */ delete_monster_idx(i); /* success */ return TRUE; }
/* * Create a feature near the player. */ static void do_cmd_wiz_feature(int feat) { int px = p_ptr->px; int py = p_ptr->py; int y, x, d = 3, attempts = 30; while (1) { /* Find a location */ y = rand_spread(py, d); x = rand_spread(px, d); /* Reject illegal grids */ if (!in_bounds(y, x)) continue; /* Reject the player */ if ((y == py) && (x == px)) continue; attempts--; if (!attempts) { d++; attempts = 8 * d; } /* Try to place a new feature */ if (area(y, x)->feat == feat) continue; /* Okay */ break; } /* Nuke objects */ delete_object_idx(area(y, x)->o_idx); /* Nuke monsters */ delete_monster_idx(area(y, x)->m_idx); /* Forget this grid */ area(y, x)->info &= ~(CAVE_MARK); /* Place the feature */ cave_set_feat(y, x, feat); /* Update stuff */ p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE); }
/* * Hack -- Delete all monsters */ static void do_cmd_wiz_zap_all(void) { int i; /* Genocide everyone */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Delete this monster */ delete_monster_idx(i); } /* Update some things */ p_ptr->update |= (PU_MON_LITE); }
/* * Hack -- Delete all nearby monsters */ static void do_cmd_wiz_zap(int d) { int i; /* Genocide everyone nearby */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip distant monsters */ if (m_ptr->cdis > d) continue; /* Delete the monster */ delete_monster_idx(i); } }
/* * Hack -- Delete all nearby monsters */ static void do_cmd_wiz_zap(int d) { int i; /* Banish everyone nearby */ for (i = 1; i < cave_monster_max(cave); i++) { monster_type *m_ptr = cave_monster(cave, i); /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip distant monsters */ if (m_ptr->cdis > d) continue; /* Delete the monster */ delete_monster_idx(i); } /* Update monster list window */ p_ptr->redraw |= PR_MONLIST; }
bool quest_invasion_ai_hook(char *fmt) { monster_type *m_ptr; s32b m_idx; m_idx = get_next_arg(fmt); m_ptr = &m_list[m_idx]; if (p_ptr->inside_quest != QUEST_INVASION) return FALSE; /* Ugly but thats better than a call to test_monster_name which is SLOW */ if (m_ptr->r_idx == 825) { /* Oups he fleed */ if ((m_ptr->fy == cquest.data[0]) && (m_ptr->fx == cquest.data[1])) { delete_monster_idx(m_idx); cmsg_print(TERM_YELLOW, "Maeglin found the way to Gondolin! All hope is lost now!"); cquest.status = QUEST_STATUS_FAILED; town_info[2].destroyed = TRUE; return (FALSE); } /* Attack or flee ?*/ if (distance(m_ptr->fy, m_ptr->fx, p_ptr->py, p_ptr->px) <= 2) { return (FALSE); } else { process_hooks_return[0].num = cquest.data[0]; process_hooks_return[1].num = cquest.data[1]; return (TRUE); } } return (FALSE); }
/* * Hack -- Delete all nearby monsters */ static void do_cmd_wiz_zap(int d) { int i; /* Banish everyone nearby */ for (i = 1; i < mon_max; i++) { monster_type *m_ptr = &mon_list[i]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip uniques */ //if ((&r_info[m_ptr->r_idx])->flags1 & (RF1_UNIQUE)) continue; /* Skip distant monsters */ if (m_ptr->cdis > d) continue; /* Delete the monster */ delete_monster_idx(i); } }
void banish_evil_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Banish Evil"); break; case SPELL_DESC: var_set_string(res, "Attempts to remove a single evil opponent."); break; case SPELL_GAIN_MUT: msg_print("You feel a holy wrath fill you."); break; case SPELL_LOSE_MUT: msg_print("You no longer feel a holy wrath."); break; case SPELL_MUT_DESC: var_set_string(res, "You can send evil creatures directly to Hell."); break; case SPELL_CAST: { int dir = 0; int x, y; cave_type *c_ptr; monster_type *m_ptr; monster_race *r_ptr; if (!get_rep_dir2(&dir)) { var_set_bool(res, FALSE); break; } var_set_bool(res, TRUE); y = py + ddy[dir]; x = px + ddx[dir]; c_ptr = &cave[y][x]; if (!c_ptr->m_idx) { msg_print("You sense no evil there!"); break; } m_ptr = &m_list[c_ptr->m_idx]; r_ptr = &r_info[m_ptr->r_idx]; if ((r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags1 & RF1_QUESTOR) && !(r_ptr->flags1 & RF1_UNIQUE) && !p_ptr->inside_arena && !p_ptr->inside_quest && (r_ptr->level < randint1(p_ptr->lev+50)) && !(m_ptr->mflag2 & MFLAG2_NOGENO)) { /* Delete the monster, rather than killing it. */ delete_monster_idx(c_ptr->m_idx); msg_print("The evil creature vanishes in a puff of sulfurous smoke!"); } else { msg_print("Your invocation is ineffectual!"); if (one_in_(13)) m_ptr->mflag2 |= MFLAG2_NOGENO; } break; } default: default_spell(cmd, res); break; } }
/*! * @brief 現在のフロアを離れるに伴って行なわれる保存処理 * / Maintain quest monsters, mark next floor_id at stairs, save current floor, and prepare to enter next floor. * @return なし */ void leave_floor(void) { cave_type *c_ptr = NULL; feature_type *f_ptr; saved_floor_type *sf_ptr; int quest_r_idx = 0; DUNGEON_IDX i; /* Preserve pets and prepare to take these to next floor */ preserve_pet(); /* Remove all mirrors without explosion */ remove_all_mirrors(FALSE); if (p_ptr->special_defense & NINJA_S_STEALTH) set_superstealth(FALSE); /* New floor is not yet prepared */ new_floor_id = 0; /* Temporary get a floor_id (for Arena) */ if (!p_ptr->floor_id && (change_floor_mode & CFM_SAVE_FLOORS) && !(change_floor_mode & CFM_NO_RETURN)) { /* Get temporal floor_id */ p_ptr->floor_id = get_new_floor_id(); } /* Search the quest monster index */ for (i = 0; i < max_q_idx; i++) { if ((quest[i].status == QUEST_STATUS_TAKEN) && ((quest[i].type == QUEST_TYPE_KILL_LEVEL) || (quest[i].type == QUEST_TYPE_RANDOM)) && (quest[i].level == dun_level) && (dungeon_type == quest[i].dungeon) && !(quest[i].flags & QUEST_FLAG_PRESET)) { quest_r_idx = quest[i].r_idx; } } /* Maintain quest monsters */ for (i = 1; i < m_max; i++) { monster_race *r_ptr; monster_type *m_ptr = &m_list[i]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Only maintain quest monsters */ if (quest_r_idx != m_ptr->r_idx) continue; /* Extract real monster race */ r_ptr = real_r_ptr(m_ptr); /* Ignore unique monsters */ if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL)) continue; /* Delete non-unique quest monsters */ delete_monster_idx(i); } /* Check if there is a same item */ for (i = 0; i < INVEN_PACK; i++) { object_type *o_ptr = &inventory[i]; /* Skip dead objects */ if (!o_ptr->k_idx) continue; /* Delete old memorized location of the artifact */ if (object_is_fixed_artifact(o_ptr)) { a_info[o_ptr->name1].floor_id = 0; } } /* Extract current floor info or NULL */ sf_ptr = get_sf_ptr(p_ptr->floor_id); /* Choose random stairs */ if ((change_floor_mode & CFM_RAND_CONNECT) && p_ptr->floor_id) { locate_connected_stairs(sf_ptr); } /* Extract new dungeon level */ if (change_floor_mode & CFM_SAVE_FLOORS) { /* Extract stair position */ c_ptr = &cave[p_ptr->y][p_ptr->x]; f_ptr = &f_info[c_ptr->feat]; /* Get back to old saved floor? */ if (c_ptr->special && !have_flag(f_ptr->flags, FF_SPECIAL) && get_sf_ptr(c_ptr->special)) { /* Saved floor is exist. Use it. */ new_floor_id = c_ptr->special; } /* Mark shaft up/down */ if (have_flag(f_ptr->flags, FF_STAIRS) && have_flag(f_ptr->flags, FF_SHAFT)) { prepare_change_floor_mode(CFM_SHAFT); } } /* Climb up/down some sort of stairs */ if (change_floor_mode & (CFM_DOWN | CFM_UP)) { int move_num = 0; /* Extract level movement number */ if (change_floor_mode & CFM_DOWN) move_num = 1; else if (change_floor_mode & CFM_UP) move_num = -1; /* Shafts are deeper than normal stairs */ if (change_floor_mode & CFM_SHAFT) move_num += SGN(move_num); /* Get out from or Enter the dungeon */ if (change_floor_mode & CFM_DOWN) { if (!dun_level) move_num = d_info[dungeon_type].mindepth; } else if (change_floor_mode & CFM_UP) { if (dun_level + move_num < d_info[dungeon_type].mindepth) move_num = -dun_level; } dun_level += move_num; } /* Leaving the dungeon to town */ if (!dun_level && dungeon_type) { p_ptr->leaving_dungeon = TRUE; if (!vanilla_town && !lite_town) { p_ptr->wilderness_y = d_info[dungeon_type].dy; p_ptr->wilderness_x = d_info[dungeon_type].dx; } p_ptr->recall_dungeon = dungeon_type; dungeon_type = 0; /* Reach to the surface -- Clear all saved floors */ change_floor_mode &= ~CFM_SAVE_FLOORS; } /* Kill some old saved floors */ if (!(change_floor_mode & CFM_SAVE_FLOORS)) { /* Kill all saved floors */ for (i = 0; i < MAX_SAVED_FLOORS; i++) kill_saved_floor(&saved_floors[i]); /* Reset visit_mark count */ latest_visit_mark = 1; } else if (change_floor_mode & CFM_NO_RETURN) { /* Kill current floor */ kill_saved_floor(sf_ptr); } /* No current floor -- Left/Enter dungeon etc... */ if (!p_ptr->floor_id) { /* No longer need to save current floor */ return; } /* Mark next floor_id on the previous floor */ if (!new_floor_id) { /* Get new id */ new_floor_id = get_new_floor_id(); /* Connect from here */ if (c_ptr && !feat_uses_special(c_ptr->feat)) { c_ptr->special = new_floor_id; } } /* Fix connection -- level teleportation or trap door */ if (change_floor_mode & CFM_RAND_CONNECT) { if (change_floor_mode & CFM_UP) sf_ptr->upper_floor_id = new_floor_id; else if (change_floor_mode & CFM_DOWN) sf_ptr->lower_floor_id = new_floor_id; } /* If you can return, you need to save previous floor */ if ((change_floor_mode & CFM_SAVE_FLOORS) && !(change_floor_mode & CFM_NO_RETURN)) { /* Get out of the my way! */ get_out_monster(); /* Record the last visit turn of current floor */ sf_ptr->last_visit = turn; /* Forget the lite */ forget_lite(); /* Forget the view */ forget_view(); /* Forget the view */ clear_mon_lite(); /* Save current floor */ if (!save_floor(sf_ptr, 0)) { /* Save failed -- No return */ prepare_change_floor_mode(CFM_NO_RETURN); /* Kill current floor */ kill_saved_floor(get_sf_ptr(p_ptr->floor_id)); } } }
/*! * @brief フロア移動時のペット保存処理 / Preserve_pets * @return なし */ static void preserve_pet(void) { int num; MONSTER_IDX i; for (num = 0; num < MAX_PARTY_MON; num++) { party_mon[num].r_idx = 0; } if (p_ptr->riding) { monster_type *m_ptr = &m_list[p_ptr->riding]; /* Pet of other pet don't follow. */ if (m_ptr->parent_m_idx) { p_ptr->riding = 0; p_ptr->pet_extra_flags &= ~(PF_RYOUTE); p_ptr->riding_ryoute = p_ptr->old_riding_ryoute = FALSE; } else { /* Preserve the mount */ (void)COPY(&party_mon[0], m_ptr, monster_type); /* Delete from this floor */ delete_monster_idx(p_ptr->riding); } } /* * If player is in wild mode, no pets are preserved * except a monster whom player riding */ if (!p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle) { for (i = m_max - 1, num = 1; (i >= 1 && num < MAX_PARTY_MON); i--) { monster_type *m_ptr = &m_list[i]; if (!m_ptr->r_idx) continue; if (!is_pet(m_ptr)) continue; if (i == p_ptr->riding) continue; if (reinit_wilderness) { /* Don't lose sight of pets when getting a Quest */ } else { int dis = distance(p_ptr->y, p_ptr->x, m_ptr->fy, m_ptr->fx); /* Confused (etc.) monsters don't follow. */ if (MON_CONFUSED(m_ptr) || MON_STUNNED(m_ptr) || MON_CSLEEP(m_ptr)) continue; /* Pet of other pet don't follow. */ if (m_ptr->parent_m_idx) continue; /* * Pets with nickname will follow even from 3 blocks away * when you or the pet can see the other. */ if (m_ptr->nickname && ((player_has_los_bold(m_ptr->fy, m_ptr->fx) && projectable(p_ptr->y, p_ptr->x, m_ptr->fy, m_ptr->fx)) || (los(m_ptr->fy, m_ptr->fx, p_ptr->y, p_ptr->x) && projectable(m_ptr->fy, m_ptr->fx, p_ptr->y, p_ptr->x)))) { if (dis > 3) continue; } else { if (dis > 1) continue; } } (void)COPY(&party_mon[num], &m_list[i], monster_type); num++; /* Delete from this floor */ delete_monster_idx(i); } } if (record_named_pet) { for (i = m_max - 1; i >=1; i--) { monster_type *m_ptr = &m_list[i]; char m_name[80]; if (!m_ptr->r_idx) continue; if (!is_pet(m_ptr)) continue; if (!m_ptr->nickname) continue; if (p_ptr->riding == i) continue; monster_desc(m_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE); do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_MOVED, m_name); } } /* Pet of other pet may disappear. */ for (i = m_max - 1; i >=1; i--) { monster_type *m_ptr = &m_list[i]; /* Are there its parent? */ if (m_ptr->parent_m_idx && !m_list[m_ptr->parent_m_idx].r_idx) { /* Its parent have gone, it also goes away. */ if (is_seen(m_ptr)) { char m_name[80]; /* Acquire the monster name */ monster_desc(m_name, m_ptr, 0); #ifdef JP msg_format("%sは消え去った!", m_name); #else msg_format("%^s disappears!", m_name); #endif } /* Delete the monster */ delete_monster_idx(i); } } }
/*! * @brief フロアの切り替え処理 / Enter new floor. * @return なし * @details * If the floor is an old saved floor, it will be\n * restored from the temporal file. If the floor is new one, new cave\n * will be generated.\n */ void change_floor(void) { saved_floor_type *sf_ptr; bool loaded = FALSE; /* The dungeon is not ready */ character_dungeon = FALSE; /* No longer in the trap detecteded region */ p_ptr->dtrap = FALSE; /* Mega-Hack -- no panel yet */ panel_row_min = 0; panel_row_max = 0; panel_col_min = 0; panel_col_max = 0; /* Mega-Hack -- not ambushed on the wildness? */ ambush_flag = FALSE; /* No saved floors (On the surface etc.) */ if (!(change_floor_mode & CFM_SAVE_FLOORS) && !(change_floor_mode & CFM_FIRST_FLOOR)) { /* Create cave */ generate_cave(); /* Paranoia -- No new saved floor */ new_floor_id = 0; } /* In the dungeon */ else { /* No floor_id yet */ if (!new_floor_id) { /* Get new id */ new_floor_id = get_new_floor_id(); } /* Pointer for infomations of new floor */ sf_ptr = get_sf_ptr(new_floor_id); /* Try to restore old floor */ if (sf_ptr->last_visit) { /* Old saved floor is exist */ if (load_floor(sf_ptr, 0)) { loaded = TRUE; /* Forbid return stairs */ if (change_floor_mode & CFM_NO_RETURN) { cave_type *c_ptr = &cave[p_ptr->y][p_ptr->x]; if (!feat_uses_special(c_ptr->feat)) { if (change_floor_mode & (CFM_DOWN | CFM_UP)) { /* Reset to floor */ c_ptr->feat = floor_type[randint0(100)]; } c_ptr->special = 0; } } } } /* * Set lower/upper_floor_id of new floor when the new * floor is right-above/right-under the current floor. * * Stair creation/Teleport level/Trap door will take * you the same floor when you used it later again. */ if (p_ptr->floor_id) { saved_floor_type *cur_sf_ptr = get_sf_ptr(p_ptr->floor_id); if (change_floor_mode & CFM_UP) { /* New floor is right-above */ if (cur_sf_ptr->upper_floor_id == new_floor_id) sf_ptr->lower_floor_id = p_ptr->floor_id; } else if (change_floor_mode & CFM_DOWN) { /* New floor is right-under */ if (cur_sf_ptr->lower_floor_id == new_floor_id) sf_ptr->upper_floor_id = p_ptr->floor_id; } } /* Break connection to killed floor */ else { if (change_floor_mode & CFM_UP) sf_ptr->lower_floor_id = 0; else if (change_floor_mode & CFM_DOWN) sf_ptr->upper_floor_id = 0; } /* Maintain monsters and artifacts */ if (loaded) { IDX i; s32b tmp_last_visit = sf_ptr->last_visit; s32b absence_ticks; int alloc_chance = d_info[dungeon_type].max_m_alloc_chance; int alloc_times; while (tmp_last_visit > turn) tmp_last_visit -= TURNS_PER_TICK * TOWN_DAWN; absence_ticks = (turn - tmp_last_visit) / TURNS_PER_TICK; /* Maintain monsters */ for (i = 1; i < m_max; i++) { monster_race *r_ptr; monster_type *m_ptr = &m_list[i]; /* Skip dead monsters */ if (!m_ptr->r_idx) continue; if (!is_pet(m_ptr)) { /* Restore HP */ m_ptr->hp = m_ptr->maxhp = m_ptr->max_maxhp; /* Remove timed status (except MTIMED_CSLEEP) */ (void)set_monster_fast(i, 0); (void)set_monster_slow(i, 0); (void)set_monster_stunned(i, 0); (void)set_monster_confused(i, 0); (void)set_monster_monfear(i, 0); (void)set_monster_invulner(i, 0, FALSE); } /* Extract real monster race */ r_ptr = real_r_ptr(m_ptr); /* Ignore non-unique */ if (!(r_ptr->flags1 & RF1_UNIQUE) && !(r_ptr->flags7 & RF7_NAZGUL)) continue; /* Appear at a different floor? */ if (r_ptr->floor_id != new_floor_id) { /* Disapper from here */ delete_monster_idx(i); } } /* Maintain artifatcs */ for (i = 1; i < o_max; i++) { object_type *o_ptr = &o_list[i]; /* Skip dead objects */ if (!o_ptr->k_idx) continue; /* Ignore non-artifact */ if (!object_is_fixed_artifact(o_ptr)) continue; /* Appear at a different floor? */ if (a_info[o_ptr->name1].floor_id != new_floor_id) { /* Disappear from here */ delete_object_idx(i); } else { /* Cancel preserve */ a_info[o_ptr->name1].cur_num = 1; } } (void)place_quest_monsters(); /* Place some random monsters */ alloc_times = absence_ticks / alloc_chance; if (randint0(alloc_chance) < (absence_ticks % alloc_chance)) alloc_times++; for (i = 0; i < alloc_times; i++) { /* Make a (group of) new monster */ (void)alloc_monster(0, 0); } } /* New floor_id or failed to restore */ else /* if (!loaded) */ { if (sf_ptr->last_visit) { /* Temporal file is broken? */ #ifdef JP msg_print("階段は行き止まりだった。"); #else msg_print("The staircases come to a dead end..."); #endif /* Create simple dead end */ build_dead_end(); /* Break connection */ if (change_floor_mode & CFM_UP) { sf_ptr->upper_floor_id = 0; } else if (change_floor_mode & CFM_DOWN) { sf_ptr->lower_floor_id = 0; } } else { /* Newly create cave */ generate_cave(); } /* Record last visit turn */ sf_ptr->last_visit = turn; /* Set correct dun_level value */ sf_ptr->dun_level = dun_level; /* Create connected stairs */ if (!(change_floor_mode & CFM_NO_RETURN)) { /* Extract stair position */ cave_type *c_ptr = &cave[p_ptr->y][p_ptr->x]; /*** Create connected stairs ***/ /* No stairs down from Quest */ if ((change_floor_mode & CFM_UP) && !quest_number(dun_level)) { c_ptr->feat = (change_floor_mode & CFM_SHAFT) ? feat_state(feat_down_stair, FF_SHAFT) : feat_down_stair; } /* No stairs up when ironman_downward */ else if ((change_floor_mode & CFM_DOWN) && !ironman_downward) { c_ptr->feat = (change_floor_mode & CFM_SHAFT) ? feat_state(feat_up_stair, FF_SHAFT) : feat_up_stair; } /* Paranoia -- Clear mimic */ c_ptr->mimic = 0; /* Connect to previous floor */ c_ptr->special = p_ptr->floor_id; } } /* Arrive at random grid */ if (change_floor_mode & (CFM_RAND_PLACE)) { (void)new_player_spot(); } /* You see stairs blocked */ else if ((change_floor_mode & CFM_NO_RETURN) && (change_floor_mode & (CFM_DOWN | CFM_UP))) { if (!p_ptr->blind) { #ifdef JP msg_print("突然階段が塞がれてしまった。"); #else msg_print("Suddenly the stairs is blocked!"); #endif } else { #ifdef JP msg_print("ゴトゴトと何か音がした。"); #else msg_print("You hear some noises."); #endif } } /* * Update visit mark * * The "turn" is not always different number because * the level teleport doesn't take any turn. Use * visit mark instead of last visit turn to find the * oldest saved floor. */ sf_ptr->visit_mark = latest_visit_mark++; } /* Place preserved pet monsters */ place_pet(); /* Reset travel target place */ forget_travel_flow(); /* Hack -- maintain unique and artifacts */ update_unique_artifact(new_floor_id); /* Now the player is in new floor */ p_ptr->floor_id = new_floor_id; /* The dungeon is ready */ character_dungeon = TRUE; /* Hack -- Munchkin characters always get whole map */ if (p_ptr->pseikaku == SEIKAKU_MUNCHKIN) wiz_lite((bool)(p_ptr->pclass == CLASS_NINJA)); /* Remember when this level was "created" */ old_turn = turn; /* No dungeon feeling yet */ p_ptr->feeling_turn = old_turn; p_ptr->feeling = 0; /* Clear all flags */ change_floor_mode = 0L; select_floor_music(); }
/** * Decreases a monster's hit points by `dam` and handle monster death. * * Hack -- we "delay" fear messages by passing around a "fear" flag. * * We announce monster death (using an optional "death message" (`note`) * if given, and a otherwise a generic killed/destroyed message). * * Returns TRUE if the monster has been killed (and deleted). * * TODO: Consider decreasing monster experience over time, say, by using * "(m_exp * m_lev * (m_lev)) / (p_lev * (m_lev + n_killed))" instead * of simply "(m_exp * m_lev) / (p_lev)", to make the first monster * worth more than subsequent monsters. This would also need to * induce changes in the monster recall code. XXX XXX XXX **/ bool mon_take_hit(struct monster *m_ptr, int dam, bool *fear, const char *note) { s32b div, new_exp, new_exp_frac; monster_lore *l_ptr = get_lore(m_ptr->race); /* Redraw (later) if needed */ if (p_ptr->health_who == m_ptr) p_ptr->redraw |= (PR_HEALTH); /* Wake it up */ mon_clear_timed(m_ptr, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, FALSE); /* Become aware of its presence */ if (m_ptr->unaware) become_aware(m_ptr); /* Hurt it */ m_ptr->hp -= dam; /* It is dead now */ if (m_ptr->hp < 0) { char m_name[80]; char buf[80]; /* Assume normal death sound */ int soundfx = MSG_KILL; /* Play a special sound if the monster was unique */ if (rf_has(m_ptr->race->flags, RF_UNIQUE)) { if (m_ptr->race->base == lookup_monster_base("Morgoth")) soundfx = MSG_KILL_KING; else soundfx = MSG_KILL_UNIQUE; } /* Extract monster name */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Death by Missile/Spell attack */ if (note) { /* Hack -- allow message suppression */ if (strlen(note) <= 1) { /* Be silent */ } else { char *str = format("%s%s", m_name, note); my_strcap(str); msgt(soundfx, "%s", str); } } /* Death by physical attack -- invisible monster */ else if (!m_ptr->ml) msgt(soundfx, "You have killed %s.", m_name); /* Death by Physical attack -- non-living monster */ else if (monster_is_unusual(m_ptr->race)) msgt(soundfx, "You have destroyed %s.", m_name); /* Death by Physical attack -- living monster */ else msgt(soundfx, "You have slain %s.", m_name); /* Player level */ div = p_ptr->lev; /* Give some experience for the kill */ new_exp = ((long)m_ptr->race->mexp * m_ptr->race->level) / div; /* Handle fractional experience */ new_exp_frac = ((((long)m_ptr->race->mexp * m_ptr->race->level) % div) * 0x10000L / div) + p_ptr->exp_frac; /* Keep track of experience */ if (new_exp_frac >= 0x10000L) { new_exp++; p_ptr->exp_frac = (u16b)(new_exp_frac - 0x10000L); } else p_ptr->exp_frac = (u16b)new_exp_frac; /* When the player kills a Unique, it stays dead */ if (rf_has(m_ptr->race->flags, RF_UNIQUE)) { char unique_name[80]; m_ptr->race->max_num = 0; /* * This gets the correct name if we slay an invisible * unique and don't have See Invisible. */ monster_desc(unique_name, sizeof(unique_name), m_ptr, MDESC_SHOW | MDESC_IND2); /* Log the slaying of a unique */ strnfmt(buf, sizeof(buf), "Killed %s", unique_name); history_add(buf, HISTORY_SLAY_UNIQUE, 0); } /* Gain experience */ player_exp_gain(p_ptr, new_exp); /* Generate treasure */ monster_death(m_ptr, FALSE); /* Recall even invisible uniques or winners */ if (m_ptr->ml || rf_has(m_ptr->race->flags, RF_UNIQUE)) { /* Count kills this life */ if (l_ptr->pkills < MAX_SHORT) l_ptr->pkills++; /* Count kills in all lives */ if (l_ptr->tkills < MAX_SHORT) l_ptr->tkills++; /* Hack -- Auto-recall */ monster_race_track(m_ptr->race); } /* Delete the monster */ delete_monster_idx(m_ptr->midx); /* Not afraid */ (*fear) = FALSE; /* Monster is dead */ return (TRUE); } /* Mega-Hack -- Pain cancels fear */ if (!(*fear) && m_ptr->m_timed[MON_TMD_FEAR] && (dam > 0)) { int tmp = randint1(dam); /* Cure a little fear */ if (tmp < m_ptr->m_timed[MON_TMD_FEAR]) { /* Reduce fear */ mon_dec_timed(m_ptr, MON_TMD_FEAR, tmp, MON_TMD_FLG_NOMESSAGE, FALSE); } /* Cure all the fear */ else { /* Cure fear */ mon_clear_timed(m_ptr, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE, FALSE); /* No more fear */ (*fear) = FALSE; } } /* Sometimes a monster gets scared by damage */ if (!m_ptr->m_timed[MON_TMD_FEAR] && !rf_has(m_ptr->race->flags, RF_NO_FEAR) && dam > 0) { int percentage; /* Percentage of fully healthy */ percentage = (100L * m_ptr->hp) / m_ptr->maxhp; /* * Run (sometimes) if at 10% or less of max hit points, * or (usually) when hit for half its current hit points */ if ((randint1(10) >= percentage) || ((dam >= m_ptr->hp) && (randint0(100) < 80))) { int timer = randint1(10) + (((dam >= m_ptr->hp) && (percentage > 7)) ? 20 : ((11 - percentage) * 5)); /* Hack -- note fear */ (*fear) = TRUE; mon_inc_timed(m_ptr, MON_TMD_FEAR, timer, MON_TMD_FLG_NOMESSAGE | MON_TMD_FLG_NOFAIL, FALSE); } } /* Not dead yet */ return (FALSE); }
/** * Compacts and reorders the monster list. * * This function can be very dangerous, use with caution! * * When `num_to_compact` is 0, we just reorder the monsters into a more compact * order, eliminating any "holes" left by dead monsters. If `num_to_compact` is * positive, then we delete at least that many monsters and then reorder. * We try not to delete monsters that are high level or close to the player. * Each time we make a full pass through the monster list, if we haven't * deleted enough monsters, we relax our bounds a little to accept * monsters of a slightly higher level, and monsters slightly closer to * the player. */ void compact_monsters(int num_to_compact) { int m_idx, num_compacted, iter; int max_lev, min_dis, chance; /* Message (only if compacting) */ if (num_to_compact) msg("Compacting monsters..."); /* Compact at least 'num_to_compact' objects */ for (num_compacted = 0, iter = 1; num_compacted < num_to_compact; iter++) { /* Get more vicious each iteration */ max_lev = 5 * iter; /* Get closer each iteration */ min_dis = 5 * (20 - iter); /* Check all the monsters */ for (m_idx = 1; m_idx < cave_monster_max(cave); m_idx++) { monster_type *m_ptr = cave_monster(cave, m_idx); const monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Skip "dead" monsters */ if (!m_ptr->r_idx) continue; /* High level monsters start out "immune" */ if (r_ptr->level > max_lev) continue; /* Ignore nearby monsters */ if ((min_dis > 0) && (m_ptr->cdis < min_dis)) continue; /* Saving throw chance */ chance = 90; /* Only compact "Quest" Monsters in emergencies */ if (rf_has(r_ptr->flags, RF_QUESTOR) && (iter < 1000)) chance = 100; /* Try not to compact Unique Monsters */ if (rf_has(r_ptr->flags, RF_UNIQUE)) chance = 99; /* All monsters get a saving throw */ if (randint0(100) < chance) continue; /* Delete the monster */ delete_monster_idx(m_idx); /* Count the monster */ num_compacted++; } } /* Excise dead monsters (backwards!) */ for (m_idx = cave_monster_max(cave) - 1; m_idx >= 1; m_idx--) { monster_type *m_ptr = cave_monster(cave, m_idx); /* Skip real monsters */ if (m_ptr->r_idx) continue; /* Move last monster into open hole */ compact_monsters_aux(cave_monster_max(cave) - 1, m_idx); /* Compress "cave->mon_max" */ cave->mon_max--; } }