/** * This is a helper function used by do_cmd_throw and do_cmd_fire. * * It abstracts out the projectile path, display code, identify and clean up * logic, while using the 'attack' parameter to do work particular to each * kind of attack. */ static void ranged_helper(int item, int dir, int range, int shots, ranged_attack attack) { /* Get the ammo */ object_type *o_ptr = object_from_item_idx(item); int i, j; byte missile_attr = object_attr(o_ptr); char missile_char = object_char(o_ptr); object_type object_type_body; object_type *i_ptr = &object_type_body; char o_name[80]; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor; /* Start at the player */ int x = p_ptr->px; int y = p_ptr->py; /* Predict the "target" location */ s16b ty = y + 99 * ddy[dir]; s16b tx = x + 99 * ddx[dir]; bool hit_target = FALSE; /* Check for target validity */ if ((dir == 5) && target_okay()) { int taim; char msg[80]; target_get(&tx, &ty); taim = distance(y, x, ty, tx); if (taim > range) { sprintf (msg, "Target out of range by %d squares. Fire anyway? ", taim - range); if (!get_check(msg)) return; } } /* Sound */ sound(MSG_SHOOT); object_notice_on_firing(o_ptr); /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR); /* Actually "fire" the object -- Take a partial turn */ p_ptr->energy_use = (100 / shots); /* Calculate the path */ path_n = project_path(path_g, range, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(p_ptr); /* Start at the player */ x = p_ptr->px; y = p_ptr->py; /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); Term_xtra(TERM_XTRA_DELAY, msec); cave_light_spot(cave, y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); } else { /* Delay anyway for consistency */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave->m_idx[y][x] > 0) break; } /* Try the attack on the monster at (x, y) if any */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); monster_race *r_ptr = &r_info[m_ptr->r_idx]; int visible = m_ptr->ml; bool fear = FALSE; char m_name[80]; const char *note_dies = monster_is_unusual(r_ptr) ? " is destroyed." : " dies."; struct attack_result result = attack(o_ptr, y, x); int dmg = result.dmg; u32b msg_type = result.msg_type; const char *hit_verb = result.hit_verb; if (result.success) { hit_target = TRUE; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); object_notice_attack_plusses(o_ptr); /* No negative damage; change verb if no damage done */ if (dmg <= 0) { dmg = 0; hit_verb = "fail to harm"; } if (!visible) { /* Invisible monster */ msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name); } else { /* Visible monster */ if (msg_type == MSG_SHOOT_HIT) msgt(MSG_SHOOT_HIT, "The %s %s %s.", o_name, hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) { msgt(MSG_HIT_GOOD, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { msgt(MSG_HIT_GREAT, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { msgt(MSG_HIT_SUPERB, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } /* Track this monster */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]); } /* Complex message */ if (p_ptr->wizard) msg("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Hit the monster, check for death */ if (!mon_take_hit(cave->m_idx[y][x], dmg, &fear, note_dies)) { message_pain(cave->m_idx[y][x], dmg); if (fear && m_ptr->ml) add_monster_message(m_name, cave->m_idx[y][x], MON_MSG_FLEE_IN_TERROR, TRUE); } } } /* Obtain a local object */ object_copy(i_ptr, o_ptr); object_split(i_ptr, o_ptr, 1); /* See if the ammunition broke or not */ j = breakage_chance(i_ptr, hit_target); /* Drop (or break) near that location */ drop_near(cave, i_ptr, j, y, x, TRUE); if (item >= 0) { /* The ammo is from the inventory */ inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } else { /* The ammo is from the floor */ floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } }
/** * Query the dungeon */ static void do_cmd_wiz_query(void) { int py = p_ptr->py; int px = p_ptr->px; int y, x; char cmd; u16b mask = 0x00; /* Get a "debug command" */ if (!get_com("Debug Command Query: ", &cmd)) return; /* Extract a flag */ switch (cmd) { case '0': mask = (1 << 0); break; case '1': mask = (1 << 1); break; case '2': mask = (1 << 2); break; case '3': mask = (1 << 3); break; case '4': mask = (1 << 4); break; case '5': mask = (1 << 5); break; case '6': mask = (1 << 6); break; case '7': mask = (1 << 7); break; case 'm': mask |= (CAVE_MARK); break; case 'g': mask |= (CAVE_GLOW); break; case 'r': mask |= (CAVE_ROOM); break; case 'i': mask |= (CAVE_ICKY); break; case 's': mask |= (CAVE_SEEN); break; case 'v': mask |= (CAVE_VIEW); break; case 't': mask |= (CAVE_TEMP); break; case 'w': mask |= (CAVE_WALL); break; } /* Scan map */ for (y = Term->offset_y; y <= Term->offset_y + SCREEN_HGT; y++) { for (x = Term->offset_x; x <= Term->offset_x + SCREEN_WID; x++) { byte a = TERM_RED; /* Given mask, show only those grids */ if (mask && !(cave_info[y][x][0] & mask)) continue; /* Given no mask, show unknown grids */ if (!mask && (cave_info[y][x][0] & (CAVE_MARK))) continue; /* Color */ if (cave_floor_bold(y, x)) a = TERM_YELLOW; /* Display player/floors/walls */ if ((y == py) && (x == px)) { print_rel('@', a, y, x); } else if (cave_floor_bold(y, x)) { print_rel('*', a, y, x); } else { print_rel('#', a, y, x); } } } /* Get keypress */ msg_print("Press any key."); msg_print(NULL); /* Redraw map */ prt_map(); }
/** * Debug scent trails and noise bursts. */ static void do_cmd_wiz_hack_ben(void) { #ifdef MONSTER_FLOW char cmd; int py = p_ptr->py; int px = p_ptr->px; int i, y, x, y2, x2; /* Get a "debug command" */ if (!get_com("Press 'S' for scent, 'N' for noise info: ", &cmd)) return; /* Analyze the command */ switch (cmd) { case 'S': case 's': { /* Update map */ for (y = Term->offset_y; y <= Term->offset_y + SCREEN_HGT; y++) { for (x = Term->offset_x; x <= Term->offset_x + SCREEN_WID; x++) { byte a; int age = get_scent(y, x); /* Must have scent */ if (age == -1) continue; /* Pretty colors by age */ if (age > SMELL_STRENGTH) a = TERM_L_DARK; else if (age < 10) a = TERM_BLUE; else if (age < 20) a = TERM_L_BLUE; else if (age < 30) a = TERM_GREEN; else if (age < 40) a = TERM_L_GREEN; else if (age < 50) a = TERM_YELLOW; else if (age < 60) a = TERM_ORANGE; else if (age < 70) a = TERM_L_RED; else a = TERM_RED; /* Display player/floors/walls */ if ((y == py) && (x == px)) { print_rel('@', a, y, x); } else { print_rel('0' + (age % 10), a, y, x); } } } /* Prompt */ prt("Scent ages", 0, 0); /* Wait for a keypress */ (void) inkey(); /* Redraw map */ prt_map(); break; } case 'N': case 'n': { /* Get a "debug command" */ if (!get_com ("Press 'D' for direction of flow, 'C' for actual cost values: ", &cmd)) return; if ((cmd == 'D') || (cmd == 'd')) { /* Update map */ for (y = Term->offset_y; y <= Term->offset_y + SCREEN_HGT; y++) { for (x = Term->offset_x; x <= Term->offset_x + SCREEN_WID; x++) { int lowest_cost = cave_cost[y][x]; int dir = -1; int cost; if (lowest_cost == 0) continue; for (i = 0; i < 8; i++) { /* Get the location */ y2 = y + ddy_ddd[i]; x2 = x + ddx_ddd[i]; cost = cave_cost[y2][x2]; if (!cost) continue; /* If this grid's scent is younger, save it */ if (lowest_cost > cost) lowest_cost = cost; /* If it isn't, look elsewhere */ else continue; /* Save this direction */ dir = i; } /* If we didn't find any younger scent, print a '5' */ if (dir == -1) print_rel('5', TERM_YELLOW, y, x); /* Otherwise, convert to true direction and print */ else { i = ddd[dir]; print_rel('0' + i, TERM_L_BLUE, y, x); } } } /* Prompt */ prt("Directions given to advancing monsters using noise info", 0, 0); /* Wait for a keypress */ (void) inkey(); /* Redraw map */ prt_map(); } /* Actual cost values */ else { int j; for (i = cost_at_center - 2; i <= 100 + NOISE_STRENGTH; ++i) { /* First show grids with no scent */ if (i == cost_at_center - 2) j = 0; /* Then show specially marked grids (bug-checking) */ else if (i == cost_at_center - 1) j = 255; /* Then show standard grids */ else j = i; /* Update map */ for (y = Term->offset_y; y <= Term->offset_y + SCREEN_HGT; y++) { for (x = Term->offset_x; x <= Term->offset_x + SCREEN_WID; x++) { byte a = TERM_YELLOW; /* Display proper cost */ if (cave_cost[y][x] != j) continue; /* Display player/floors/walls */ if ((y == py) && (x == px)) { print_rel('@', a, y, x); } else if (cave_floor_bold(y, x)) { print_rel('*', a, y, x); } else { print_rel('#', a, y, x); } } } /* Prompt */ if (j == 0) { prt("Grids with no scent", 0, 0); } else if (j == 255) { prt("Specially marked grids", 0, 0); } else { prt(format("Depth %d: ", j), 0, 0); } /* Get key */ if (inkey() == ESCAPE) break; /* Redraw map */ prt_map(); } } break; } default: { break; } } /* Done */ prt("", 0, 0); /* Redraw map */ prt_map(); #else /* MONSTER_FLOW */ /* Oops */ msg_print("Monster flow is not included in this copy of the game."); #endif /* MONSTER_FLOW */ }
static void _greater_whirlwind_attack_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Greater Ambush"); break; case SPELL_DESC: var_set_string(res, "Perform a massive ambush on nearby monsters."); break; case SPELL_CAST: { int i, x, y; cave_type *c_ptr; monster_type *m_ptr; /* cba d218l e3@7k f456j ghi */ typedef struct _offset_t { int dx; int dy; } _offset; static _offset offsets[] = { { 0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, { 0, 1}, { 1, 1}, { 1, 0}, { 1, -1}, { 1, -2}, { 0, -2}, {-1, -2}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, 2}, { 0, 2}, { 1, 2}, { 2, 1}, { 2, 0}, { 2, -1}, { 0, 0}, /* sentinel */ }; for (i = 0;; i++) { _offset offset = offsets[i]; if (offset.dx == 0 && offset.dy == 0) break; y = py + offset.dy; x = px + offset.dx; if (!in_bounds(y, x)) continue; if (!projectable(py, px, y, x)) continue; c_ptr = &cave[y][x]; if (!c_ptr->m_idx) continue; m_ptr = &m_list[c_ptr->m_idx]; if (m_ptr->ml || cave_have_flag_bold(y, x, FF_PROJECT)) { int msec = delay_factor * delay_factor * delay_factor; if (panel_contains(y, x) && player_can_see_bold(y, x)) { char c = 0x30; byte a = TERM_WHITE; print_rel(c, a, y, x); move_cursor_relative(y, x); Term_fresh(); Term_xtra(TERM_XTRA_DELAY, msec); lite_spot(y, x); Term_fresh(); } else Term_xtra(TERM_XTRA_DELAY, msec); py_attack(y, x, 0); } } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }