/** * Make a new trap of the given type. Return TRUE if successful. * * We choose a player trap at random if the index is not legal. This means that * things which are not player traps must be picked by passing a valid index. * * This should be the only function that places traps in the dungeon * except the savefile loading code. */ void place_trap(struct chunk *c, int y, int x, int t_idx, int trap_level) { struct trap *new_trap; /* We've been called with an illegal index; choose a random trap */ if ((t_idx <= 0) || (t_idx >= z_info->trap_max)) { /* Require the correct terrain */ if (!square_player_trap_allowed(c, y, x)) return; t_idx = pick_trap(c->squares[y][x].feat, trap_level); } /* Failure */ if (t_idx < 0) return; /* Allocate a new trap for this grid (at the front of the list) */ new_trap = mem_zalloc(sizeof(*new_trap)); new_trap->next = c->squares[y][x].trap; c->squares[y][x].trap = new_trap; /* Set the details */ new_trap->t_idx = t_idx; new_trap->kind = &trap_info[t_idx]; new_trap->fy = y; new_trap->fx = x; trf_copy(new_trap->flags, trap_info[t_idx].flags); /* Toggle on the trap marker */ sqinfo_on(c->squares[y][x].info, SQUARE_TRAP); /* Redraw the grid */ square_light_spot(c, y, x); }
/* * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int py = p_ptr->py; int px = p_ptr->px; int y = py + ddy[dir]; int x = px + ddx[dir]; int m_idx = cave->m_idx[y][x]; /* Attack monsters */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(m_idx)) { become_aware(m_idx); /* Mimic wakes up */ mon_clear_timed(m_idx, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE); } else { py_attack(y, x); } } /* Optionally alter traps/doors on movement */ else if (disarm && (cave->info[y][x] & CAVE_MARK) && (cave_isknowntrap(cave, y, x) || cave_iscloseddoor(cave, y, x))) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } /* Cannot walk through walls */ else if (!cave_floor_bold(y, x)) { /* Disturb the player */ disturb(p_ptr, 0, 0); /* Notice unknown obstacles */ if (!(cave->info[y][x] & CAVE_MARK)) { /* Rubble */ if (cave->feat[y][x] == FEAT_RUBBLE) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } /* Closed door */ else if (cave->feat[y][x] < FEAT_SECRET) { msgt(MSG_HITWALL, "You feel a door blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } /* Wall (or secret door) */ else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); cave->info[y][x] |= (CAVE_MARK); cave_light_spot(cave, y, x); } } /* Mention known obstacles */ else { if (cave->feat[y][x] == FEAT_RUBBLE) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (cave->feat[y][x] < FEAT_SECRET) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } /* Normal movement */ else { /* See if trap detection status will change */ bool old_dtrap = ((cave->info2[py][px] & (CAVE2_DTRAP)) != 0); bool new_dtrap = ((cave->info2[y][x] & (CAVE2_DTRAP)) != 0); /* Note the change in the detect status */ if (old_dtrap != new_dtrap) p_ptr->redraw |= (PR_DTRAP); /* Disturb player if the player is about to leave the area */ if (OPT(disturb_detect) && p_ptr->running && !p_ptr->running_firststep && old_dtrap && !new_dtrap) { disturb(p_ptr, 0, 0); return; } /* Move player */ monster_swap(py, px, y, x); /* New location */ y = py = p_ptr->py; x = px = p_ptr->px; /* Searching */ if (p_ptr->searching || (p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] >= 50) || one_in_(50 - p_ptr->state.skills[SKILL_SEARCH_FREQUENCY])) search(FALSE); /* Handle "store doors" */ if ((cave->feat[p_ptr->py][p_ptr->px] >= FEAT_SHOP_HEAD) && (cave->feat[p_ptr->py][p_ptr->px] <= FEAT_SHOP_TAIL)) { /* Disturb */ disturb(p_ptr, 0, 0); cmd_insert(CMD_ENTER_STORE); } /* All other grids (including traps) */ else { /* Handle objects (later) */ p_ptr->notice |= (PN_PICKUP); } /* Discover invisible traps */ if (cave->feat[y][x] == FEAT_INVIS) { /* Disturb */ disturb(p_ptr, 0, 0); /* Message */ msg("You found a trap!"); /* Pick a trap */ pick_trap(y, x); /* Hit the trap */ hit_trap(y, x); } /* Set off an visible trap */ else if (cave_isknowntrap(cave, y, x)) { /* Disturb */ disturb(p_ptr, 0, 0); /* Hit the trap */ hit_trap(y, x); } } p_ptr->running_firststep = FALSE; }
/* * Search for hidden things. Returns true if a search was attempted, returns * false when the player has a 0% chance of finding anything. Prints messages * for negative confirmation when verbose mode is requested. */ bool search(bool verbose) { int py = p_ptr->py; int px = p_ptr->px; int y, x, chance; bool found = FALSE; object_type *o_ptr; /* Start with base search ability */ chance = p_ptr->state.skills[SKILL_SEARCH]; /* Penalize various conditions */ if (p_ptr->timed[TMD_BLIND] || no_light()) chance = chance / 10; if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) chance = chance / 10; /* Prevent fruitless searches */ if (chance <= 0) { if (verbose) { msg("You can't make out your surroundings well enough to search."); /* Cancel repeat */ disturb(p_ptr, 0, 0); } return FALSE; } /* Search the nearby grids, which are always in bounds */ for (y = (py - 1); y <= (py + 1); y++) { for (x = (px - 1); x <= (px + 1); x++) { /* Sometimes, notice things */ if (randint0(100) < chance) { /* Invisible trap */ if (cave->feat[y][x] == FEAT_INVIS) { found = TRUE; /* Pick a trap */ pick_trap(y, x); /* Message */ msg("You have found a trap."); /* Disturb */ disturb(p_ptr, 0, 0); } /* Secret door */ if (cave->feat[y][x] == FEAT_SECRET) { found = TRUE; /* Message */ msg("You have found a secret door."); /* Pick a door */ place_closed_door(cave, y, x); /* Disturb */ disturb(p_ptr, 0, 0); } /* Scan all objects in the grid */ for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr)) { /* Skip non-chests */ if (o_ptr->tval != TV_CHEST) continue; /* Skip disarmed chests */ if (o_ptr->pval[DEFAULT_PVAL] <= 0) continue; /* Skip non-trapped chests */ if (!chest_traps[o_ptr->pval[DEFAULT_PVAL]]) continue; /* Identify once */ if (!object_is_known(o_ptr)) { found = TRUE; /* Message */ msg("You have discovered a trap on the chest!"); /* Know the trap */ object_notice_everything(o_ptr); /* Notice it */ disturb(p_ptr, 0, 0); } } } } } if (verbose && !found) { if (chance >= 100) msg("There are no secrets here."); else msg("You found nothing."); } return TRUE; }
/** * Move player in the given direction, with the given "pickup" flag. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/etc. */ void move_player(int dir) { int py = p_ptr->py; int px = p_ptr->px; byte str_escape, dex_escape; /* Permit the player to move? */ bool can_move = FALSE; /* Player is jumping off a cliff */ bool falling = FALSE; /* Player hits a trap (always unless flying) */ bool trapped = TRUE; int temp; int y, x; /* Find the result of moving */ y = py + ddy[dir]; x = px + ddx[dir]; /* Hack -- attack monsters */ if (cave_m_idx[y][x] > 0) { /* Attack */ if (py_attack(y, x, TRUE)) return; } /* It takes some dexterity, or failing that strength, to get out of pits */ if (cave_feat[p_ptr->py][p_ptr->px] == (FEAT_TRAP_HEAD + 0x01)) { str_escape = adj_dex_dis[p_ptr->state.stat_ind[A_STR]]; dex_escape = adj_dex_dis[p_ptr->state.stat_ind[A_DEX]]; /* First attempt to leap out of the pit, */ if ((dex_escape + 1) * 2 < randint1(16)) { /* then attempt to climb out of the pit. */ if (str_escape + 3 < randint1(16)) { /* Failure costs a turn. */ msg_print("You remain stuck in the pit."); return; } else msg_print("You clamber out of the pit."); } else msg_print("You leap out of the pit."); } /* Option to disarm a visible trap. -TNB- */ /* Hack - Rogues can walk over their own trap - BR */ if (OPT(easy_alter) && (cave_feat[y][x] >= FEAT_TRAP_HEAD) && (cave_feat[y][x] <= FEAT_TRAP_TAIL)) { bool more = FALSE; /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); more = do_cmd_disarm_aux(y, x); /* Cancel repeat unless we may continue */ if (!more) disturb(0, 0); return; } /* Some terrain is impassable for the player, such as stone walls. */ else if (!cave_passable_bold(y, x)) { /* Disturb the player */ disturb(0, 0); /* Notice unknown obstacles */ if (!(cave_info[y][x] & (CAVE_MARK))) { /* Closed door */ if (cave_feat[y][x] < FEAT_SECRET) { message(MSG_HITWALL, 0, "You feel a door blocking your way."); cave_info[y][x] |= (CAVE_MARK); light_spot(y, x); } /* Wall (or secret door) */ else { message(MSG_HITWALL, 0, "You feel a wall blocking your way."); cave_info[y][x] |= (CAVE_MARK); light_spot(y, x); } } /* Mention known obstacles */ else { /* Closed door */ if (cave_feat[y][x] < FEAT_SECRET) { /* Option to automatically open doors. -TNB- */ if (OPT(easy_alter)) { bool more = FALSE; /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); /* Open the door */ more = do_cmd_open_aux(y, x); /* Cancel repeat unless we may continue */ if (!more) disturb(0, 0); return; } /* Otherwise, a message. */ message(MSG_HITWALL, 0, "There is a door blocking your way."); } /* Wall (or secret door) */ else { message(MSG_HITWALL, 0, "There is a wall blocking your way."); } } /* Sound */ sound(MSG_HITWALL); } /* Normal movement */ else { /*** Handle traversable terrain. ***/ switch (cave_feat[y][x]) { case FEAT_RUBBLE: { /* Dwarves move easily through rubble */ if (player_has(PF_DWARVEN)) can_move = TRUE; /* Bats, dragons can fly */ else if ((p_ptr->schange == SHAPE_BAT) || (p_ptr->schange == SHAPE_WYRM)) can_move = TRUE; else if (player_is_crossing == dir) { can_move = TRUE; player_is_crossing = 0; } else { player_is_crossing = dir; cmd_insert(CMD_WALK); } break; } case FEAT_TREE: case FEAT_TREE2: { /* Druids, rangers, elves and ents (SJGU) slip easily under * trees */ if (((player_has(PF_WOODSMAN)) || (player_has(PF_ELVEN))) || (player_has(PF_WOODEN))) can_move = TRUE; /* Bats, dragons can fly */ else if ((p_ptr->schange == SHAPE_BAT) || (p_ptr->schange == SHAPE_WYRM)) can_move = TRUE; /* Allow movement only if partway through already. */ else if (player_is_crossing == dir) { can_move = TRUE; player_is_crossing = 0; } else { player_is_crossing = dir; cmd_insert(CMD_WALK); } break; } case FEAT_WATER: /* Water now slows rather than stopping -NRM- */ { /* Stop any run. */ disturb(0, 0); can_move = TRUE; /* Speed will need updating */ p_ptr->update |= PU_BONUS; break; } case FEAT_LAVA: { /* Assume player will continue. */ temp = TRUE; /* Smart enough to stop running. */ if (p_ptr->running) { if (!get_check("Lava blocks your path. Step into it? ")) { temp = FALSE; p_ptr->running = 0; } } /* Smart enough to sense trouble. */ else if ((!p_resist_pos(P_RES_FIRE)) || (!p_resist_strong(P_RES_FIRE) && (p_ptr->chp <= 100)) || (!p_immune(P_RES_FIRE) && (p_ptr->chp <= 30))) { if (!get_check ("The heat of the lava scalds you! Really enter? ")) { temp = FALSE; } } /* Enter if OK or confirmed. */ if (temp) { /* Can always cross. */ can_move = TRUE; /* Feather fall makes one lightfooted. */ if (p_ptr->state.ffall) { notice_obj(OF_FEATHER, 0); temp = 49 + randint1(51); } else temp = 124 + randint1(126); /* Will take serious fire damage. */ fire_dam(temp, "burnt to a cinder in molten lava"); } break; } case FEAT_VOID: { /* Bats, dragons can fly */ if ((p_ptr->schange == SHAPE_BAT) || (p_ptr->schange == SHAPE_WYRM)) can_move = TRUE; else { /* Assume player will continue. */ temp = TRUE; /* Smart enough to stop running. */ if (p_ptr->running) { if (!get_check ("You have come to a cliff. Step off it? ")) { temp = FALSE; p_ptr->running = 0; } } /* Smart enough to sense trouble. */ else if (!p_ptr->timed[TMD_BLIND]) { if (!get_check("It's a cliff! Really step off it? ")) { temp = FALSE; } } /* Step off if confirmed. */ if (temp) { /* Can always jump. */ can_move = TRUE; /* Will take serious damage. */ falling = TRUE; } } break; } default: { /* All other terrain can be traversed normally. */ can_move = TRUE; } } /* If the player can move, handle various things. */ if (can_move) { /* Move player */ monster_swap(py, px, y, x); /* Update speed if stepping out of water */ if (cave_feat[py][px] == FEAT_WATER) p_ptr->update |= PU_BONUS; /* Update stealth for Unlight */ if (player_has(PF_UNLIGHT)) p_ptr->update |= PU_BONUS; /* Superstealth for ents in trees SJGU */ if ((player_has(PF_WOODEN)) && (tf_has (f_info[cave_feat[p_ptr->py][p_ptr->px]].flags, TF_TREE))) { if (!(tf_has(f_info[cave_feat[py][px]].flags, TF_TREE)) || !(p_ptr->timed[TMD_SSTEALTH])) { (void) inc_timed(TMD_SSTEALTH, 1, FALSE); p_ptr->update |= (PU_BONUS); } } else if ((player_has(PF_WOODEN)) && (tf_has(f_info[cave_feat[py][px]].flags, TF_TREE))) { if (p_ptr->timed[TMD_SSTEALTH]) { (void) dec_timed(TMD_SSTEALTH, 1, FALSE); p_ptr->update |= (PU_BONUS); } } /* New location */ y = py = p_ptr->py; x = px = p_ptr->px; /* No longer traversing. */ player_is_crossing = 0; /* Fall off a cliff */ if (falling) fall_off_cliff(); /* Spontaneous Searching */ if (p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] > 49) { (void) search(FALSE); } else if (0 == randint0(50 - p_ptr->state.skills[SKILL_SEARCH_FREQUENCY])) { (void) search(FALSE); } /* Continuous Searching */ if (p_ptr->searching) { (void) search(FALSE); } /* Handle "store doors" */ if ((cave_feat[y][x] >= FEAT_SHOP_HEAD) && (cave_feat[y][x] <= FEAT_SHOP_TAIL)) { /* Disturb */ disturb(0, 0); cmd_insert(CMD_ENTER_STORE); } /* All other grids (including traps) */ else { /* Handle objects (later) */ p_ptr->notice |= (PN_PICKUP); } /* Flying players have a chance to miss traps */ if ((p_ptr->schange == SHAPE_BAT) || (p_ptr->schange == SHAPE_WYRM)) { if (((cave_feat[y][x] == FEAT_INVIS) || (cave_feat[y][x] == FEAT_GRASS_INVIS)) && (randint0(3) != 0)) trapped = FALSE; else if ((cave_feat[y][x] >= FEAT_TRAP_HEAD) && (cave_feat[y][x] <= FEAT_TRAP_TAIL) && (randint0(10) != 0)) trapped = FALSE; } /* Discover invisible traps */ else if (((cave_feat[y][x] == FEAT_INVIS) || (cave_feat[y][x] == FEAT_GRASS_INVIS) || (cave_feat[y][x] == FEAT_TREE_INVIS) || (cave_feat[y][x] == FEAT_TREE2_INVIS)) && trapped) { /* Disturb */ disturb(0, 0); /* Message */ msg_print("You stumble upon a trap!"); /* Pick a trap */ pick_trap(y, x); /* Hit the floor trap. */ hit_trap(y, x); } /* Set off a visible trap */ else if ((cave_feat[y][x] >= FEAT_TRAP_HEAD) && (cave_feat[y][x] <= FEAT_TRAP_TAIL) && trapped) { /* Disturb */ disturb(0, 0); /* Hit the floor trap. */ hit_trap(y, x); } /* Walk on a monster trap */ else if ((cave_feat[y][x] >= FEAT_MTRAP_HEAD) && (cave_feat[y][x] <= FEAT_MTRAP_TAIL)) { msg_print("You inspect your cunning trap."); } } } }
/* * 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); } } }