static void _excavation_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Excavation"); break; case SPELL_DESC: var_set_string(res, "You break walls on your quest for treasure! This takes a bit more time, though."); break; case SPELL_ENERGY: { int n = 200; if (equip_find_object(TV_DIGGING, SV_ANY)) n -= 120 * p_ptr->lev / 50; else n -= 80 * p_ptr->lev / 50; var_set_int(res, n); } break; case SPELL_CAST: { int dir = 5; bool b = FALSE; if ( get_rep_dir2(&dir) && dir != 5 ) { int x, y; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) { msg_print("You may excavate no further."); } else if ( cave_have_flag_bold(y, x, FF_WALL) || cave_have_flag_bold(y, x, FF_TREE) || cave_have_flag_bold(y, x, FF_CAN_DIG) ) { msg_print("You dig your way to treasure!"); cave_alter_feat(y, x, FF_TUNNEL); teleport_player_to(y, x, TELEPORT_NONMAGICAL); /*??*/ b = TRUE; } else { msg_print("There is nothing to excavate."); } } var_set_bool(res, b); } break; default: default_spell(cmd, res); break; } }
static void _cavern_creation_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Cavern Creation"); break; case SPELL_DESC: var_set_string(res, "Stone to Mud all surrounding walls."); break; case SPELL_CAST: { int dir, x, y, ct = 0; for (dir = 0; dir < 8; dir++) { y = py + ddy_ddd[dir]; x = px + ddx_ddd[dir]; if (!in_bounds(y, x)) continue; if (!cave_have_flag_bold(y, x, FF_HURT_ROCK)) continue; cave_alter_feat(y, x, FF_HURT_ROCK); ct++; } if (ct) p_ptr->update |= (PU_FLOW | PU_BONUS); var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
static void _smash_wall_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Smash"); break; case SPELL_DESC: var_set_string(res, "Destroys adjacent targeted wall, door, tree, or trap."); break; case SPELL_CAST: { int y, x, dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) return; if (cave_have_flag_bold(y, x, FF_HURT_ROCK)) { cave_alter_feat(y, x, FF_HURT_ROCK); p_ptr->update |= PU_FLOW; } else if (cave_have_flag_bold(y, x, FF_TREE)) { cave_set_feat(y, x, one_in_(3) ? feat_brake : feat_grass); } else { int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_HIDE; project(0, 0, y, x, 0, GF_KILL_DOOR, flg, -1); } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
static bool _create_shots(void) { int x, y, dir, slot; cave_type *c_ptr; object_type forge; if (!get_rep_dir(&dir, FALSE)) return FALSE; y = py + ddy[dir]; x = px + ddx[dir]; c_ptr = &cave[y][x]; if (!have_flag(f_info[get_feat_mimic(c_ptr)].flags, FF_CAN_DIG)) { msg_print("You need pile of rubble."); return FALSE; } if (!cave_have_flag_grid(c_ptr, FF_CAN_DIG) || !cave_have_flag_grid(c_ptr, FF_HURT_ROCK)) { msg_print("You failed to make ammo."); return FALSE; } object_prep(&forge, lookup_kind(TV_SHOT, m_bonus(1, p_ptr->lev) + 1)); forge.number = (byte)rand_range(15,30); apply_magic(&forge, p_ptr->lev, AM_NO_FIXED_ART); obj_identify(&forge); forge.discount = 99; msg_print("You make some ammo."); slot = inven_carry(&forge); if (slot >= 0) autopick_alter_item(slot, FALSE); cave_alter_feat(y, x, FF_HURT_ROCK); p_ptr->update |= PU_FLOW; return TRUE; }
static void _stone_smash_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Stone Smash"); break; case SPELL_DESC: var_set_string(res, "Destroys adjacent targeted wall."); break; case SPELL_CAST: { int y, x, dir; var_set_bool(res, FALSE); if (!get_rep_dir2(&dir)) return; if (dir == 5) return; y = py + ddy[dir]; x = px + ddx[dir]; if (!in_bounds(y, x)) return; if (cave_have_flag_bold(y, x, FF_HURT_ROCK)) { cave_alter_feat(y, x, FF_HURT_ROCK); p_ptr->update |= PU_FLOW; } var_set_bool(res, TRUE); break; } default: default_spell(cmd, res); break; } }
/* * Handle monster hitting a real trap. */ void mon_hit_trap(int m_idx, int y, int x) { feature_type *f_ptr; monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int feat = cave_feat[y][x]; bool fear; /* Option */ if (!variant_hit_traps) return; /* Hack --- don't activate unknown invisible traps */ if (cave_feat[y][x] == FEAT_INVIS) return; /* Get feature */ f_ptr = &f_info[cave_feat[y][x]]; /* Hack --- trapped doors */ /* XXX XXX Dangerous */ while (!(f_ptr->spell) && !(f_ptr->blow.method) && (f_ptr->flags1 & (FF1_TRAP))) { pick_trap(y,x); /* Error */ if (cave_feat[y][x] == feat) break; feat = cave_feat[y][x]; /* Get feature */ f_ptr = &f_info[feat]; } /* Use covered or bridged if necessary */ if ((f_ptr->flags2 & (FF2_COVERED)) || (f_ptr->flags2 & (FF2_BRIDGED))) { f_ptr = &f_info[f_ptr->mimic]; } /* Hack -- monster falls onto trap */ if ((m_ptr->fy!=y)|| (m_ptr->fx !=x)) { /* Move monster */ monster_swap(m_ptr->fy, m_ptr->fx, y, x); } /* Apply the object */ if ((cave_o_idx[y][x]) && (f_ptr->flags1 & (FF1_HIT_TRAP))) { object_type *o_ptr = &o_list[cave_o_idx[y][x]]; char o_name[80]; int power = 0; switch (o_ptr->tval) { case TV_BOW: { object_type *j_ptr; u32b f1,f2,f3; int i, shots = 1; /* Get bow */ j_ptr = o_ptr; /* Get bow flags */ object_flags(o_ptr,&f1,&f2,&f3); /* Apply extra shots */ if (f1 & (TR1_SHOTS)) shots += j_ptr->pval; /* Test for hit */ for (i = 0; i < shots; i++) { if (j_ptr->next_o_idx) { int ammo = j_ptr->next_o_idx; object_type *i_ptr; object_type object_type_body; /* Use ammo instead of bow */ o_ptr = &o_list[ammo]; /* Describe ammo */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0); if ((ammo) && (test_hit_fire((j_ptr->to_h + o_ptr->to_h)* BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac * (r_ptr->flags2 & (RF2_ARMOR) ? 2 : 1), TRUE))) { int k, mult; switch (j_ptr->sval) { case SV_SLING: case SV_SHORT_BOW: mult = 2; break; case SV_LONG_BOW: case SV_LIGHT_XBOW: mult = 3; break; case SV_HEAVY_XBOW: mult = 4; break; default: mult = 1; break; } /* Apply extra might */ if (f1 & (TR1_MIGHT)) mult += j_ptr->pval; k = damroll(o_ptr->dd, o_ptr->ds); k *= mult; k = tot_dam_aux(o_ptr, k, m_ptr); k = critical_shot(o_ptr->weight, o_ptr->to_h + j_ptr->to_h, k); k += o_ptr->to_d + j_ptr->to_d; /* No negative damage */ if (k < 0) k = 0; /* Trap description */ msg_format("%^s hits you.",o_name); /* Damage, check for fear and death */ (void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL); } else { /* Trap description */ msg_format("%^s narrowly misses you.",o_name); } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Drop nearby - some chance of breakage */ drop_near(i_ptr,y,x,breakage_chance(i_ptr)); /* Decrease the item */ floor_item_increase(ammo, -1); floor_item_optimize(ammo); break; } else { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); } } } case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_HAFTED: case TV_SWORD: case TV_POLEARM: { object_type *i_ptr; object_type object_type_body; /* Describe ammo */ object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0); /* Test for hit */ if (test_hit_norm(o_ptr->to_h * BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac, TRUE)) { int k; k = damroll(o_ptr->dd, o_ptr->ds); k = tot_dam_aux(o_ptr, k, m_ptr); k = critical_norm(o_ptr->weight, o_ptr->to_h, k); k += o_ptr->to_d; /* Armour reduces total damage */ k -= (k * ((p_ptr->ac < 150) ? p_ptr->ac : 150) / 250); /* No negative damage */ if (k < 0) k = 0; /* Trap description */ msg_format("%^s hits you.",o_name); /* Damage, check for fear and death */ (void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL); } else { /* Trap description */ msg_format("%^s narrowly misses you.",o_name); } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Drop nearby - some chance of breakage */ drop_near(i_ptr,y,x,breakage_chance(i_ptr)); /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); break; } case TV_WAND: case TV_STAFF: { if (o_ptr->pval > 0) { /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* XXX Hack -- new unstacking code */ o_ptr->stackc++; /* No spare charges */ if (o_ptr->stackc >= o_ptr->number) { /* Use a charge off the stack */ o_ptr->pval--; /* Reset the stack count */ o_ptr->stackc = 0; } /* XXX Hack -- unstack if necessary */ if ((o_ptr->number > 1) && ((!variant_pval_stacks) || ((!object_known_p(o_ptr) && (o_ptr->pval == 2) && (o_ptr->stackc > 1)) || (!object_known_p(o_ptr) && (rand_int(o_ptr->number) <= o_ptr->stackc) && (o_ptr->stackc != 1) && (o_ptr->pval > 2))))) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Reset stack counter */ i_ptr->stackc = 0; /* Unstack the used item */ o_ptr->number--; /* Reduce the charges on the new item */ if (o_ptr->stackc > 1) { i_ptr->pval-=2; o_ptr->stackc--; } else if (!o_ptr->stackc) { i_ptr->pval--; o_ptr->pval++; o_ptr->stackc = o_ptr->number-1; } (void)floor_carry(y,x,i_ptr); } } else { /* Disarm if runs out */ cave_alter_feat(y,x,FS_DISARM); } break; } case TV_ROD: case TV_DRAG_ARMOR: { if (!((o_ptr->timeout) && ((!o_ptr->stackc) || (o_ptr->stackc >= o_ptr->number)))) { int tmpval; /* Store pval */ tmpval = o_ptr->timeout; /* Time rod out */ o_ptr->timeout = o_ptr->pval; /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* Has a power */ /* Hack -- check if we are stacking rods */ if ((o_ptr->timeout > 0) && (!(tmpval) || stack_force_times)) { /* Hack -- one more rod charging */ if (o_ptr->timeout) o_ptr->stackc++; /* Reset stack count */ if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0; /* Hack -- always use maximum timeout */ if (tmpval > o_ptr->timeout) o_ptr->timeout = tmpval; } /* XXX Hack -- unstack if necessary */ if ((o_ptr->number > 1) && (o_ptr->timeout > 0)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Clear stack counter */ i_ptr->stackc = 0; /* Restore "charge" */ o_ptr->timeout = tmpval; /* Unstack the used item */ o_ptr->number--; /* Reset the stack if required */ if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0; (void)floor_carry(y,x,i_ptr); } } break; } case TV_POTION: case TV_SCROLL: case TV_FLASK: case TV_FOOD: { /* Hack -- boring food */ if ((o_ptr->tval == TV_FOOD) && (o_ptr->sval >= SV_FOOD_MIN_FOOD)) { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); } else { /* Get item effect */ get_spell(&power, "use", o_ptr, FALSE); /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); } break; } case TV_RUNESTONE: { u32b runes = p_ptr->cur_runes; int num = 0; s16b book[26]; /* Hack -- use current rune */ p_ptr->cur_runes = (2 << (o_ptr->sval-1)); /* Fill the book with spells */ fill_book(o_ptr,book,&num); /* Unhack */ p_ptr->cur_runes = runes; /* Get a power */ power = book[rand_int(num)]; /* Decrease the item */ floor_item_increase(cave_o_idx[y][x], -1); floor_item_optimize(cave_o_idx[y][x]); /* Disarm if runs out */ if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM); break; } default: { /* Disarm */ cave_alter_feat(y,x,FS_DISARM); break; } } /* Has a power */ if (power > 0) { spell_type *s_ptr = &s_info[power]; int ap_cnt; /* Object is used */ if (k_info[o_ptr->k_idx].used < MAX_SHORT) k_info[o_ptr->k_idx].used++; /* Scan through all four blows */ for (ap_cnt = 0; ap_cnt < 4; ap_cnt++) { int damage = 0; /* Extract the attack infomation */ int effect = s_ptr->blow[ap_cnt].effect; int method = s_ptr->blow[ap_cnt].method; int d_dice = s_ptr->blow[ap_cnt].d_dice; int d_side = s_ptr->blow[ap_cnt].d_side; int d_plus = s_ptr->blow[ap_cnt].d_plus; /* Hack -- no more attacks */ if (!method) break; /* Mega hack -- dispel evil/undead objects */ if (!d_side) { d_plus += 25 * d_dice; } /* Roll out the damage */ if ((d_dice) && (d_side)) { damage = damroll(d_dice, d_side) + d_plus; } else { damage = d_plus; } (void)project_m(0,0,y,x,damage, effect); (void)project_f(0,0,y,x,damage, effect); } } } /* Regular traps */ else { if (f_ptr->spell) { make_attack_spell_aux(0,y,x,f_ptr->spell); } else if (f_ptr->blow.method) { int damage = damroll(f_ptr->blow.d_side,f_ptr->blow.d_dice); /* Apply the blow */ project_m(0, 0, y, x, damage, f_ptr->blow.effect); } /* Get feature */ f_ptr = &f_info[cave_feat[p_ptr->py][p_ptr->px]]; if (f_ptr->flags1 & (FF1_HIT_TRAP)) { /* Modify the location hit by the trap */ cave_alter_feat(y,x,FS_HIT_TRAP); } else if (f_ptr->flags1 & (FF1_SECRET)) { /* Discover */ cave_alter_feat(y,x,FS_SECRET); } } }
/* * Places "streamers" of rock through dungeon * * Note that their are actually six different terrain features used * to represent streamers. Three each of magma and quartz, one for * basic vein, one with hidden gold, and one with known gold. The * hidden gold types are currently unused. */ void build_streamer(int feat, int chance) { int i, tx, ty; int y, x, dir; int dummy = 0; cave_type *c_ptr; feature_type *f_ptr; feature_type *streamer_ptr = &f_info[feat]; bool streamer_is_wall = have_flag(streamer_ptr->flags, FF_WALL) && !have_flag(streamer_ptr->flags, FF_PERMANENT); bool streamer_may_have_gold = have_flag(streamer_ptr->flags, FF_MAY_HAVE_GOLD); /* Hack -- Choose starting point */ y = rand_spread(cur_hgt / 2, cur_hgt / 6); x = rand_spread(cur_wid / 2, cur_wid / 6); /* Choose a random compass direction */ dir = ddd[randint0(8)]; /* Place streamer into dungeon */ while (dummy < SAFE_MAX_ATTEMPTS) { dummy++; /* One grid per density */ for (i = 0; i < DUN_STR_DEN; i++) { int d = DUN_STR_RNG; /* Pick a nearby grid */ while (1) { ty = rand_spread(y, d); tx = rand_spread(x, d); if (!in_bounds2(ty, tx)) continue; break; } /* Access the grid */ c_ptr = &cave[ty][tx]; f_ptr = &f_info[c_ptr->feat]; if (have_flag(f_ptr->flags, FF_MOVE) && (have_flag(f_ptr->flags, FF_WATER) || have_flag(f_ptr->flags, FF_LAVA))) continue; /* Do not convert permanent features */ if (have_flag(f_ptr->flags, FF_PERMANENT)) continue; /* Only convert "granite" walls */ if (streamer_is_wall) { if (!is_extra_grid(c_ptr) && !is_inner_grid(c_ptr) && !is_outer_grid(c_ptr) && !is_solid_grid(c_ptr)) continue; if (is_closed_door(c_ptr->feat)) continue; } if (c_ptr->m_idx && !(have_flag(streamer_ptr->flags, FF_PLACE) && monster_can_cross_terrain(feat, &r_info[m_list[c_ptr->m_idx].r_idx], 0))) { /* Delete the monster (if any) */ delete_monster(ty, tx); } if (c_ptr->o_idx && !have_flag(streamer_ptr->flags, FF_DROP)) { s16b this_o_idx, next_o_idx = 0; /* Scan all objects in the grid */ for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) { /* Acquire object */ object_type *o_ptr = &o_list[this_o_idx]; /* Acquire next object */ next_o_idx = o_ptr->next_o_idx; /* Hack -- Preserve unknown artifacts */ if (object_is_fixed_artifact(o_ptr)) { /* Mega-Hack -- Preserve the artifact */ a_info[o_ptr->name1].cur_num = 0; if (cheat_peek) { char o_name[MAX_NLEN]; object_desc(o_name, o_ptr, (OD_NAME_ONLY | OD_STORE)); msg_format("Artifact (%s) was deleted by streamer.", o_name); } } else if (o_ptr->name3) { /* Mega-Hack -- Preserve the artifact */ a_info[o_ptr->name3].cur_num = 0; if (cheat_peek) { char o_name[MAX_NLEN]; object_desc(o_name, o_ptr, (OD_NAME_ONLY | OD_STORE)); msg_format("Artifact (%s) was deleted by streamer.", o_name); } } else if (cheat_peek && o_ptr->art_name) { msg_print("One of the random artifacts was deleted by streamer."); } } /* Delete objects */ delete_object(ty, tx); } /* Clear previous contents, add proper vein type */ c_ptr->feat = feat; /* Paranoia: Clear mimic field */ c_ptr->mimic = 0; if (streamer_may_have_gold) { /* Hack -- Add some known treasure */ if (one_in_(chance)) { cave_alter_feat(ty, tx, FF_MAY_HAVE_GOLD); } /* Hack -- Add some hidden treasure */ else if (one_in_(chance / 4)) { cave_alter_feat(ty, tx, FF_MAY_HAVE_GOLD); cave_alter_feat(ty, tx, FF_ENSECRET); } } } if (dummy >= SAFE_MAX_ATTEMPTS) { if (cheat_room) { msg_print("Warning! Could not place streamer!"); } return; } /* Advance the streamer */ y += ddy[dir]; x += ddx[dir]; /* Quit before leaving the dungeon */ if (!in_bounds(y, x)) break; } }