static bool _get_loc(int set, int* x, int *y) { int dummy = 0; while (dummy < SAFE_MAX_ATTEMPTS) { bool room; cave_type *c_ptr; dummy++; *x = randint0(cur_wid); *y = randint0(cur_hgt); c_ptr = &cave[*y][*x]; if (!is_floor_grid(c_ptr) || c_ptr->o_idx || c_ptr->m_idx) continue; if (player_bold(*y, *x)) continue; room = (cave[*y][*x].info & CAVE_ROOM) ? TRUE : FALSE; if (set == ALLOC_SET_CORR && room) continue; if (set == ALLOC_SET_ROOM && !room) continue; return TRUE; } return FALSE; }
/* * Strictly check if monster can enter the grid */ bool monster_can_enter(int y, int x, monster_race *r_ptr, u16b mode) { cave_type *c_ptr = &cave[y][x]; /* Player or other monster */ if (player_bold(y, x)) return FALSE; if (c_ptr->m_idx) return FALSE; return monster_can_cross_terrain(c_ptr->feat, r_ptr, mode); }
/*! * @brief モンスターにとってボルト型魔法が有効な状態かを返す / * Determine if a bolt spell will hit the player. * @param y1 ボルト魔法発射地点のY座標 * @param x1 ボルト魔法発射地点のX座標 * @param y2 ボルト魔法目標地点のY座標 * @param x2 ボルト魔法目標地点のX座標 * @param is_friend モンスターがプレイヤーに害意を持たない(ペットか友好的)ならばTRUEをつける * @return ボルト型魔法が有効ならばTRUEを返す。 * @details * Originally, it was possible for a friendly to shoot another friendly.\n * Change it so a "clean shot" means no equally friendly monster is\n * between the attacker and target.\n *\n * This is exactly like "projectable", but it will\n * return FALSE if a monster is in the way.\n * no equally friendly monster is\n * between the attacker and target.\n */ bool clean_shot(int y1, int x1, int y2, int x2, bool is_friend) { /* Must be the same as projectable() */ int i, y, x; int grid_n = 0; u16b grid_g[512]; /* Check the projection path */ grid_n = project_path(grid_g, MAX_RANGE, y1, x1, y2, x2, 0); /* No grid is ever projectable from itself */ if (!grid_n) return (FALSE); /* Final grid */ y = GRID_Y(grid_g[grid_n-1]); x = GRID_X(grid_g[grid_n-1]); /* May not end in an unrequested grid */ if ((y != y2) || (x != x2)) return (FALSE); for (i = 0; i < grid_n; i++) { y = GRID_Y(grid_g[i]); x = GRID_X(grid_g[i]); if ((cave[y][x].m_idx > 0) && !((y == y2) && (x == x2))) { monster_type *m_ptr = &m_list[cave[y][x].m_idx]; if (is_friend == is_pet(m_ptr)) { return (FALSE); } } /* Pets may not shoot through the character - TNB */ if (player_bold(y, x)) { if (is_friend) return (FALSE); } } return (TRUE); }
/*! * @brief モンスターが敵対モンスターにビームを当てること可能かを判定する / * Determine if a beam spell will hit the target. * @param y1 始点のY座標 * @param x1 始点のX座標 * @param y2 目標のY座標 * @param x2 目標のX座標 * @param m_ptr 使用するモンスターの構造体参照ポインタ * @return ビームが到達可能ならばTRUEを返す */ static bool direct_beam(int y1, int x1, int y2, int x2, monster_type *m_ptr) { bool hit2 = FALSE; int i, y, x; int grid_n = 0; u16b grid_g[512]; bool is_friend = is_pet(m_ptr); /* Check the projection path */ grid_n = project_path(grid_g, MAX_RANGE, y1, x1, y2, x2, PROJECT_THRU); /* No grid is ever projectable from itself */ if (!grid_n) return (FALSE); for (i = 0; i < grid_n; i++) { y = GRID_Y(grid_g[i]); x = GRID_X(grid_g[i]); if (y == y2 && x == x2) hit2 = TRUE; else if (is_friend && cave[y][x].m_idx > 0 && !are_enemies(m_ptr, &m_list[cave[y][x].m_idx])) { /* Friends don't shoot friends */ return FALSE; } if (is_friend && player_bold(y, x)) return FALSE; } if (!hit2) return FALSE; return TRUE; }
/* * Allocates some objects (using "place" and "type") */ static void alloc_object(int set, int typ, int num) { int y = 0, x = 0, k; int dummy = 0; cave_type *c_ptr; /* A small level has few objects. */ num = num * cur_hgt * cur_wid / (MAX_HGT*MAX_WID) +1; /* Place some objects */ for (k = 0; k < num; k++) { /* Pick a "legal" spot */ while (dummy < SAFE_MAX_ATTEMPTS) { bool room; dummy++; /* Location */ y = randint0(cur_hgt); x = randint0(cur_wid); c_ptr = &cave[y][x]; /* Require "naked" floor grid */ if (!is_floor_grid(c_ptr) || c_ptr->o_idx || c_ptr->m_idx) continue; /* Avoid player location */ if (player_bold(y, x)) continue; /* Check for "room" */ room = (cave[y][x].info & CAVE_ROOM) ? TRUE : FALSE; /* Require corridor? */ if ((set == ALLOC_SET_CORR) && room) continue; /* Require room? */ if ((set == ALLOC_SET_ROOM) && !room) continue; /* Accept it */ break; } if (dummy >= SAFE_MAX_ATTEMPTS) { if (cheat_room) { #ifdef JP msg_print("警告!アイテムを配置できません!"); #else msg_print("Warning! Could not place object!"); #endif } return; } /* Place something */ switch (typ) { case ALLOC_TYP_RUBBLE: { place_rubble(y, x); cave[y][x].info &= ~(CAVE_FLOOR); break; } case ALLOC_TYP_TRAP: { place_trap(y, x); cave[y][x].info &= ~(CAVE_FLOOR); break; } case ALLOC_TYP_GOLD: { place_gold(y, x); break; } case ALLOC_TYP_OBJECT: { place_object(y, x, 0L); break; } } } }
_rush_result _rush_attack(int rng, _rush_type type) { _rush_result result = _rush_cancelled; int tx, ty; int tm_idx = 0; u16b path_g[32]; int path_n, i; bool moved = FALSE; int flg = 0; int dis = 0; if (type == _rush_normal) flg = PROJECT_STOP | PROJECT_KILL; else if (type == _rush_acrobatic) flg = PROJECT_THRU | PROJECT_KILL; else flg = PROJECT_DISI | PROJECT_THRU; if (!p_ptr->duelist_target_idx) { msg_print("You need to select a foe first (Mark Target)."); return result; } tm_idx = p_ptr->duelist_target_idx; tx = m_list[tm_idx].fx; ty = m_list[tm_idx].fy; dis = distance(ty, tx, py, px); /* Foe must be visible. For all charges except the phase charge, the foe must also be in your line of sight */ if (!m_list[p_ptr->duelist_target_idx].ml || (type != _rush_phase && !los(ty, tx, py, px))) { msg_format("%^s is not in your line of sight.", duelist_current_challenge()); return result; } if (dis > rng) { msg_format("Your foe is out of range (%d vs %d).", dis, rng); if (!get_check("Charge anyway? ")) return result; } project_length = rng; path_n = project_path(path_g, project_length, py, px, ty, tx, flg); project_length = 0; if (!path_n) return result; result = _rush_failed; /* Use ty and tx as to-move point */ ty = py; tx = px; /* Scrolling the cave would invalidate our path! */ if (!dun_level && !p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle) wilderness_scroll_lock = TRUE; /* Project along the path */ for (i = 0; i < path_n; i++) { monster_type *m_ptr; cave_type *c_ptr; bool can_enter = FALSE; bool old_pass_wall = p_ptr->pass_wall; int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); c_ptr = &cave[ny][nx]; switch (type) { case _rush_normal: can_enter = cave_empty_bold(ny, nx) && player_can_enter(c_ptr->feat, 0); break; case _rush_acrobatic: can_enter = !c_ptr->m_idx && player_can_enter(c_ptr->feat, 0); break; case _rush_phase: p_ptr->pass_wall = TRUE; can_enter = !c_ptr->m_idx && player_can_enter(c_ptr->feat, 0); p_ptr->pass_wall = old_pass_wall; break; } if (can_enter) { ty = ny; tx = nx; continue; } if (!c_ptr->m_idx) { msg_print("Failed!"); break; } /* Move player before updating the monster */ if (!player_bold(ty, tx)) move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); moved = TRUE; /* Update the monster */ update_mon(c_ptr->m_idx, TRUE); /* Found a monster */ m_ptr = &m_list[c_ptr->m_idx]; /* But it is not the monster we seek! */ if (tm_idx != c_ptr->m_idx) { /* Acrobatic Charge attempts to displace monsters on route */ if (type == _rush_acrobatic) { /* Swap position of player and monster */ set_monster_csleep(c_ptr->m_idx, 0); move_player_effect(ny, nx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); ty = ny; tx = nx; continue; } /* Normal Charge just attacks first monster on route */ else msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone"); } /* Attack the monster */ if (tm_idx == p_ptr->duelist_target_idx) result = _rush_succeeded; py_attack(ny, nx, 0); break; } if (!moved && !player_bold(ty, tx)) move_player_effect(ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP); if (!dun_level && !p_ptr->wild_mode && !p_ptr->inside_arena && !p_ptr->inside_battle) { wilderness_scroll_lock = FALSE; wilderness_move_player(px, py); } return result; }
/*! * @brief モンスターが敵対モンスターに直接ブレスを当てることが可能かを判定する / * Determine if a breath will hit the target. * @param y1 始点のY座標 * @param x1 始点のX座標 * @param y2 目標のY座標 * @param x2 目標のX座標 * @param rad 半径 * @param typ 効果属性ID * @param is_friend TRUEならば、プレイヤーを巻き込む時にブレスの判定をFALSEにする。 * @return ブレスを直接当てられるならばTRUEを返す */ static bool breath_direct(int y1, int x1, int y2, int x2, int rad, int typ, bool is_friend) { /* Must be the same as projectable() */ int i; /* Initial grid */ int y = y1; int x = x1; int grid_n = 0; u16b grid_g[512]; int grids = 0; byte gx[1024], gy[1024]; byte gm[32]; int gm_rad = rad; bool hit2 = FALSE; bool hityou = FALSE; int flg; switch (typ) { case GF_LITE: case GF_LITE_WEAK: flg = PROJECT_LOS; break; case GF_DISINTEGRATE: flg = PROJECT_DISI; break; default: flg = 0; break; } /* Check the projection path */ grid_n = project_path(grid_g, MAX_RANGE, y1, x1, y2, x2, flg); /* Project along the path */ for (i = 0; i < grid_n; ++i) { int ny = GRID_Y(grid_g[i]); int nx = GRID_X(grid_g[i]); if (flg & PROJECT_DISI) { /* Hack -- Balls explode before reaching walls */ if (cave_stop_disintegration(ny, nx)) break; } else if (flg & PROJECT_LOS) { /* Hack -- Balls explode before reaching walls */ if (!cave_los_bold(ny, nx)) break; } else { /* Hack -- Balls explode before reaching walls */ if (!cave_have_flag_bold(ny, nx, FF_PROJECT)) break; } /* Save the "blast epicenter" */ y = ny; x = nx; } grid_n = i; if (!grid_n) { if (flg & PROJECT_DISI) { if (in_disintegration_range(y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) hit2 = TRUE; if (in_disintegration_range(y1, x1, p_ptr->y, p_ptr->x) && (distance(y1, x1, p_ptr->y, p_ptr->x) <= rad)) hityou = TRUE; } else if (flg & PROJECT_LOS) { if (los(y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) hit2 = TRUE; if (los(y1, x1, p_ptr->y, p_ptr->x) && (distance(y1, x1, p_ptr->y, p_ptr->x) <= rad)) hityou = TRUE; } else { if (projectable(y1, x1, y2, x2) && (distance(y1, x1, y2, x2) <= rad)) hit2 = TRUE; if (projectable(y1, x1, p_ptr->y, p_ptr->x) && (distance(y1, x1, p_ptr->y, p_ptr->x) <= rad)) hityou = TRUE; } } else { breath_shape(grid_g, grid_n, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, y, x, typ); for (i = 0; i < grids; i++) { /* Extract the location */ y = gy[i]; x = gx[i]; if ((y == y2) && (x == x2)) hit2 = TRUE; if (player_bold(y, x)) hityou = TRUE; } } if (!hit2) return FALSE; if (is_friend && hityou) return FALSE; return TRUE; }