void _grasp_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Vampiric Grasp"); break; case SPELL_DESC: var_set_string(res, "Pulls a target creature to you."); break; case SPELL_CAST: { int m_idx; bool fear = FALSE; monster_type *m_ptr; monster_race *r_ptr; char m_name[MAX_NLEN]; var_set_bool(res, FALSE); if (!target_set(TARGET_KILL)) break; if (!cave[target_row][target_col].m_idx) break; if (!player_has_los_bold(target_row, target_col)) break; if (!projectable(py, px, target_row, target_col)) break; var_set_bool(res, TRUE); m_idx = cave[target_row][target_col].m_idx; m_ptr = &m_list[m_idx]; r_ptr = &r_info[m_ptr->r_idx]; monster_desc(m_name, m_ptr, 0); if (r_ptr->flagsr & RFR_RES_TELE) { if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flagsr & RFR_RES_ALL)) { if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; msg_format("%s is unaffected!", m_name); break; } else if (r_ptr->level > randint1(100)) { if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; msg_format("%s resists!", m_name); break; } } msg_format("You grasp %s.", m_name); teleport_monster_to(m_idx, py, px, 100, TELEPORT_PASSIVE); mon_take_hit(m_idx, damroll(10, 10), &fear, extract_note_dies(real_r_ptr(m_ptr))); break; } default: default_spell(cmd, res); break; } }
/*! * @brief フロア移動時にペットを伴った場合の準備処理 / Pre-calculate the racial counters of preserved pets * @return なし * @details * To prevent multiple generation of unique monster who is the minion of player */ void precalc_cur_num_of_pet(void) { monster_type *m_ptr; int i; int max_num = p_ptr->wild_mode ? 1 : MAX_PARTY_MON; for (i = 0; i < max_num; i++) { m_ptr = &party_mon[i]; /* Skip empty monsters */ if (!m_ptr->r_idx) continue; /* Hack -- Increase the racial counter */ real_r_ptr(m_ptr)->cur_num++; } }
/*! * @brief ユニークモンスターやアーティファクトの所在フロアを更新する / Hack -- Update location of unique monsters and artifacts * @param cur_floor_id 現在のフロアID * @return なし * @details * The r_ptr->floor_id and a_ptr->floor_id are not updated correctly\n * while new floor creation since dungeons may be re-created by\n * auto-scum option.\n */ static void update_unique_artifact(s16b cur_floor_id) { int i; /* Maintain unique 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; /* Extract real monster race */ r_ptr = real_r_ptr(m_ptr); /* Memorize location of the unique monster */ if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL)) { r_ptr->floor_id = cur_floor_id; } } /* 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; /* Memorize location of the artifact */ if (object_is_fixed_artifact(o_ptr)) { a_info[o_ptr->name1].floor_id = cur_floor_id; } } }
/*! * @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 移動先のフロアに伴ったペットを配置する / Place preserved pet monsters on new floor * @return なし */ static void place_pet(void) { int i; int max_num = p_ptr->wild_mode ? 1 : MAX_PARTY_MON; for (i = 0; i < max_num; i++) { POSITION cy = 0, cx = 0; MONSTER_IDX m_idx; if (!(party_mon[i].r_idx)) continue; if (i == 0) { m_idx = m_pop(); p_ptr->riding = m_idx; if (m_idx) { cy = p_ptr->y; cx = p_ptr->x; } } else { int j; POSITION d; for (d = 1; d < 6; d++) { for (j = 1000; j > 0; j--) { scatter(&cy, &cx, p_ptr->y, p_ptr->x, d, 0); if (monster_can_enter(cy, cx, &r_info[party_mon[i].r_idx], 0)) break; } if (j) break; } m_idx = (d == 6) ? 0 : m_pop(); } if (m_idx) { monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr; cave[cy][cx].m_idx = m_idx; m_ptr->r_idx = party_mon[i].r_idx; /* Copy all member of the structure */ *m_ptr = party_mon[i]; r_ptr = real_r_ptr(m_ptr); m_ptr->fy = cy; m_ptr->fx = cx; m_ptr->ml = TRUE; m_ptr->mtimed[MTIMED_CSLEEP] = 0; /* Paranoia */ m_ptr->hold_o_idx = 0; m_ptr->target_y = 0; if ((r_ptr->flags1 & RF1_FORCE_SLEEP) && !ironman_nightmare) { /* Monster is still being nice */ m_ptr->mflag |= (MFLAG_NICE); /* Must repair monsters */ repair_monsters = TRUE; } /* Update the monster */ update_mon(m_idx, TRUE); lite_spot(cy, cx); /* Pre-calculated in precalc_cur_num_of_pet() */ /* r_ptr->cur_num++; */ /* Hack -- Count the number of "reproducers" */ if (r_ptr->flags2 & RF2_MULTIPLY) num_repro++; /* Hack -- Notice new multi-hued monsters */ { monster_race *ap_r_ptr = &r_info[m_ptr->ap_r_idx]; if (ap_r_ptr->flags1 & (RF1_ATTR_MULTI | RF1_SHAPECHANGER)) shimmer_monsters = TRUE; } } else { monster_type *m_ptr = &party_mon[i]; monster_race *r_ptr = real_r_ptr(m_ptr); char m_name[80]; monster_desc(m_name, m_ptr, 0); #ifdef JP msg_format("%sとはぐれてしまった。", m_name); #else msg_format("You have lost sight of %s.", m_name); #endif if (record_named_pet && m_ptr->nickname) { monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_LOST_SIGHT, m_name); } /* Pre-calculated in precalc_cur_num_of_pet(), but need to decrease */ if (r_ptr->cur_num) r_ptr->cur_num--; } } /* For accuracy of precalc_cur_num_of_pet() */ (void)C_WIPE(party_mon, MAX_PARTY_MON, monster_type); }
/*! * @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(); }
/* * Generates a random dungeon level -RAK- * * Hack -- regenerate any "overflow" levels */ void generate_cave(void) { int num; /* Fill the arrays of floors and walls in the good proportions */ set_floor_and_wall(dungeon_type); /* Generate */ for (num = 0; TRUE; num++) { bool okay = TRUE; cptr why = NULL; clear_cave(); /* Build the arena -KMW- */ if (p_ptr->inside_arena) { arena_gen(); } /* Build the battle -KMW- */ else if (p_ptr->inside_battle) { battle_gen(); } /* Enter a special quest level from the wilderness (QUEST_ENTER(id)) */ else if (enter_quest) { quests_generate(enter_quest); enter_quest = 0; } /* Build the town */ else if (!dun_level) { /* Make the wilderness */ if (p_ptr->wild_mode) wilderness_gen_small(); else wilderness_gen(); } /* Build a real level, possibly a quest level. * The quest level might want to generate itself * or it might simply need to 'place quest monsters' */ else { quest_ptr q; quests_on_generate(dungeon_type, dun_level); q = quests_get_current(); if (q && (q->flags & QF_GENERATE)) quest_generate(q); else { okay = level_gen(&why); if (okay && q) okay = quest_post_generate(q); } } if (o_max >= max_o_idx) { why = "too many objects"; okay = FALSE; } else if (m_max >= max_m_idx) { why = "too many monsters"; okay = FALSE; } if (okay) break; if (why) msg_format("Generation restarted (%s)", why); wipe_o_list(); wipe_m_list(); } glow_deep_lava_and_bldg(); p_ptr->enter_dungeon = FALSE; wipe_generate_cave_flags(); #if 0 wiz_lite(FALSE); detect_all(255); if (1) { int i, ct = 0; char buf[MAX_NLEN]; for (i = 0; i < max_o_idx; i++) { if (!o_list[i].k_idx) continue; ct++; identify_item(&o_list[i]); o_list[i].ident |= IDENT_MENTAL; if (o_list[i].name1 || o_list[i].name2) { object_desc(buf, &o_list[i], 0); msg_print(buf); } } msg_format("Objects=%d", ct); } { int i; int lvl = 0, ct = 0, uniques = 0, ct_drops = 0; for (i = 1; i < max_m_idx; i++) { monster_type *m_ptr = &m_list[i]; monster_race *r_ptr; if (!m_ptr->r_idx) continue; r_ptr = real_r_ptr(m_ptr); ct++; ct_drops += m_ptr->drop_ct; lvl += r_ptr->level; if (r_ptr->flags1 & RF1_UNIQUE) uniques++; } msg_format("DL=%d, Monsters=%d, Drops=%d, <ML>= %d, Uniques=%d", dun_level, ct, ct_drops, lvl/MAX(ct, 1), uniques); for (i = 0; i < ct_drops; i++) { object_type forge; char buf[MAX_NLEN]; make_object(&forge, 0); /* TODO: DROP_GOOD? */ /*if (forge.name1 || forge.name2)*/ if (forge.curse_flags) { identify_item(&forge); forge.ident |= IDENT_MENTAL; object_desc(buf, &forge, 0); msg_print(buf); } } } #endif }