/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* Oops. We've walked right into trouble. */ if (num == 1) msg("You stumble upon a trap!"); else if (num > 1) msg("You stumble upon some traps!"); /* Look at the traps in this grid */ for (trap = cave->squares[y][x].trap; trap; trap = trap->next) { /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; /* Disturb the player */ disturb(player, 0); /* Fire off the trap */ effect = trap->kind->effect; effect_do(effect, &ident, FALSE, 0, 0, 0); /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); sqinfo_on(cave->squares[y][x].info, SQUARE_MARK); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 0); }
/* * Handle player hitting a real trap */ void hit_trap(int y, int x) { bool ident; struct feature *trap = &f_info[cave->feat[y][x]]; /* Disturb the player */ disturb(p_ptr, 0, 0); /* Run the effect */ effect_do(trap->effect, &ident, FALSE, 0, 0, 0); }
/** * Process a monster spell * * \param index is the monster spell flag (RSF_FOO) * \param mon is the attacking monster * \param seen is whether the player can see the monster at this moment */ void do_mon_spell(int index, struct monster *mon, bool seen) { char m_name[80]; bool ident, hits = FALSE; /* Extract the monster level */ int rlev = ((mon->race->level >= 1) ? mon->race->level : 1); const struct monster_spell *spell = monster_spell_by_index(index); /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD); /* See if it hits */ if (spell->hit == 100) hits = TRUE; else if (spell->hit == 0) hits = FALSE; else hits = check_hit(player, spell->hit, rlev); /* Tell the player what's going on */ disturb(player, 1); spell_message(mon, spell, seen, hits); if (!hits) return; /* Try a saving throw if available */ if (spell->save_message && randint0(100) < player->state.skills[SKILL_SAVE]) { msg("%s", spell->save_message); return; } /* Do effects */ effect_do(spell->effect, NULL, &ident, TRUE, 0, 0, 0); return; }
/* * Use an object the right way. * * There may be a BIG problem with any "effect" that can cause "changes" * to the inventory. For example, a "scroll of recharging" can cause * a wand/staff to "disappear", moving the inventory up. Luckily, the * scrolls all appear BEFORE the staffs/wands, so this is not a problem. * But, for example, a "staff of recharging" could cause MAJOR problems. * In such a case, it will be best to either (1) "postpone" the effect * until the end of the function, or (2) "change" the effect, say, into * giving a staff "negative" charges, or "turning a staff into a stick". * It seems as though a "rod of recharging" might in fact cause problems. * The basic problem is that the act of recharging (and destroying) an * item causes the inducer of that action to "move", causing "o_ptr" to * no longer point at the correct item, with horrifying results. */ void do_cmd_use(cmd_code code, cmd_arg args[]) { int item = args[0].item; object_type *o_ptr = object_from_item_idx(item); int effect; bool ident = FALSE, used = FALSE; bool was_aware = object_flavor_is_aware(o_ptr); int dir = 5; int px = p_ptr->px, py = p_ptr->py; int snd, boost, level; use_type use; int items_allowed = 0; /* Determine how this item is used. */ if (obj_is_rod(o_ptr)) { if (!obj_can_zap(o_ptr)) { msg("That rod is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_wand(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That wand has no charges."); return; } use = USE_CHARGE; snd = MSG_ZAP_ROD; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_staff(o_ptr)) { if (!obj_has_charges(o_ptr)) { msg("That staff has no charges."); return; } use = USE_CHARGE; snd = MSG_USE_STAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_food(o_ptr)) { use = USE_SINGLE; snd = MSG_EAT; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_potion(o_ptr)) { use = USE_SINGLE; snd = MSG_QUAFF; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_scroll(o_ptr)) { /* Check player can use scroll */ if (!player_can_read()) return; use = USE_SINGLE; snd = MSG_GENERIC; items_allowed = USE_INVEN | USE_FLOOR; } else if (obj_is_activatable(o_ptr)) { if (!obj_can_activate(o_ptr)) { msg("That item is still charging."); return; } use = USE_TIMEOUT; snd = MSG_ACT_ARTIFACT; items_allowed = USE_EQUIP; } else { msg("The item cannot be used at the moment"); } /* Check if item is within player's reach. */ if (items_allowed == 0 || !item_is_available(item, NULL, items_allowed)) { msg("You cannot use that item from its current location."); return; } /* track the object used */ track_object(item); /* Figure out effect to use */ effect = object_effect(o_ptr); /* If the item requires a direction, get one (allow cancelling) */ if (obj_needs_aim(o_ptr)) dir = args[1].direction; /* Check for use if necessary, and execute the effect */ if ((use != USE_CHARGE && use != USE_TIMEOUT) || check_devices(o_ptr)) { int beam = beam_chance(o_ptr->tval); /* Special message for artifacts */ if (o_ptr->artifact) { msgt(snd, "You activate it."); if (o_ptr->artifact->effect_msg) activation_message(o_ptr, o_ptr->artifact->effect_msg); level = o_ptr->artifact->level; } else { /* Make a noise! */ sound(snd); level = o_ptr->kind->level; } /* A bit of a hack to make ID work better. -- Check for "obvious" effects beforehand. */ if (effect_obvious(effect)) object_flavor_aware(o_ptr); /* Boost damage effects if skill > difficulty */ boost = MAX(p_ptr->state.skills[SKILL_DEVICE] - level, 0); /* Do effect */ used = effect_do(effect, &ident, was_aware, dir, beam, boost); /* Quit if the item wasn't used and no knowledge was gained */ if (!used && (was_aware || !ident)) return; } /* If the item is a null pointer or has been wiped, be done now */ if (!o_ptr || !o_ptr->kind) return; if (ident) object_notice_effect(o_ptr); /* Food feeds the player */ if (o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION) (void)set_food(p_ptr->food + o_ptr->pval[DEFAULT_PVAL]); /* Use the turn */ p_ptr->energy_use = 100; /* Mark as tried and redisplay */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); p_ptr->redraw |= (PR_INVEN | PR_EQUIP | PR_OBJECT); /* * If the player becomes aware of the item's function, then mark it as * aware and reward the player with some experience. Otherwise, mark * it as "tried". */ if (ident && !was_aware) { /* Object level */ int lev = o_ptr->kind->level; object_flavor_aware(o_ptr); if (o_ptr->tval == TV_ROD) object_notice_everything(o_ptr); player_exp_gain(p_ptr, (lev + (p_ptr->lev / 2)) / p_ptr->lev); p_ptr->notice |= PN_SQUELCH; } else if (used) { object_flavor_tried(o_ptr); } /* If there are no more of the item left, then we're done. */ if (!o_ptr->number) return; /* Chargeables act differently to single-used items when not used up */ if (used && use == USE_CHARGE) { /* Use a single charge */ o_ptr->pval[DEFAULT_PVAL]--; /* Describe charges */ if (item >= 0) inven_item_charges(item); else floor_item_charges(0 - item); } else if (used && use == USE_TIMEOUT) { /* Artifacts use their own special field */ if (o_ptr->artifact) o_ptr->timeout = randcalc(o_ptr->artifact->time, 0, RANDOMISE); else o_ptr->timeout += randcalc(o_ptr->kind->time, 0, RANDOMISE); } else if (used && use == USE_SINGLE) { /* Destroy a potion in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a potion on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } } /* Hack to make Glyph of Warding work properly */ if (cave->feat[py][px] == FEAT_GLYPH) { /* Push objects off the grid */ if (cave->o_idx[py][px]) push_object(py, px); } }
/** * Hit a trap. */ extern void hit_trap(int y, int x) { bool ident = false; struct trap *trap; struct effect *effect; /* Count the hidden traps here */ int num = num_traps(cave, y, x, -1); /* The player is safe from all traps */ if (player_is_trapsafe(player)) return; /* Oops. We've walked right into trouble. */ if (num == 1) msg("You stumble upon a trap!"); else if (num > 1) msg("You stumble upon some traps!"); /* Look at the traps in this grid */ for (trap = square_trap(cave, y, x); trap; trap = trap->next) { int flag; bool saved = false; /* Require that trap be capable of affecting the character */ if (!trf_has(trap->kind->flags, TRF_TRAP)) continue; if (trap->timeout) continue; /* Disturb the player */ disturb(player, 0); /* Give a message */ if (trap->kind->msg) msg(trap->kind->msg); /* Test for save due to flag */ for (flag = of_next(trap->kind->save_flags, FLAG_START); flag != FLAG_END; flag = of_next(trap->kind->save_flags, flag + 1)) if (player_of_has(player, flag)) { saved = true; equip_learn_flag(player, flag); } /* Test for save due to armor */ if (trf_has(trap->kind->flags, TRF_SAVE_ARMOR) && !trap_check_hit(125)) saved = true; /* Test for save due to saving throw */ if (trf_has(trap->kind->flags, TRF_SAVE_THROW) && (randint0(100) < player->state.skills[SKILL_SAVE])) saved = true; /* Save, or fire off the trap */ if (saved) { if (trap->kind->msg_good) msg(trap->kind->msg_good); } else { if (trap->kind->msg_bad) msg(trap->kind->msg_bad); effect = trap->kind->effect; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); /* Do any extra effects */ if (trap->kind->effect_xtra && one_in_(2)) { if (trap->kind->msg_xtra) msg(trap->kind->msg_xtra); effect = trap->kind->effect_xtra; effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0); } } /* Some traps drop you a dungeon level */ if (trf_has(trap->kind->flags, TRF_DOWN)) dungeon_change_level(player, dungeon_get_next_level(player->depth, 1)); /* Some traps drop you onto them */ if (trf_has(trap->kind->flags, TRF_PIT)) monster_swap(player->py, player->px, trap->fy, trap->fx); /* Some traps disappear after activating, all have a chance to */ if (trf_has(trap->kind->flags, TRF_ONETIME) || one_in_(3)) { square_destroy_trap(cave, y, x); square_forget(cave, y, x); } /* Trap may have gone */ if (!square_trap(cave, y, x)) break; /* Trap becomes visible (always XXX) */ trf_on(trap->flags, TRF_VISIBLE); square_memorize(cave, y, x); } /* Verify traps (remove marker if appropriate) */ (void)square_verify_trap(cave, y, x, 0); }