/src/spells2.c
C | 5718 lines | 3076 code | 1215 blank | 1427 comment | 827 complexity | 6d694e94c9c09f28d257dafde9823057 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /** \file spells2.c
- \brief Spells
- * Healing spells, glyphs of warding, reducing or sustaining a stat, ID
- * everything, chance for enchant spells to fail, remove curses, regain
- * exp, detection spells, create stairs. Definitions of armour & weapons,
- * enchantment, branding, temporary branding, cursing, and ID code, what
- * items are rechargable and the recharging code. Various special object
- * spells. Spells that effect an area or LOS, lighten & darken rooms and
- * areas, casting ball, projection, beam, and bolt spells. Some miscel-
- * lanious non-damage spell functions.
- *
- * Copyright (c) 2009 Nick McConnell, Leon Marrick & Bahman Rabii,
- * Ben Harrison, James E. Wilson, Robert A. Koeneke
- *
- * This work is free software; you can redistribute it and/or modify it
- * under the terms of either:
- *
- * a) the GNU General Public License as published by the Free Software
- * Foundation, version 2, or
- *
- * b) the "Angband licence":
- * This software may be copied and distributed for educational, research,
- * and not for profit purposes provided that this copyright and statement
- * are included in all such copies. Other copyrights may also apply.
- */
- #include "angband.h"
- #include "cave.h"
- #include "history.h"
- #include "generate.h"
- #include "monster.h"
- #include "player.h"
- #include "spells.h"
- #include "squelch.h"
- #include "target.h"
- #include "trap.h"
- #include "ui-menu.h"
- /* Element to be proofed against in element-proofing */
- static bitflag el_to_proof[OF_SIZE];
- /**
- * Alter player's shape. Taken from Sangband.
- */
- void shapechange(s16b shape)
- {
- char *shapedesc = "";
- bool landing = FALSE;
- /* Were we flying? */
- landing = ((p_ptr->schange == SHAPE_BAT)
- || (p_ptr->schange == SHAPE_WYRM));
- /* Wonder Twin powers -- Activate! */
- p_ptr->schange = (byte) shape;
- p_ptr->update |= PU_BONUS;
- switch (shape) {
- case SHAPE_MOUSE:
- shapedesc = "mouse";
- break;
- case SHAPE_FERRET:
- shapedesc = "ferret";
- break;
- case SHAPE_HOUND:
- shapedesc = "hound";
- break;
- case SHAPE_GAZELLE:
- shapedesc = "gazelle";
- break;
- case SHAPE_LION:
- shapedesc = "lion";
- break;
- case SHAPE_ENT:
- shapedesc = "elder ent";
- break;
- case SHAPE_BAT:
- shapedesc = "bat";
- break;
- case SHAPE_WEREWOLF:
- shapedesc = "werewolf";
- break;
- case SHAPE_VAMPIRE:
- if ((chunk_list[p_ptr->stage].z_pos == 0)
- && ((turn % (10L * TOWN_DAWN)) < ((10L * TOWN_DAWN) / 2))) {
- msg("The sunlight prevents your shapechange!");
- shape = SHAPE_NORMAL;
- p_ptr->schange = (byte) shape;
- break;
- }
- shapedesc = "vampire";
- break;
- case SHAPE_WYRM:
- shapedesc = "dragon";
- break;
- case SHAPE_BEAR:
- shapedesc = "bear";
- break;
- default:
- msg("You return to your normal form.");
- break;
- }
- if (shape) {
- msg("You assume the form of a %s.", shapedesc);
- msg("Your equipment merges into your body.");
- }
- /* Recalculate mana. */
- p_ptr->update |= (PU_MANA);
- /* Show or hide shapechange on main window. */
- p_ptr->redraw |= (PR_SHAPE);
- if (landing) {
- int y = p_ptr->py, x = p_ptr->px;
- feature_type *f_ptr = &f_info[cave_feat[y][x]];
- if (tf_has(f_ptr->flags, TF_FALL))
- fall_off_cliff(0);
- else if (cave_invisible_trap(y, x)) {
- /* Disturb */
- disturb(0, 0);
- /* Hit the trap. */
- hit_trap(y, x);
- }
- /* Set off a visible trap */
- else if (cave_visible_trap(y, x)) {
- /* Disturb */
- disturb(0, 0);
- /* Hit the floor trap. */
- hit_trap(y, x);
- }
- }
- }
- /**
- * Type for choosing an elemental attack
- */
- typedef struct ele_attack_type {
- char *desc;
- u32b type;
- } ele_attack_type;
- static ele_attack_type ele_attack[] = {
- {"Fire Brand", ATTACK_FIRE},
- {"Cold Brand", ATTACK_COLD},
- {"Acid Brand", ATTACK_ACID},
- {"Elec Brand", ATTACK_ELEC}
- };
- char el_tag(menu_type * menu, int oid)
- {
- return I2A(oid);
- }
- /**
- * Display an entry on the sval menu
- */
- void el_display(menu_type * menu, int oid, bool cursor, int row, int col,
- int width)
- {
- const u16b *choice = menu->menu_data;
- int idx = choice[oid];
- byte attr = (cursor ? TERM_L_BLUE : TERM_WHITE);
- /* Print it */
- c_put_str(attr, format("%s", ele_attack[idx].desc), row, col);
- }
- /**
- * Deal with events on the sval menu
- */
- bool el_action(menu_type * menu, const ui_event * e, int oid)
- {
- u16b *choice = menu->menu_data;
- /* Choose */
- if (e->type == EVT_SELECT) {
- int idx = choice[oid];
- set_ele_attack(ele_attack[idx].type, 200);
- return FALSE;
- }
- else if (e->type == EVT_ESCAPE)
- return FALSE;
- else {
- int idx = choice[oid];
- set_ele_attack(ele_attack[idx].type, 200);
- return FALSE;
- }
- return FALSE;
- }
- /**
- * Display list of svals to be squelched.
- */
- bool el_menu(void)
- {
- menu_type menu;
- menu_iter menu_f = { el_tag, 0, el_display, el_action, 0 };
- region area = { 15, 1, 48, -1 };
- ui_event evt = { 0 };
- int cursor = 0;
- int num = 0;
- int i;
- u16b *choice;
- /* See how many attacks available */
- num = (p_ptr->lev - 20) / 7;
- /* Create the array */
- choice = C_ZNEW(num, u16b);
- /* Obvious */
- for (i = 0; i < num; i++) {
- /* Add this item to our possibles list */
- choice[i] = i;
- }
- /* Clear space */
- area.page_rows = num + 2;
- /* Return here if there are no attacks */
- if (!num) {
- FREE(choice);
- return FALSE;
- }
- /* Save the screen and clear it */
- screen_save();
- /* Help text */
- /* Set up the menu */
- WIPE(&menu, menu);
- menu_init(&menu, MN_SKIN_SCROLL, &menu_f);
- menu.title = "Choose a temporary elemental brand";
- menu_setpriv(&menu, num, choice);
- menu_layout(&menu, &area);
- /* Select an entry */
- evt = menu_select(&menu, cursor, TRUE);
- /* Free memory */
- FREE(choice);
- /* Load screen */
- screen_load();
- return (evt.type != EVT_ESCAPE);
- }
- /**
- * Choose a paladin elemental attack. -LM-
- */
- bool choose_ele_attack(void)
- {
- bool brand = FALSE;
- /* Save screen */
- screen_save();
- /* Choose */
- if (!el_menu())
- msg("You cancel the temporary branding.");
- else
- brand = TRUE;
- /* Load screen */
- screen_load();
- return brand;
- }
- /**
- * Array of elemental resistances
- */
- const char *ele_resist[] = {
- "Fire Resistance",
- "Cold Resistance",
- "Acid Resistance",
- "Electricity Resistance",
- "Poison Resistance"
- };
- char res_tag(menu_type * menu, int oid)
- {
- return I2A(oid);
- }
- /**
- * Display an entry on the sval menu
- */
- void res_display(menu_type * menu, int oid, bool cursor, int row, int col,
- int width)
- {
- const u16b *choice = menu->menu_data;
- int idx = choice[oid];
- byte attr = (cursor ? TERM_L_BLUE : TERM_WHITE);
- /* Print it */
- c_put_str(attr, format("%s", ele_resist[idx]), row, col);
- }
- /**
- * Deal with events on the sval menu
- */
- bool res_action(menu_type * menu, const ui_event * e, int oid)
- {
- u16b *choice = menu->menu_data;
- int plev = p_ptr->lev;
- /* Choose */
- if (e->type == EVT_ESCAPE)
- return FALSE;
- switch (choice[oid]) {
- case 0:
- {
- (void) inc_timed(TMD_OPP_FIRE, randint1(plev) + plev, TRUE);
- return FALSE;
- }
- case 1:
- {
- (void) inc_timed(TMD_OPP_COLD, randint1(plev) + plev, TRUE);
- return FALSE;
- }
- case 2:
- {
- (void) inc_timed(TMD_OPP_ACID, randint1(plev) + plev, TRUE);
- return FALSE;
- }
- case 3:
- {
- (void) inc_timed(TMD_OPP_ELEC, randint1(plev) + plev, TRUE);
- return FALSE;
- }
- case 4:
- {
- (void) inc_timed(TMD_OPP_POIS, randint1(plev) + plev, TRUE);
- return FALSE;
- }
- default:
- {
- return TRUE;
- }
- }
- }
- /**
- * Display list of svals to be squelched.
- */
- bool res_menu(void)
- {
- menu_type menu;
- menu_iter menu_f = { res_tag, 0, res_display, res_action, 0 };
- region area = { 15, 1, 48, 7 };
- ui_event evt = { 0 };
- int cursor = 0;
- size_t i;
- u16b *choice;
- /* Create the array */
- choice = C_ZNEW(5, u16b);
- /* Obvious */
- for (i = 0; i < 5; i++) {
- /* Add this item to our possibles list */
- choice[i] = i;
- }
- /* Save the screen and clear it */
- screen_save();
- /* Help text */
- /* Set up the menu */
- WIPE(&menu, menu);
- menu_init(&menu, MN_SKIN_SCROLL, &menu_f);
- menu.title = "Choose a temporary resistance";
- menu_setpriv(&menu, 5, choice);
- menu_layout(&menu, &area);
- /* Select an entry */
- evt = menu_select(&menu, cursor, TRUE);
- /* Free memory */
- FREE(choice);
- /* Load screen */
- screen_load();
- return (evt.type != EVT_ESCAPE);
- }
- /**
- * Choose an elemental resistance
- */
- extern bool choose_ele_resist(void)
- {
- bool resist = FALSE;
- /* Save screen */
- screen_save();
- /* Choose */
- if (!res_menu())
- msg("You cancel the temporary resistance.");
- else
- resist = TRUE;
- /* Load screen */
- screen_load();
- return resist;
- }
- /**
- * Hack -- The Athelas-creation code. -LM-
- */
- void create_athelas(void)
- {
- int py = p_ptr->py;
- int px = p_ptr->px;
- object_type *i_ptr;
- object_type object_type_body;
- /* Get local object */
- i_ptr = &object_type_body;
- /* Hack -- Make some Athelas, identify it, and drop it near the player. */
- object_prep(i_ptr, lookup_kind(TV_FOOD, SV_FOOD_ATHELAS), MINIMISE);
- /* Prevent money-making. */
- i_ptr->discount = 80;
- object_aware(i_ptr);
- object_known(i_ptr);
- drop_near(i_ptr, -1, py, px, TRUE);
- }
- /**
- * Controlled teleportation. -LM-
- * Idea from PsiAngband, through Zangband.
- */
- void dimen_door(void)
- {
- s16b ny;
- s16b nx;
- bool okay;
- okay = target_set_interactive(TARGET_LOOK | TARGET_GRID, -1, -1);
- if (!okay)
- return;
- /* grab the target coords. */
- target_get(&nx, &ny);
- /* Test for empty floor, forbid vaults or too large a distance, and insure
- * that this spell is never certain. */
- if (!cave_empty_bold(ny, nx) || cave_has(cave_info[ny][nx], CAVE_ICKY)
- || (distance(ny, nx, p_ptr->py, p_ptr->px) > 25)
- || (randint0(p_ptr->lev) == 0)) {
- msg("You fail to exit the astral plane correctly!");
- p_ptr->energy -= 50;
- teleport_player(15, FALSE);
- handle_stuff(p_ptr);
- }
- /* Controlled teleport. */
- else
- teleport_player_to(ny, nx, TRUE);
- }
- /**
- * Rebalance Weapon. This is a rather powerful spell, because it can be
- * used with any non-artifact throwing weapon, including ego-items. It is
- * therefore high-level, and curses weapons on failure. Do not give Assas-
- * sins "Break Curse". -LM-
- */
- void rebalance_weapon(void)
- {
- object_type *o_ptr;
- char o_name[120];
- /* Select the wielded melee weapon */
- o_ptr = &p_ptr->inventory[INVEN_WIELD];
- /* Nothing to rebalance */
- if (!o_ptr->k_idx) {
- msg("You are not wielding any melee weapon.");
- return;
- }
- /* Artifacts not allowed. */
- if (o_ptr->name1) {
- msg("Artifacts cannot be rebalanced.");
- return;
- }
- /* Not a throwing weapon. */
- if (!of_has(o_ptr->flags_obj, OF_THROWING)) {
- msg("The melee weapon you are wielding is not designed for throwing.");
- return;
- }
- /* 20% chance to curse weapon. */
- else if (randint1(5) == 1) {
- /* Description */
- object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE);
- /* Light curse and lower to_h and to_d by 2 to 5 each. */
- o_ptr->to_h -= (s16b) (2 + randint0(4));
- o_ptr->to_d -= (s16b) (2 + randint0(4));
- cf_on(o_ptr->flags_curse, FLAG_START + randint0(CF_MAX));
- /* Describe */
- msg("Oh no! A dreadful black aura surrounds your %s!", o_name);
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
- }
- /* Rebalance. */
- else {
- /* Grant perfect balance. */
- of_on(o_ptr->flags_obj, OF_PERFECT_BALANCE);
- /* Description */
- object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE);
- /* Describe */
- msg("Your %s gleams steel blue!", o_name);
- /* Prevent money-making. */
- o_ptr->discount = 80;
- }
- }
- /*
- * Increase players hit points, notice effects
- */
- bool hp_player(int num)
- {
- /* Healing needed */
- if (p_ptr->chp < p_ptr->mhp) {
- /* Gain hitpoints */
- p_ptr->chp += num;
- /* Enforce maximum */
- if (p_ptr->chp >= p_ptr->mhp) {
- p_ptr->chp = p_ptr->mhp;
- p_ptr->chp_frac = 0;
- }
- /* Redraw */
- p_ptr->redraw |= (PR_HP);
- /* Heal 0-4 */
- if (num < 5) {
- msg("You feel a little better.");
- }
- /* Heal 5-14 */
- else if (num < 15) {
- msg("You feel better.");
- }
- /* Heal 15-34 */
- else if (num < 35) {
- msg("You feel much better.");
- }
- /* Heal 35+ */
- else {
- msg("You feel very good.");
- }
- /* Notice */
- return (TRUE);
- }
- /* Ignore */
- return (FALSE);
- }
- /**
- * Jam a closed door with a magical spike.
- * Code is taken from do_cmd_spike. -LM-
- */
- void magic_spiking(void)
- {
- int py = p_ptr->py;
- int px = p_ptr->px;
- int y, x, i, dir;
- feature_type *f_ptr;
- /* Get a direction (or abort) */
- if (!get_rep_dir(&dir))
- return;
- /* Get location */
- y = py + ddy[dir];
- x = px + ddx[dir];
- f_ptr = &f_info[cave_feat[y][x]];
- /* Verify legality */
- if (!do_cmd_spike_test(y, x))
- return;
- /* Monster */
- if (cave_m_idx[y][x] > 0) {
- /* Message */
- msg("There is a monster in the way!");
- /* Attack */
- if (py_attack(y, x, TRUE))
- return;
- }
- /* Go for it */
- else {
- /* Verify legality */
- if (!do_cmd_spike_test(y, x))
- return;
- /* Successful jamming */
- msg("You magically jam the door.");
- /* Successful jamming */
- msg("You jam the door with a spike.");
- /* Convert "locked" to "stuck" XXX XXX XXX */
- if (!tf_has(f_ptr->flags, TF_DOOR_JAMMED)) {
- cave_feat[y][x] += 0x08;
- }
- /* Add three magical spikes to the door. */
- for (i = 0; i < 3; i++) {
- if (cave_feat[y][x] != FEAT_DOOR_TAIL) {
- cave_feat[y][x] += 0x01;
- }
- }
- }
- }
- /**
- * Leave a rune
- */
- bool lay_rune(int type)
- {
- int py = p_ptr->py;
- int px = p_ptr->px;
- trap_kind *trap_ptr = &trap_info[type];
- bool takes_rune = tf_has(f_info[cave_feat[py][px]].flags, TF_RUNE);
- /* If we're standing on a rune of mana, we can add mana to it */
- if ((type == RUNE_MANA) && (cave_trap_specific(py, px, RUNE_MANA))) {
- /* Standard mana amount */
- int mana = 40;
- /* Already full? */
- if (mana_reserve >= MAX_MANA_RESERVE) {
- msg("The rune cannot hold more mana");
- return (FALSE);
- }
- /* Don't put in more than we have */
- if (p_ptr->csp < mana)
- mana = p_ptr->csp;
- /* Don't put in more than it will hold */
- mana_reserve += mana;
- if (mana_reserve > MAX_MANA_RESERVE)
- mana_reserve = MAX_MANA_RESERVE;
- return (TRUE);
- }
- /* Need appropriate terrain and no monster */
- if (!takes_rune || cave_m_idx[py][px] > 0) {
- msg("You cannot lay a rune here.");
- return (FALSE);
- }
- #if 0
- /* Scan all objects in the grid */
- for (this_o_idx = cave_o_idx[py][px]; this_o_idx;
- this_o_idx = next_o_idx) {
- /* Acquire object */
- o_ptr = &o_list[this_o_idx];
- /* Acquire next object */
- next_o_idx = o_ptr->next_o_idx;
- /* Artifact */
- if (o_ptr->name1) {
- msg("There is an indestructible object here.");
- return (FALSE);
- }
- }
- /* Verify */
- if (cave_o_idx[py][px]) {
- if (!get_check("Destroy all items and lay a rune?"))
- return (FALSE);
- else {
- for (this_o_idx = cave_o_idx[py][px]; this_o_idx;
- this_o_idx = next_o_idx) {
- /* Acquire object */
- o_ptr = &o_list[this_o_idx];
- /* Acquire next object */
- next_o_idx = o_ptr->next_o_idx;
- /* Delete the object */
- delete_object_idx(this_o_idx);
- }
- /* Redraw */
- light_spot(py, px);
- }
- }
- #endif
- /* Limit total number of runes. */
- if (num_runes_on_level[type - 1] >= trap_ptr->max_num) {
- msg("You have reached the maximum number of runes of this type.");
- return (FALSE);
- }
- /* Create a rune */
- place_trap(py, px, type, 0);
- /* Increment the rune count. */
- num_runes_on_level[type - 1]++;
- /* Warning. */
- if (num_runes_on_level[type - 1] == trap_ptr->max_num) {
- msg("You have now reached your limit for runes of this type.");
- msg("In order to set more, remove some.");
- }
- return (TRUE);
- }
- /**
- * Array of stat "descriptions"
- */
- static const char *desc_stat_pos[] = {
- "strong",
- "smart",
- "wise",
- "dextrous",
- "healthy",
- "cute"
- };
- /**
- * Array of stat "descriptions"
- */
- static const char *desc_stat_neg[] = {
- "weak",
- "stupid",
- "naive",
- "clumsy",
- "sickly",
- "ugly"
- };
- /**
- * Lose a "point"
- */
- bool do_dec_stat(int stat)
- {
- bool sust = FALSE;
- bool clarity = (player_has(PF_CLARITY));
- bool athletics = (player_has(PF_ATHLETICS));
- /* Access the "sustain" and specialty skills */
- switch (stat) {
- case A_STR:
- if (p_ptr->state.sustain_str)
- sust = TRUE;
- break;
- case A_INT:
- if ((p_ptr->state.sustain_int) || (clarity && (randint0(2) != 0)))
- sust = TRUE;
- break;
- case A_WIS:
- if ((p_ptr->state.sustain_wis) || (clarity && (randint0(2) != 0)))
- sust = TRUE;
- break;
- case A_DEX:
- if ((p_ptr->state.sustain_dex)
- || (athletics && (randint0(2) != 0)))
- sust = TRUE;
- break;
- case A_CON:
- if ((p_ptr->state.sustain_con)
- || (athletics && (randint0(2) != 0)))
- sust = TRUE;
- break;
- case A_CHR:
- if (p_ptr->state.sustain_chr)
- sust = TRUE;
- break;
- }
- /* Sustain */
- if (sust) {
- /* Message */
- msg("You feel very %s for a moment, but the feeling passes.",
- desc_stat_neg[stat]);
- /* Notice effect */
- notice_obj(OBJECT_RAND_BASE_SUSTAIN + stat, 0);
- return (TRUE);
- }
- /* Attempt to reduce the stat */
- if (dec_stat(stat, 10, FALSE)) {
- /* Message */
- msg("You feel very %s.", desc_stat_neg[stat]);
- /* Notice effect */
- return (TRUE);
- }
- /* Nothing obvious */
- return (FALSE);
- }
- /**
- * Restore lost "points" in a stat
- */
- bool do_res_stat(int stat)
- {
- /* Attempt to increase */
- if (res_stat(stat)) {
- /* Message */
- msg("You feel less %s.", desc_stat_neg[stat]);
- /* Notice */
- return (TRUE);
- }
- /* Nothing obvious */
- return (FALSE);
- }
- /**
- * Gain a "point" in a stat
- */
- bool do_inc_stat(int stat, bool star)
- {
- bool res;
- /* Restore stst */
- res = res_stat(stat);
- /* Attempt to increase */
- if (inc_stat(stat, star)) {
- /* Message */
- msg("You feel very %s!", desc_stat_pos[stat]);
- /* Notice */
- return (TRUE);
- }
- /* Restoration worked */
- if (res) {
- /* Message */
- msg("You feel less %s.", desc_stat_neg[stat]);
- /* Notice */
- return (TRUE);
- }
- /* Nothing obvious */
- return (FALSE);
- }
- void identify_object(object_type * o_ptr)
- {
- object_kind *k_ptr;
- bool was_dubious = FALSE;
- /* Get the object kind. */
- k_ptr = &k_info[o_ptr->k_idx];
- /* See what we thought of it before */
- if ((o_ptr->feel == FEEL_PERILOUS)
- || (o_ptr->feel == FEEL_DUBIOUS_WEAK)
- || (o_ptr->feel == FEEL_DUBIOUS_STRONG))
- was_dubious = TRUE;
- /* Identify it fully */
- object_aware(o_ptr);
- object_known(o_ptr);
- /* Now we know about any ego-item type */
- if (o_ptr->name2)
- e_info[o_ptr->name2].everseen = TRUE;
- /* Check for known curses */
- if ((of_has(o_ptr->flags_obj, OF_SHOW_CURSE))
- || (artifact_p(o_ptr) && (o_ptr->name1 < ART_MIN_RANDOM))) {
- cf_copy(o_ptr->id_curse, o_ptr->flags_curse);
- o_ptr->ident |= IDENT_KNOW_CURSES;
- if (!cf_is_empty(o_ptr->flags_curse))
- o_ptr->ident |= IDENT_CURSED;
- else
- o_ptr->ident |= IDENT_UNCURSED;
- }
- /* If it seemed dubious but has no identifiable negatives, it's cursed */
- if (!item_dubious(o_ptr, FALSE) && was_dubious)
- o_ptr->ident |= IDENT_CURSED;
- /* Log artifacts to the history list. */
- if (artifact_p(o_ptr))
- history_add_artifact(o_ptr->name1, TRUE, TRUE);
- /* If the object is flavored, also make all items of that type, except for
- * variable rings and amulets, fully known. */
- if (k_ptr->flavor) {
- if ((o_ptr->tval == TV_FOOD) || (o_ptr->tval == TV_STAFF)
- || (o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_ROD))
- k_ptr->known_effect = TRUE;
- }
- /* Set squelch flag as appropriate */
- p_ptr->notice |= PN_SQUELCH;
- }
- /**
- * Identify everything being carried.
- * Done by a potion of "*Enlightenment*".
- */
- void identify_pack(void)
- {
- int i;
- /* Simply identify and know every item */
- for (i = 0; i < INVEN_TOTAL; i++) {
- object_type *o_ptr = &p_ptr->inventory[i];
- /* Skip non-objects */
- if (!o_ptr->k_idx)
- continue;
- /* Identify it */
- identify_object(o_ptr);
- }
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
- /* Combine / Reorder the pack (later) */
- p_ptr->notice |= (PN_COMBINE | PN_REORDER | PN_SORT_QUIVER);
- /* Redraw stuff */
- p_ptr->redraw |= (PR_INVEN | PR_EQUIP);
- }
- /**
- * Used by the "enchant" function (chance of failure)
- */
- static int enchant_table[16] = {
- 0, 10, 50, 100, 200,
- 300, 400, 500, 700, 950,
- 990, 992, 995, 997, 999,
- 1000
- };
- static bool item_tester_cursed(const object_type * o_ptr)
- {
- if (known_cursed_p(o_ptr)
- && !(of_has(o_ptr->flags_obj, OF_PERMA_CURSE)))
- return TRUE;
- else
- return FALSE;
- }
- /**
- * Attempts to remove curses from items in inventory
- *
- * Note that Items which are "Perma-Cursed"
- * can NEVER be uncursed.
- *
- * If good is TRUE, there is a better chance of removal. Using this spell
- * once makes an item fragile, which means it is likely to be destroyed on
- * a second attempt.
- */
- static bool remove_curse_aux(int good)
- {
- int i, item, slot;
- object_type *o_ptr;
- char o_name[120];
- const char *q, *s;
- bitflag curses[CF_SIZE];
- int destroy_chance = 50;
- int uncurse_chance = 50;
- bool heavy = FALSE;
- int feel;
- cf_wipe(curses);
- /* Only cursed items */
- item_tester_hook = item_tester_cursed;
- /* Don't restrict choices */
- item_tester_tval = 0;
- /* Get an item. */
- q = "Attempt to uncurse which item? ";
- s = "You have no curses which can be removed.";
- if (!get_item
- (&item, q, s, CMD_NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
- return (FALSE);
- /* Get the item (in the pack) */
- if (item >= 0) {
- o_ptr = &p_ptr->inventory[item];
- }
- /* Get the item (on the floor) */
- else {
- o_ptr = &o_list[0 - item];
- }
- /* Artifacts are harder to uncurse and destroy */
- if (artifact_p(o_ptr)) {
- destroy_chance -= 25;
- uncurse_chance -= 25;
- }
- /* Try every curse, even unknown ones */
- for (i = cf_next(o_ptr->flags_curse, FLAG_START); i != FLAG_END;
- i = cf_next(o_ptr->flags_curse, i + 1))
- if (cf_has(o_ptr->flags_curse, i)) {
- /* If fragile, bad things can happen */
- if ((of_has(o_ptr->flags_obj, OF_FRAGILE))
- && (randint0(100) < destroy_chance - (good ? 10 : 0))) {
- /* Message */
- msg("There is a bang and a flash!");
- /* Damage */
- take_hit(damroll(5, 5), "Failed uncursing");
- /* Gone */
- if (item >= 0) {
- inven_item_increase(item, -1);
- inven_item_describe(item);
- inven_item_optimize(item);
- } else {
- floor_item_increase(0 - item, -1);
- floor_item_describe(0 - item);
- floor_item_optimize(0 - item);
- }
- return (TRUE);
- }
- /* Try once */
- if (randint0(100) < uncurse_chance)
- cf_on(curses, i);
- /* If good, try again */
- if (good && (randint0(100) < uncurse_chance))
- cf_on(curses, i);
- }
- /* Uncurse it */
- cf_negate(curses);
- cf_inter(o_ptr->flags_curse, curses);
- cf_inter(o_ptr->id_curse, curses);
- /* May not be cursed any more */
- if (cf_is_empty(o_ptr->id_curse))
- o_ptr->ident &= ~(IDENT_CURSED);
- /* Fragile now */
- of_on(o_ptr->flags_obj, OF_FRAGILE);
- of_on(o_ptr->id_obj, OF_FRAGILE);
- /* Known objects get free curse notification now */
- if (object_known_p(o_ptr)) {
- if (!cf_is_empty(o_ptr->flags_curse))
- o_ptr->ident |= IDENT_CURSED;
- else
- o_ptr->ident |= (IDENT_UNCURSED | IDENT_KNOW_CURSES);
- }
- /* Redo feeling if it's not known */
- else {
- /* Heavy sensing */
- heavy = (player_has(PF_PSEUDO_ID_HEAVY));
- /* Type of feeling */
- feel = (heavy ? value_check_aux1(o_ptr) : value_check_aux2(o_ptr));
- /* Check the slot */
- slot = wield_slot(o_ptr);
- /* Redo feeling */
- if (!(o_ptr->feel == feel)) {
- /* Get an object description */
- object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE);
- msg("You feel the %s (%c) you are %s %s now %s...", o_name,
- index_to_label(slot), describe_use(slot),
- ((o_ptr->number == 1) ? "is" : "are"), feel_text[feel]);
- /* We have "felt" it */
- o_ptr->ident |= (IDENT_SENSE);
- /* Inscribe it textually */
- o_ptr->feel = feel;
- /* Set squelch flag as appropriate */
- p_ptr->notice |= PN_SQUELCH;
- }
- }
- /* Recalculate the bonuses */
- p_ptr->update |= (PU_BONUS);
- /* Redraw stuff */
- p_ptr->redraw |= (PR_EQUIP | PR_INVEN);
- /* Something uncursed */
- if (cf_is_empty(curses))
- msg("You feel as if someone is watching over you.");
- /* Return scroll used/spell cast */
- return (TRUE);
- }
- /**
- * Remove most curses
- */
- bool remove_curse(void)
- {
- return (remove_curse_aux(FALSE));
- }
- /**
- * Remove all curses
- */
- bool remove_curse_good(void)
- {
- return (remove_curse_aux(TRUE));
- }
- /**
- * Restores any drained experience
- */
- bool restore_level(void)
- {
- /* Restore experience */
- if (p_ptr->exp < p_ptr->max_exp) {
- /* Message */
- msg("You feel your life energies returning.");
- /* Restore the experience */
- p_ptr->exp = p_ptr->max_exp;
- /* Check the experience */
- check_experience();
- /* Did something */
- return (TRUE);
- }
- /* No effect */
- return (FALSE);
- }
- /**
- * Forget everything
- */
- bool lose_all_info(void)
- {
- /* Mega-Hack -- Forget the map */
- wiz_dark();
- /* It worked */
- return (TRUE);
- }
- /**
- * Hack - displays areas effected by detection spells.
- *
- */
- static void animate_detect(int rad)
- {
- int py = p_ptr->py;
- int px = p_ptr->px;
- int x, y;
- byte a, c;
- int msec = op_ptr->delay_factor * op_ptr->delay_factor;
- /* Exit if not desired */
- if (!OPT(show_detect))
- return;
- /* Hack - Needs to last a bit longer to be visible */
- msec *= 6;
- /* Scan the maximal area of detection */
- for (y = py - rad; y <= py + rad; y++) {
- for (x = px - rad; x <= px + rad; x++) {
- /* Ignore "illegal" locations */
- if (!in_bounds(y, x))
- continue;
- /* Enforce a "circular" area */
- if (distance(py, px, y, x) > rad)
- continue;
- /* Only show the region that the player can see */
- if (panel_contains(y, x)) {
- /* Hack - Obtain attr/char */
- a = gf_to_attr[GF_DETECT][BOLT_NO_MOTION];
- c = gf_to_char[GF_DETECT][BOLT_NO_MOTION];
- /* Hack -- Visual effects -- Display a yellow star */
- print_rel(c, a, y, x);
- }
- }
- }
- /* Flush the image of detected region */
- Term_fresh();
- if (p_ptr->redraw)
- redraw_stuff(p_ptr);
- /* Delay (efficiently) */
- Term_xtra(TERM_XTRA_DELAY, msec);
- /* Now erase the effect */
- for (y = py - rad; y <= py + rad; y++) {
- for (x = px - rad; x <= px + rad; x++) {
- /* Ignore "illegal" locations */
- if (!in_bounds(y, x))
- continue;
- /* Enforce a "circular" area */
- if (distance(py, px, y, x) > rad)
- continue;
- /* Hack -- Erase only if needed */
- if (panel_contains(y, x)) {
- light_spot(y, x);
- }
- }
- }
- /* Hack -- center the cursor */
- move_cursor_relative(py, px);
- /* Flush screen back to normal */
- Term_fresh();
- if (p_ptr->redraw)
- redraw_stuff(p_ptr);
- /* Exit */
- return;
- }
- /**
- * Detect all traps within range
- */
- bool detect_traps(int range, bool show)
- {
- int y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool detect = FALSE;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan the map */
- for (y = 0; y < ARENA_HGT; y++) {
- for (x = 0; x < ARENA_WID; x++) {
- /* check range */
- if (distance(py, px, y, x) <= range) {
- /* Detect invisible traps */
- if (cave_invisible_trap(y, x)) {
- if (reveal_trap(y, x, 100, FALSE)) {
- detect = TRUE;
- }
- }
- /* Mark grid as detected */
- cave_on(cave_info[y][x], CAVE_DTRAP);
- }
- }
- }
- /* Found some */
- if (detect) {
- /* Print success message */
- msg("You detect traps.");
- }
- /* Redraw DTrap Status */
- p_ptr->redraw |= (PR_DTRAP);
- /* Result - trap detection items are easy to recognize for now -BR- */
- return (TRUE);
- }
- /**
- * Detect all doors within range
- */
- bool detect_doors(int range, bool show)
- {
- int y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool detect = FALSE;
- int num = 0;
- feature_type *f_ptr = NULL;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan the map */
- for (y = 0; y < ARENA_HGT; y++) {
- for (x = 0; x < ARENA_WID; x++) {
- /* check range */
- if (distance(py, px, y, x) <= range) {
- /* Detect secret doors */
- if (cave_feat[y][x] == FEAT_SECRET) {
- /* Pick a door */
- place_closed_door(y, x);
- }
- /* Set the feature */
- f_ptr = &f_info[cave_feat[y][x]];
- /* Detect doors */
- if (tf_has(f_ptr->flags, TF_DOOR_ANY)) {
- /* Hack -- Memorize */
- cave_on(cave_info[y][x], CAVE_MARK);
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- num++;
- }
- }
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- /* Print success message */
- msg("You detect doors.");
- }
- /* Result */
- return (detect);
- }
- /**
- * Detect all stairs within range
- */
- bool detect_stairs(int range, bool show)
- {
- int y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- int num = 0;
- bool detect = FALSE;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan the map */
- for (y = 0; y < ARENA_HGT; y++) {
- for (x = 0; x < ARENA_WID; x++) {
- /* check range */
- if (distance(py, px, y, x) <= range) {
- feature_type *f_ptr = &f_info[cave_feat[y][x]];
- /* Detect stairs */
- if (tf_has(f_ptr->flags, TF_STAIR) ||
- tf_has(f_ptr->flags, TF_PATH)) {
- /* Hack -- Memorize */
- cave_on(cave_info[y][x], CAVE_MARK);
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- num++;
- }
- }
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- /* Print success message */
- msg("You detect stairs.");
- }
- /* Result */
- return (detect);
- }
- /**
- * Detect any treasure within range
- */
- bool detect_treasure(int range, bool show)
- {
- int y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool detect = FALSE;
- int num = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan the map */
- for (y = 0; y < ARENA_HGT; y++) {
- for (x = 0; x < ARENA_WID; x++) {
- /* check range */
- if (distance(py, px, y, x) <= range) {
- /* Notice embedded gold */
- if (cave_feat[y][x] == FEAT_MAGMA_H) {
- /* Expose the gold */
- cave_feat[y][x] = FEAT_MAGMA_K;
- }
- /* Notice embedded gold */
- if (cave_feat[y][x] == FEAT_QUARTZ_H) {
- /* Expose the gold */
- cave_feat[y][x] = FEAT_QUARTZ_K;
- }
- /* Magma/Quartz + Known Gold */
- if ((cave_feat[y][x] == FEAT_MAGMA_K)
- || (cave_feat[y][x] == FEAT_QUARTZ_K)) {
- /* Hack -- Memorize */
- cave_on(cave_info[y][x], CAVE_MARK);
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- num++;
- }
- }
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- /* Print success message */
- msg("You detect buried treasure.");
- }
- /* Result */
- return (detect);
- }
- /**
- * Detect all "gold" objects within range
- */
- bool detect_objects_gold(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- int num = 0;
- bool detect = FALSE;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan objects */
- for (i = 1; i < o_max; i++) {
- object_type *o_ptr = &o_list[i];
- /* Skip dead objects */
- if (!o_ptr->k_idx)
- continue;
- /* Skip held objects */
- if (o_ptr->held_m_idx)
- continue;
- /* Location */
- y = o_ptr->iy;
- x = o_ptr->ix;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Detect "gold" objects */
- if (o_ptr->tval == TV_GOLD) {
- /* Hack -- memorize it */
- o_ptr->marked = TRUE;
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- num++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- msg("You detect treasure.");
- }
- /* Result */
- return (detect);
- }
- /**
- * Detect all "normal" objects within range
- */
- bool detect_objects_normal(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- int num = 0;
- bool detect = FALSE;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan objects */
- for (i = 1; i < o_max; i++) {
- object_type *o_ptr = &o_list[i];
- /* Skip dead objects */
- if (!o_ptr->k_idx)
- continue;
- /* Skip held objects */
- if (o_ptr->held_m_idx)
- continue;
- /* Location */
- y = o_ptr->iy;
- x = o_ptr->ix;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Detect "real" objects */
- if (o_ptr->tval != TV_GOLD) {
- /* Hack -- memorize it */
- o_ptr->marked = TRUE;
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- if (!squelch_hide_item(o_ptr))
- num++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- /* Print success message */
- msg("You detect objects.");
- }
- /* Result */
- return (detect);
- }
- /**
- * Detect all "magic" objects within range.
- *
- * This will light up all spaces with "magic" items, including artifacts,
- * ego-items, potions, scrolls, books, rods, wands, staves, amulets, rings,
- * and "enchanted" items of the "good" variety.
- *
- * It can probably be argued that this function is now too powerful.
- */
- bool detect_objects_magic(int range, bool show)
- {
- int i, y, x, tv;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool detect = FALSE;
- int num = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan all objects */
- for (i = 1; i < o_max; i++) {
- object_type *o_ptr = &o_list[i];
- /* Skip dead objects */
- if (!o_ptr->k_idx)
- continue;
- /* Skip held objects */
- if (o_ptr->held_m_idx)
- continue;
- /* Location */
- y = o_ptr->iy;
- x = o_ptr->ix;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Examine the tval */
- tv = o_ptr->tval;
- /* Artifacts, misc magic items, or enchanted wearables */
- if (artifact_p(o_ptr) || ego_item_p(o_ptr) || (tv == TV_AMULET)
- || (tv == TV_RING) || (tv == TV_STAFF) || (tv == TV_WAND)
- || (tv == TV_ROD) || (tv == TV_SCROLL) || (tv == TV_POTION)
- || (tv == TV_MAGIC_BOOK) || (tv == TV_PRAYER_BOOK)
- || (tv == TV_DRUID_BOOK) || (tv == TV_NECRO_BOOK)
- || ((o_ptr->to_a > 0) || (o_ptr->to_h + o_ptr->to_d > 0))) {
- /* Memorize the item */
- o_ptr->marked = TRUE;
- /* Redraw */
- light_spot(y, x);
- /* increment number found */
- if (!squelch_hide_item(o_ptr))
- num++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- detect = TRUE;
- /* Print success message */
- msg("You detect magic objects.");
- }
- /* Return result */
- return (detect);
- }
- /**
- * Detect all "normal" monsters within range
- */
- bool detect_monsters_normal(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool flag = FALSE;
- int num = 0;
- int num_off = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan monsters */
- for (i = 1; i < m_max; i++) {
- monster_type *m_ptr = &m_list[i];
- monster_race *r_ptr = &r_info[m_ptr->r_idx];
- /* Skip dead monsters */
- if (!m_ptr->r_idx)
- continue;
- /* Location */
- y = m_ptr->fy;
- x = m_ptr->fx;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Detect all non-invisible monsters */
- if (!(rf_has(r_ptr->flags, RF_INVISIBLE))) {
- /* Optimize -- Repair flags */
- repair_mflag_mark = repair_mflag_show = TRUE;
- /* Hack -- Detect the monster */
- m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
- /* Update the monster */
- update_mon(i, FALSE);
- /* increment number found */
- num++;
- /* increment number found offscreen */
- if (!panel_contains(y, x))
- num_off++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- flag = TRUE;
- /* Print success message */
- if (num_off > 0)
- msg("You detect monsters (%i offscreen).", num_off);
- else
- msg("You detect monsters.");
- }
- /* Result */
- return (flag);
- }
- /**
- * Detect all "invisible" monsters within range
- */
- bool detect_monsters_invis(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool flag = FALSE;
- int num = 0;
- int num_off = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan monsters */
- for (i = 1; i < m_max; i++) {
- monster_type *m_ptr = &m_list[i];
- monster_race *r_ptr = &r_info[m_ptr->r_idx];
- monster_lore *l_ptr = &l_list[m_ptr->r_idx];
- /* Skip dead monsters */
- if (!m_ptr->r_idx)
- continue;
- /* Location */
- y = m_ptr->fy;
- x = m_ptr->fx;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Detect invisible monsters */
- if (rf_has(r_ptr->flags, RF_INVISIBLE)) {
- /* Take note that they are invisible */
- rf_on(l_ptr->flags, RF_INVISIBLE);
- /* Update monster recall window */
- if (p_ptr->monster_race_idx == m_ptr->r_idx) {
- /* Redraw stuff */
- p_ptr->redraw |= (PR_MONSTER);
- }
- /* Optimize -- Repair flags */
- repair_mflag_mark = repair_mflag_show = TRUE;
- /* Hack -- Detect the monster */
- m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
- /* Update the monster */
- update_mon(i, FALSE);
- /* increment number found */
- num++;
- /* increment number found offscreen */
- if (!panel_contains(y, x))
- num_off++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- flag = TRUE;
- /* Print success message */
- if (num_off > 0)
- msg("You detect invisible creatures (%i offscreen).", num_off);
- else
- msg("You detect invisible creatures.");
- }
- /* Result */
- return (flag);
- }
- /**
- * Detect all "evil" monsters within range
- */
- bool detect_monsters_evil(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool flag = FALSE;
- int num = 0;
- int num_off = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan monsters */
- for (i = 1; i < m_max; i++) {
- monster_type *m_ptr = &m_list[i];
- monster_race *r_ptr = &r_info[m_ptr->r_idx];
- monster_lore *l_ptr = &l_list[m_ptr->r_idx];
- /* Skip dead monsters */
- if (!m_ptr->r_idx)
- continue;
- /* Location */
- y = m_ptr->fy;
- x = m_ptr->fx;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Detect evil monsters */
- if (rf_has(r_ptr->flags, RF_EVIL)) {
- /* Take note that they are evil */
- rf_on(l_ptr->flags, RF_EVIL);
- /* Update monster recall window */
- if (p_ptr->monster_race_idx == m_ptr->r_idx) {
- /* Redraw stuff */
- p_ptr->redraw |= (PR_MONSTER);
- }
- /* Optimize -- Repair flags */
- repair_mflag_mark = repair_mflag_show = TRUE;
- /* Detect the monster */
- m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
- /* Update the monster */
- update_mon(i, FALSE);
- /* increment number found */
- num++;
- /* increment number found offscreen */
- if (!panel_contains(y, x))
- num_off++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- flag = TRUE;
- /* Print success message */
- if (num_off > 0)
- msg("You detect evil creatures (%i offscreen).", num_off);
- else
- msg("You detect evil creatures.");
- }
- /* Result */
- return (flag);
- }
- /**
- * Detect all "living" monsters within range.
- */
- bool detect_monsters_living(int range, bool show)
- {
- int i, y, x;
- int py = p_ptr->py;
- int px = p_ptr->px;
- bool flag = FALSE;
- int num = 0;
- int num_off = 0;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Scan monsters */
- for (i = 1; i < m_max; i++) {
- monster_type *m_ptr = &m_list[i];
- monster_race *r_ptr = &r_info[m_ptr->r_idx];
- /* Skip dead monsters */
- if (!m_ptr->r_idx)
- continue;
- /* Location */
- y = m_ptr->fy;
- x = m_ptr->fx;
- /* check range */
- if (distance(py, px, y, x) > range)
- continue;
- /* Hack -- Detect all living monsters. */
- if ((!strchr("Egv", r_ptr->d_char))
- && (!(rf_has(r_ptr->flags, RF_UNDEAD)))) {
- /* Optimize -- Repair flags */
- repair_mflag_mark = repair_mflag_show = TRUE;
- /* Hack -- Detect the monster */
- m_ptr->mflag |= (MFLAG_MARK | MFLAG_SHOW);
- /* Update the monster */
- update_mon(i, FALSE);
- /* increment number found */
- num++;
- /* increment number found offscreen */
- if (!panel_contains(y, x))
- num_off++;
- }
- }
- /* Found some */
- if (num > 0) {
- /* Obvious */
- flag = TRUE;
- /* Print success message */
- if (num_off > 0)
- msg("You detect living creatures (%i offscreen).", num_off);
- else
- msg("You detect living creatures.");
- }
- /* Now detect trees */
- num = 0;
- /* Scan the maximal area of mapping */
- for (y = py - range; y <= py + range; y++) {
- for (x = px - range; x <= px + range; x++) {
- feature_type *f_ptr = &f_info[cave_feat[y][x]];
- /* Ignore "illegal" locations */
- if (!in_bounds(y, x))
- continue;
- /* Enforce a "circular" area */
- if (distance(py, px, y, x) > range)
- continue;
- /* Notice trees */
- if (tf_has(f_ptr->flags, TF_TREE)) {
- /* Mark it */
- cave_on(cave_info[y][x], CAVE_MARK);
- /* Count it */
- num++;
- }
- }
- }
- /* Found some */
- if (num > 0) {
- flag = TRUE;
- /* Print message */
- msg("You detect trees.");
- /* Update */
- p_ptr->redraw |= PR_MAP;
- redraw_stuff(p_ptr);
- }
- /* Result */
- return (flag);
- }
- /**
- * Detect everything
- */
- bool detect_all(int range, bool show)
- {
- bool detect = FALSE;
- /* Hack - flash the effected region on the current panel */
- if (show)
- animate_detect(range);
- /* Detect everything */
- /* Do not 'show' the affected region for each detect individually */
- if (detect_traps(range, FALSE))
- detect = TRUE;
- if (detect_doors(range, FALSE))
- detect = TRUE;
- if (detect_stairs(range, FALSE))
- detect = TRUE;
- if (detect_treasure(range, FALSE))
- detect = TRUE;
- if (detect_objects_gold(range, FALSE))
- detect = TRUE;
- if (detect_objects_normal(range, FALSE))
- detect = TRUE;
- if (detect_monsters_invis(range, FALSE))
- detect = TRUE;
- if (detect_monsters_normal(range, FALSE))
- detect = TRUE;
- /* Result */
- return (detect);
- }
- /**
- * Create stairs at the player location
- */
- void stair_creation(void)
- {
- int py = p_ptr->py;
- int px = p_ptr->px;
- /* XXX XXX XXX */
- if (!cave_valid_bold(py, px)) {
- msg("The object resists the spell.");
- return;
- }
- /* Doesn't work outside caves */
- if (chunk_list[p_ptr->stage].z_pos == 0) {
- msg("You can only create stairs in caves!");
- return;
- }
- /* XXX XXX XXX */
- delete_object(py, px);
- /* Create a staircase */
- if (is_quest(p_ptr->stage) || (chunk_list[p_ptr->stage].z_pos == 127)) {
- cave_set_feat(py, px, FEAT_LESS);
- } else if (chunk_list[p_ptr->stage].z_pos == 0) {
- cave_set_feat(py, px, FEAT_MORE);
- } else if (randint0(100) < 50) {
- cave_set_feat(py, px, FEAT_MORE);
- } else {
- cave_set_feat(py, px, FEAT_LESS);
- }
- }
- /**
- * Hook to specify "weapon"
- */
- static bool item_tester_hook_weapon(const object_type * o_ptr)
- {
- switch (o_ptr->tval) {
- case TV_SWORD:
- case TV_HAFTED:
- case TV_POLEARM:
- case TV_DIGGING:
- case TV_BOW:
- case TV_BOLT:
- case TV_ARROW:
- case TV_SHOT:
- {
- return (TRUE);
- }
- }
- return (FALSE);
- }
- /**
- * Hook to specify "ammunition"
- */
- static bool item_tester_hook_ammo(const object_type * o_ptr)
- {
- switch (o_ptr->tval) {
- case TV_BOLT:
- case TV_ARROW:
- case TV_SHOT:
- {
- return (TRUE);
- }
- }
- return (FALSE);
- }
- /**
- * Hook to specify "armour"
- */
- static bool item_tester_hook_armour(const object_type * o_ptr)
- {
- switch (o_ptr->tval) {
- case TV_DRAG_ARMOR:
- case TV_HARD_ARMOR:
- case TV_SOFT_ARMOR:
- case TV_SHIELD:
- case TV_CLOAK:
- case TV_CROWN:
- case TV_HELM:
- case TV_BOOTS:
- case TV_GLOVES:
- {
- return (TRUE);
- }
- }
- return (FALSE);
- }
- static bool item_tester_unknown(const object_type * o_ptr)
- {
- if (object_known_p(o_ptr))
- return FALSE;
- else
- return TRUE;
- }
- static bool item_tester_unknown_curse(const object_type * o_ptr)
- {
- if (object_known_p(o_ptr) && (o_ptr->ident & IDENT_KNOW_CURSES))
- return FALSE;
- else
- return TRUE;
- }
- static bool item_tester_unproofed(const object_type * o_ptr)
- {
- if (o_ptr->number != 1)
- return FALSE;
- if (of_is_subset(o_ptr->flags_obj, el_to_proof))
- return FALSE;
- else
- return TRUE;
- }
- /**
- * Enchant an item
- *
- * Revamped! Now takes item pointer, number of times to try enchanting,
- * and a flag of what to try enchanting. Artifacts resist enchantment
- * some of the time, and successful enchantment to at least +0 might
- * break a curse on the item. -CFT
- *
- * Note that an item can technically be enchanted all the way to +15 if
- * you wait a very, very, long time. Going from +9 to +10 only works
- * about 5% of the time, and from +10 to +11 only about 1% of the time.
- *
- * Note that this function can now be used on "piles" of items, and
- * the larger the pile, the lower the chance of success.
- */
- bool enchant(object_type * o_ptr, int n, int eflag)
- {
- int i, chance, prob;
- bool res = FALSE;
- bool a = artifact_p(o_ptr);
- /* Large piles resist enchantment */
- prob = o_ptr->number * 100;
- /* Missiles are easy to enchant */
- if ((o_ptr->tval == TV_BOLT) || (o_ptr->tval == TV_ARROW)
- || (o_ptr->tval == TV_SHOT)) {
- prob = prob / 35;
- }
- /* Try "n" times */
- for (i = 0; i < n; i++) {
- /* Hack -- Roll for pile resistance */
- if ((prob > 100) && (randint0(prob) >= 100))
- continue;
- /* Enchant to hit */
- if (eflag & (ENCH_TOHIT)) {
- if (o_ptr->to_h < 0)
- chance = 0;
- else if (o_ptr->to_h > 15)
- chance = 1000;
- else
- chance = enchant_table[o_ptr->to_h];
- /* Attempt to enchant */
- if ((randint1(1000) > chance) && (!a || (randint0(100) < 50))) {
- res = TRUE;
- /* Enchant */
- o_ptr->to_h++;
- }
- }
- /* Enchant to damage */
- if (eflag & (ENCH_TODAM)) {
- if (o_ptr->to_d < 0)
- chance = 0;
- else if (o_ptr->to_d > 15)
- chance = 1000;
- else
- chance = enchant_table[o_ptr->to_d];
- if ((randint1(1000) > chance) && (!a || (randint0(100) < 50))) {
- res = TRUE;
- /* Enchant */
- o_ptr->to_d++;
- }
- }
- /* Enchant to armor class */
- if (eflag & (ENCH_TOAC)) {
- if (o_ptr->to_a < 0)
- chance = 0;
- else if (o_ptr->to_a > 15)
- chance = 1000;
- else
- chance = enchant_table[o_ptr->to_a];
- if ((randint1(1000) > chance) && (!a || (randint0(100) < 50))) {
- res = TRUE;
- /* Enchant */
- o_ptr->to_a++;
- }
- }
- }
- /* Failure */
- if (!res)
- return (FALSE);
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
- /* Combine / Reorder the pack (later) */
- p_ptr->notice |= (PN_COMBINE | PN_REORDER | PN_SORT_QUIVER);
- /* Redraw stuff */
- p_ptr->redraw |= (PR_INVEN | PR_EQUIP);
- /* Success */
- return (TRUE);
- }
- /**
- * Enchant an item (in the inventory or on the floor)
- * Note that "num_ac" requires armour, else weapon
- * Returns TRUE if attempted, FALSE if cancelled
- */
- bool enchant_spell(int num_hit, int num_dam, int num_ac)
- {
- int item;
- bool okay = FALSE;
- object_type *o_ptr;
- char o_name[120];
- const char *q, *s;
- /* Assume enchant weapon */
- item_tester_hook = item_tester_hook_weapon;
- /* Don't restrict choices */
- item_tester_tval = 0;
- /* Enchant armor if requested */
- if (num_ac)
- item_tester_hook = item_tester_hook_armour;
- /* Get an item */
- q = "Enchant which item? ";
- s = "You have nothing to enchant.";
- if (!get_item
- (&item, q, s, CMD_NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
- return (FALSE);
- /* Get the item (in the pack) */
- if (item >= 0) {
- o_ptr = &p_ptr->inventory[item];
- }
- /* Get the item (on the floor) */
- else {
- o_ptr = &o_list[0 - item];
- }
- /* Description */
- object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE);
- /* Describe */
- msg("%s %s glow%s brightly!", ((item >= 0) ? "Your" : "The"), o_name,
- ((o_ptr->number > 1) ? "" : "s"));
- /* Enchant */
- if (enchant(o_ptr, num_hit, ENCH_TOHIT))
- okay = TRUE;
- if (enchant(o_ptr, num_dam, ENCH_TODAM))
- okay = TRUE;
- if (enchant(o_ptr, num_ac, ENCH_TOAC))
- okay = TRUE;
- /* Failure */
- if (!okay) {
- /* Flush */
- if (OPT(flush_failure))
- flush();
- /* Message */
- msg("The enchantment failed.");
- }
- /* Something happened */
- return (TRUE);
- }
- /**
- * Enchant some missiles and give them an elemental brand
- *
- * Combines the old brand_bolts and brand_missiles routines.
- *
- * ammo_type is the tval of the relevant ammunition.
- * If set to 0, any ammunition is enchantable.
- *
- * Brand type is the EGO flag for the relevant type element.
- * If set to 0, a non-poison brand is picked randomly.
- *
- */
- bool brand_missile(int ammo_type, int brand_type)
- {
- int item, choice;
- object_type *o_ptr;
- const char *q, *s;
- bool status;
- /* Restrict choices Hack - check for restricted choice */
- if ((ammo_type >= TV_SHOT) && (ammo_type <= TV_BOLT))
- item_tester_tval = ammo_type;
- /* Otherwise any ammo will do */
- else
- item_tester_hook = item_tester_hook_ammo;
- /* Get an item */
- q = "Enchant which ammunition? ";
- s = "You have no ammunition to brand.";
- status = get_item(&item, q, s, 0, (USE_EQUIP | USE_INVEN | USE_FLOOR));
- /* Hack - if failed, return, but only after resetting the ammo hack */
- if (!status)
- return (FALSE);
- if (item >= 0) {
- o_ptr = &p_ptr->inventory[item];
- }
- /* Get the item (on the floor) */
- else {
- o_ptr = &o_list[0 - item];
- }
- /*
- * Don't enchant artifacts or ego-items
- */
- if (artifact_p(o_ptr) || ego_item_p(o_ptr)) {
- /* Flush */
- if (OPT(flush_failure))
- flush();
- /* Fail */
- msg("The ammunition enchantment failed.");
- /* Notice */
- return (TRUE);
- }
- /* Type of brand may be restricted */
- if (brand_type)
- choice = brand_type;
- /* Otherwise choose randomly Hack - Never get poison brand randomly */
- else
- choice = randint0(4) + EGO_ACIDIC;
- switch (choice) {
- case EGO_FLAME:
- {
- /* Print message and fire brand missiles. */
- msg("Your missiles are covered in a fiery aura!");
- break;
- }
- case EGO_FROST:
- {
- /* Print message and frost brand missiles. */
- msg("Your missiles are covered in a frosty sheath!");
- break;
- }
- case EGO_ACIDIC:
- {
- /* Print message and acid brand missiles. */
- msg("Your missiles sizzle with acid!");
- break;
- }
- case EGO_ELECT:
- {
- /* Print message and electric brand missiles. */
- msg("Your missiles are covered in sparks!");
- break;
- }
- case EGO_POISON:
- {
- /* Print message and poison brand missiles. */
- msg("Your missiles drip with deadly poison!");
- break;
- }
- default:
- {
- /* Oops */
- return (FALSE);
- }
- }
- /* Brand */
- o_ptr->name2 = choice;
- o_ptr->m…
Large files files are truncated, but you can click here to view the full file