summaryrefslogtreecommitdiff
path: root/src/spells1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/spells1.c')
-rw-r--r--src/spells1.c9327
1 files changed, 0 insertions, 9327 deletions
diff --git a/src/spells1.c b/src/spells1.c
deleted file mode 100644
index 9bfc6fe2..00000000
--- a/src/spells1.c
+++ /dev/null
@@ -1,9327 +0,0 @@
-/* File: spells1.c */
-
-/* Purpose: Spell code (part 1) */
-
-/*
- * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
- *
- * 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.
- */
-
-#include "angband.h"
-
-/* 1/x chance of reducing stats (for elemental attacks) */
-#define HURT_CHANCE 32
-
-/* 1/x chance of hurting even if invulnerable!*/
-#define PENETRATE_INVULNERABILITY 13
-
-/* Maximum number of tries for teleporting */
-#define MAX_TRIES 100
-
-
-/*
- * Helper function -- return a "nearby" race for polymorphing
- *
- * Note that this function is one of the more "dangerous" ones...
- */
-s16b poly_r_idx(int r_idx)
-{
- monster_race *r_ptr = &r_info[r_idx];
-
- int i, r;
-
- /* Hack -- Uniques never polymorph */
- if (r_ptr->flags1 & RF1_UNIQUE)
- return (r_idx);
-
- /* Pick a (possibly new) non-unique race */
- for (i = 0; i < 1000; i++)
- {
- /* Pick a new race, using a level calculation */
- r = get_mon_num((dun_level + r_ptr->level) / 2 + 5);
-
- /* Handle failure */
- if (!r) break;
-
- /* Obtain race */
- r_ptr = &r_info[r];
-
- /* Ignore unique monsters */
- if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
-
- /* Use that index */
- r_idx = r;
-
- /* Done */
- break;
- }
-
- /* Result */
- return (r_idx);
-}
-
-/*
- * Teleport player, using a distance and a direction as a rough guide.
- *
- * This function is not at all obsessive about correctness.
- * This function allows teleporting into vaults (!)
- */
-void teleport_player_directed(int rad, int dir)
-{
- int y = p_ptr->py;
- int x = p_ptr->px;
- int yfoo = ddy[dir];
- int xfoo = ddx[dir];
- int min = rad / 4;
- int dis = rad;
- int i, d;
- bool_ look = TRUE;
- bool_ y_major = FALSE;
- bool_ x_major = FALSE;
- int y_neg = 1;
- int x_neg = 1;
- cave_type *c_ptr;
-
- if (xfoo == 0 && yfoo == 0)
- {
- teleport_player(rad);
- return;
- }
-
- /* Rooted means no move */
- if (p_ptr->tim_roots) return;
-
- if (yfoo == 0) x_major = TRUE;
- if (xfoo == 0) y_major = TRUE;
- if (yfoo < 0) y_neg = -1;
- if (xfoo < 0) x_neg = -1;
-
- /* Look until done */
- while (look)
- {
- /* Verify max distance */
- if (dis > 200)
- {
- teleport_player(rad);
- return;
- }
-
- /* Try several locations */
- for (i = 0; i < 500; i++)
- {
- /* Pick a (possibly illegal) location */
- while (1)
- {
- if (y_major)
- {
- y = rand_spread(p_ptr->py + y_neg * dis / 2, dis / 2);
- }
- else
- {
- y = rand_spread(p_ptr->py, dis / 3);
- }
-
- if (x_major)
- {
- x = rand_spread(p_ptr->px + x_neg * dis / 2, dis / 2);
- }
- else
- {
- x = rand_spread(p_ptr->px, dis / 3);
- }
-
- d = distance(p_ptr->py, p_ptr->px, y, x);
- if ((d >= min) && (d <= dis)) break;
- }
-
- /* Ignore illegal locations */
- if (!in_bounds(y, x)) continue;
-
- /* Require "naked" floor space */
- if (!cave_empty_bold(y, x)) continue;
-
- /* This grid looks good */
- look = FALSE;
-
- /* Stop looking */
- break;
- }
-
- /* Increase the maximum distance */
- dis = dis * 2;
-
- /* Decrease the minimum distance */
- min = min / 2;
-
- }
-
- /* Sound */
- sound(SOUND_TELEPORT);
-
- /* Move player */
- teleport_player_to(y, x);
-
- /* Handle stuff XXX XXX XXX */
- handle_stuff();
-
- c_ptr = &cave[y][x];
-
- /* Hack -- enter a store if we are on one */
- if (c_ptr->feat == FEAT_SHOP)
- {
- /* Disturb */
- disturb(0, 0);
-
- /* Hack -- enter store */
- command_new = '_';
- }
-}
-
-
-/*
- * Teleport a monster, normally up to "dis" grids away.
- *
- * Attempt to move the monster at least "dis/2" grids away.
- *
- * But allow variation to prevent infinite loops.
- */
-void teleport_away(int m_idx, int dis)
-{
- int ny = 0, nx = 0, oy, ox, d, i, min;
- int tries = 0;
-
- bool_ look = TRUE;
-
- monster_type *m_ptr = &m_list[m_idx];
- monster_race *r_ptr = race_inf(m_ptr);
-
- if (p_ptr->resist_continuum)
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- /* Paranoia */
- if (!m_ptr->r_idx) return;
-
- /* Save the old location */
- oy = m_ptr->fy;
- ox = m_ptr->fx;
-
- /* Minimum distance */
- min = dis / 2;
-
- /* Look until done */
- while (look)
- {
- tries++;
-
- /* Verify max distance */
- if (dis > 200) dis = 200;
-
- /* Try several locations */
- for (i = 0; i < 500; i++)
- {
- /* Pick a (possibly illegal) location */
- while (1)
- {
- ny = rand_spread(oy, dis);
- nx = rand_spread(ox, dis);
- d = distance(oy, ox, ny, nx);
- if ((d >= min) && (d <= dis)) break;
- }
-
- /* Ignore illegal locations */
- if (!in_bounds(ny, nx)) continue;
-
- /* Require "empty" floor space */
- if (!cave_empty_bold(ny, nx)) continue;
-
- /* Hack -- no teleport onto glyph of warding */
- if (cave[ny][nx].feat == FEAT_GLYPH) continue;
- if (cave[ny][nx].feat == FEAT_MINOR_GLYPH) continue;
-
- /* ...nor onto the Pattern */
- if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
- (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2)) continue;
-
- /* No teleporting into vaults and such */
- if (!(p_ptr->inside_quest || p_ptr->inside_arena))
- if (cave[ny][nx].info & (CAVE_ICKY)) continue;
-
- /* This grid looks good */
- look = FALSE;
-
- /* Stop looking */
- break;
- }
-
- /* Increase the maximum distance */
- dis = dis * 2;
-
- /* Decrease the minimum distance */
- min = min / 2;
-
- /* Stop after MAX_TRIES tries */
- if (tries > MAX_TRIES) return;
- }
-
- /* Sound */
- sound(SOUND_TPOTHER);
-
- /* Update the new location */
- cave[ny][nx].m_idx = m_idx;
- last_teleportation_y = ny;
- last_teleportation_x = nx;
-
- /* Update the old location */
- cave[oy][ox].m_idx = 0;
-
- /* Move the monster */
- m_ptr->fy = ny;
- m_ptr->fx = nx;
-
- /* Update the monster (new location) */
- update_mon(m_idx, TRUE);
-
- /* Redraw the old grid */
- lite_spot(oy, ox);
-
- /* Redraw the new grid */
- lite_spot(ny, nx);
-
- /* Update monster light */
- if (r_ptr->flags9 & RF9_HAS_LITE) p_ptr->update |= (PU_MON_LITE);
-}
-
-
-/*
- * Teleport monster next to the player
- */
-void teleport_to_player(int m_idx)
-{
- int ny = 0, nx = 0, oy, ox, d, i, min;
- int dis = 2;
-
- bool_ look = TRUE;
-
- monster_type *m_ptr = &m_list[m_idx];
- monster_race *r_ptr = race_inf(m_ptr);
-
- int attempts = 500;
-
- if (p_ptr->resist_continuum)
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- /* Paranoia */
- if (!m_ptr->r_idx) return;
-
- /* "Skill" test */
- if (randint(100) > m_ptr->level) return;
-
- /* Save the old location */
- oy = m_ptr->fy;
- ox = m_ptr->fx;
-
- /* Minimum distance */
- min = dis / 2;
-
- /* Look until done */
- while (look && --attempts)
- {
- /* Verify max distance */
- if (dis > 200) dis = 200;
-
- /* Try several locations */
- for (i = 0; i < 500; i++)
- {
- /* Pick a (possibly illegal) location */
- while (1)
- {
- ny = rand_spread(p_ptr->py, dis);
- nx = rand_spread(p_ptr->px, dis);
- d = distance(p_ptr->py, p_ptr->px, ny, nx);
- if ((d >= min) && (d <= dis)) break;
- }
-
- /* Ignore illegal locations */
- if (!in_bounds(ny, nx)) continue;
-
- /* Require "empty" floor space */
- if (!cave_empty_bold(ny, nx)) continue;
-
- /* Hack -- no teleport onto glyph of warding */
- if (cave[ny][nx].feat == FEAT_GLYPH) continue;
- if (cave[ny][nx].feat == FEAT_MINOR_GLYPH) continue;
-
- /* ...nor onto the Pattern */
- if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
- (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2)) continue;
-
- /* No teleporting into vaults and such */
- /* if (cave[ny][nx].info & (CAVE_ICKY)) continue; */
-
- /* This grid looks good */
- look = FALSE;
-
- /* Stop looking */
- break;
- }
-
- /* Increase the maximum distance */
- dis = dis * 2;
-
- /* Decrease the minimum distance */
- min = min / 2;
- }
-
- if (attempts < 1) return;
-
- /* Sound */
- sound(SOUND_TPOTHER);
-
- /* Update the new location */
- cave[ny][nx].m_idx = m_idx;
- last_teleportation_y = ny;
- last_teleportation_x = nx;
-
- /* Update the old location */
- cave[oy][ox].m_idx = 0;
-
- /* Move the monster */
- m_ptr->fy = ny;
- m_ptr->fx = nx;
-
- /* Update the monster (new location) */
- update_mon(m_idx, TRUE);
-
- /* Redraw the old grid */
- lite_spot(oy, ox);
-
- /* Redraw the new grid */
- lite_spot(ny, nx);
-
- /* Update monster light */
- if (r_ptr->flags9 & RF9_HAS_LITE) p_ptr->update |= (PU_MON_LITE);
-}
-
-
-/*
- * Teleport the player to a location up to "dis" grids away.
- *
- * If no such spaces are readily available, the distance may increase.
- * Try very hard to move the player at least a quarter that distance.
- */
-/* It'd be better if this was made an argument ... */
-bool_ teleport_player_bypass = FALSE;
-
-void teleport_player(int dis)
-{
- int d, i, min, ox, oy, x = 0, y = 0;
- int tries = 0;
-
- int xx = -1, yy = -1;
-
- bool_ look = TRUE;
-
- if (p_ptr->resist_continuum && (!teleport_player_bypass))
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- if (p_ptr->wild_mode) return;
-
- /* Rooted means no move */
- if (p_ptr->tim_roots) return;
-
- if (p_ptr->anti_tele && (!teleport_player_bypass))
- {
- msg_print("A mysterious force prevents you from teleporting!");
- return;
- }
-
- if ((dungeon_flags2 & DF2_NO_TELEPORT) && (!teleport_player_bypass))
- {
- msg_print("No teleport on special levels...");
- return;
- }
-
-
- if (dis > 200) dis = 200; /* To be on the safe side... */
-
- /* Minimum distance */
- min = dis / 2;
-
- /* Look until done */
- while (look)
- {
- tries++;
-
- /* Verify max distance */
- if (dis > 200) dis = 200;
-
- /* Try several locations */
- for (i = 0; i < 500; i++)
- {
- /* Pick a (possibly illegal) location */
- while (1)
- {
- y = rand_spread(p_ptr->py, dis);
- x = rand_spread(p_ptr->px, dis);
- d = distance(p_ptr->py, p_ptr->px, y, x);
- if ((d >= min) && (d <= dis)) break;
- }
-
- /* Ignore illegal locations */
- if (!in_bounds(y, x)) continue;
-
- /* Require "naked" floor space */
- if (!cave_naked_bold(y, x)) continue;
-
- /* No teleporting into vaults and such */
- if (cave[y][x].info & (CAVE_ICKY)) continue;
-
- /* This grid looks good */
- look = FALSE;
-
- /* Stop looking */
- break;
- }
-
- /* Increase the maximum distance */
- dis = dis * 2;
-
- /* Decrease the minimum distance */
- min = min / 2;
-
- /* Stop after MAX_TRIES tries */
- if (tries > MAX_TRIES) return;
- }
-
- /* Sound */
- sound(SOUND_TELEPORT);
-
- /* Save the old location */
- oy = p_ptr->py;
- ox = p_ptr->px;
-
- /* Move the player */
- p_ptr->py = y;
- p_ptr->px = x;
- last_teleportation_y = y;
- last_teleportation_x = x;
-
- /* Redraw the old spot */
- lite_spot(oy, ox);
-
- while (xx < 2)
- {
- yy = -1;
-
- while (yy < 2)
- {
- if (xx == 0 && yy == 0)
- {
- /* Do nothing */
- }
- else
- {
- if (cave[oy + yy][ox + xx].m_idx)
- {
- monster_race *r_ptr = race_inf(&m_list[cave[oy + yy][ox + xx].m_idx]);
-
- if ((r_ptr->flags6
- & RF6_TPORT) &&
- !(r_ptr->flags3
- & RF3_RES_TELE))
- /*
- * The latter limitation is to avoid
- * totally unkillable suckers...
- */
- {
- if (!(m_list[cave[oy + yy][ox + xx].m_idx].csleep))
- teleport_to_player(cave[oy + yy][ox + xx].m_idx);
- }
- }
- }
- yy++;
- }
- xx++;
- }
-
- /* Redraw the new spot */
- lite_spot(p_ptr->py, p_ptr->px);
-
- /* Check for new panel (redraw map) */
- verify_panel();
-
- /* Update stuff */
- p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
-
- /* Update the monsters */
- p_ptr->update |= (PU_DISTANCE);
-
- /* Redraw trap detection status */
- p_ptr->redraw |= (PR_DTRAP);
-
- /* Window stuff */
- p_ptr->window |= (PW_OVERHEAD);
-
- /* Handle stuff XXX XXX XXX */
- handle_stuff();
-}
-
-
-/*
- * get a grid near the given location
- *
- * This function is slightly obsessive about correctness.
- */
-void get_pos_player(int dis, int *ny, int *nx)
-{
- int d, i, min, x = 0, y = 0;
- int tries = 0;
-
- bool_ look = TRUE;
-
- if (dis > 200) dis = 200; /* To be on the safe side... */
-
- /* Minimum distance */
- min = dis / 2;
-
- /* Look until done */
- while (look)
- {
- tries++;
-
- /* Verify max distance */
- if (dis > 200) dis = 200;
-
- /* Try several locations */
- for (i = 0; i < 500; i++)
- {
- /* Pick a (possibly illegal) location */
- while (1)
- {
- y = rand_spread(p_ptr->py, dis);
- x = rand_spread(p_ptr->px, dis);
- d = distance(p_ptr->py, p_ptr->px, y, x);
- if ((d >= min) && (d <= dis)) break;
- }
-
- /* Ignore illegal locations */
- if (!in_bounds(y, x)) continue;
-
- /* Require "naked" floor space */
- if (!cave_naked_bold(y, x)) continue;
-
- /* No teleporting into vaults and such */
- if (cave[y][x].info & (CAVE_ICKY)) continue;
-
- /* This grid looks good */
- look = FALSE;
-
- /* Stop looking */
- break;
- }
-
- /* Increase the maximum distance */
- dis = dis * 2;
-
- /* Decrease the minimum distance */
- min = min / 2;
-
- /* Stop after MAX_TRIES tries */
- if (tries > MAX_TRIES) return;
- }
-
- *ny = y;
- *nx = x;
-}
-
-/*
- * Teleport a monster to a grid near the given location
- *
- * This function is slightly obsessive about correctness.
- */
-void teleport_monster_to(int m_idx, int ny, int nx)
-{
- int y, x, oy, ox, dis = 0, ctr = 0;
- monster_type *m_ptr = &m_list[m_idx];
-
- if (p_ptr->resist_continuum)
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- if (p_ptr->anti_tele)
- {
- msg_print("A mysterious force prevents you from teleporting!");
- return;
- }
-
- /* Find a usable location */
- while (1)
- {
- /* Pick a nearby legal location */
- while (1)
- {
- y = rand_spread(ny, dis);
- x = rand_spread(nx, dis);
- if (in_bounds(y, x)) break;
- }
-
- /* Not on the player's grid */
- /* Accept "naked" floor grids */
- if (cave_naked_bold(y, x) && (y != p_ptr->py) && (x != p_ptr->px)) break;
-
- /* Occasionally advance the distance */
- if (++ctr > (4 * dis * dis + 4 * dis + 1))
- {
- ctr = 0;
- dis++;
- }
- }
-
- /* Sound */
- sound(SOUND_TPOTHER);
-
- /* Save the old position */
- oy = m_ptr->fy;
- ox = m_ptr->fx;
- cave[oy][ox].m_idx = 0;
-
- /* Move the monster */
- m_ptr->fy = y;
- m_ptr->fx = x;
- cave[y][x].m_idx = m_idx;
- last_teleportation_y = y;
- last_teleportation_x = x;
-
- /* Update the monster (new location) */
- update_mon(m_idx, TRUE);
-
- /* Redraw the old spot */
- lite_spot(oy, ox);
-
- /* Redraw the new spot */
- lite_spot(m_ptr->fy, m_ptr->fx);
-}
-
-
-/*
- * Teleport player to a grid near the given location
- *
- * This function is slightly obsessive about correctness.
- * This function allows teleporting into vaults (!)
- */
-void teleport_player_to(int ny, int nx)
-{
- int y, x, oy, ox, dis = 0, ctr = 0;
-
- if (p_ptr->resist_continuum)
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- if (p_ptr->anti_tele)
- {
- msg_print("A mysterious force prevents you from teleporting!");
- return;
- }
-
- if (dungeon_flags2 & DF2_NO_TELEPORT)
- {
- msg_print("No teleport on special levels...");
- return;
- }
-
- /* Rooted means no move */
- if (p_ptr->tim_roots) return;
-
- /* Find a usable location */
- while (1)
- {
- /* Pick a nearby legal location */
- while (1)
- {
- y = rand_spread(ny, dis);
- x = rand_spread(nx, dis);
- if (in_bounds(y, x)) break;
- }
-
- /* Accept "naked" floor grids */
- if (cave_naked_bold2(y, x)) break;
-
- /* Occasionally advance the distance */
- if (++ctr > (4 * dis * dis + 4 * dis + 1))
- {
- ctr = 0;
- dis++;
- }
- }
-
- /* Sound */
- sound(SOUND_TELEPORT);
-
- /* Save the old location */
- oy = p_ptr->py;
- ox = p_ptr->px;
-
- /* Move the player */
- p_ptr->py = y;
- p_ptr->px = x;
- last_teleportation_y = y;
- last_teleportation_x = x;
-
- /* Redraw the old spot */
- lite_spot(oy, ox);
-
- /* Redraw the new spot */
- lite_spot(p_ptr->py, p_ptr->px);
-
- /* Check for new panel (redraw map) */
- verify_panel();
-
- /* Update stuff */
- p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE);
-
- /* Update the monsters */
- p_ptr->update |= (PU_DISTANCE);
-
- /* Redraw trap detection status */
- p_ptr->redraw |= (PR_DTRAP);
-
- /* Window stuff */
- p_ptr->window |= (PW_OVERHEAD);
-
- /* Handle stuff XXX XXX XXX */
- handle_stuff();
-}
-
-
-
-/*
- * Teleport the player one level up or down (random when legal)
- */
-void teleport_player_level(void)
-{
- /* No effect in arena or quest */
- if (p_ptr->inside_arena || p_ptr->inside_quest)
- {
- msg_print("There is no effect.");
- return;
- }
- if (dungeon_flags2 & DF2_NO_TELEPORT)
- {
- msg_print("No teleport on special levels...");
- return;
- }
- if (dungeon_flags2 & DF2_NO_EASY_MOVE)
- {
- msg_print("Some powerfull force prevents your from teleporting.");
- return;
- }
-
- if (p_ptr->resist_continuum)
- {
- msg_print("The space-time continuum can't be disrupted.");
- return;
- }
-
- /* Hack -- when you are fated to die, you cant cheat :) */
- if (dungeon_type == DUNGEON_DEATH)
- {
- msg_print("A mysterious force prevents you from teleporting!");
- return;
- }
-
- if (p_ptr->anti_tele)
- {
- msg_print("A mysterious force prevents you from teleporting!");
- return;
- }
-
- /* Rooted means no move */
- if (p_ptr->tim_roots) return;
-
- if (!dun_level)
- {
- msg_print("You sink through the floor.");
-
- autosave_checkpoint();
-
- dun_level++;
-
- /* Leaving */
- p_ptr->leaving = TRUE;
- }
- else if (is_quest(dun_level) || (dun_level >= MAX_DEPTH - 1))
- {
- msg_print("You rise up through the ceiling.");
-
- autosave_checkpoint();
-
- dun_level--;
-
- /* Leaving */
- p_ptr->leaving = TRUE;
- }
- else if (rand_int(100) < 50)
- {
- msg_print("You rise up through the ceiling.");
-
- autosave_checkpoint();
-
- dun_level--;
-
- /* Leaving */
- p_ptr->leaving = TRUE;
- }
- else
- {
- msg_print("You sink through the floor.");
-
- autosave_checkpoint();
-
- dun_level++;
-
- /* Leaving */
- p_ptr->leaving = TRUE;
- }
-
- /* Sound */
- sound(SOUND_TPLEVEL);
-}
-
-
-
-/*
- * Recall the player to town or dungeon
- */
-void recall_player(int d, int f)
-{
- /* Rooted means no move */
- if (p_ptr->tim_roots)
- {
- msg_print("Your roots prevent the recall.");
- return;
- }
-
-
- if (dun_level && (max_dlv[dungeon_type] > dun_level) &&
- !p_ptr->inside_quest)
- {
- if (get_check("Reset recall depth? "))
- max_dlv[dungeon_type] = dun_level;
-
- }
- if (!p_ptr->word_recall)
- {
- p_ptr->word_recall = rand_int(d) + f;
- msg_print("The air about you becomes charged...");
- }
- else
- {
- p_ptr->word_recall = 0;
- msg_print("A tension leaves the air around you...");
- }
- p_ptr->redraw |= (PR_DEPTH);
-}
-
-
-
-/*
- * Get a legal "multi-hued" color for drawing "spells"
- */
-static byte mh_attr(int max)
-{
- switch (randint(max))
- {
- case 1:
- return (TERM_RED);
- case 2:
- return (TERM_GREEN);
- case 3:
- return (TERM_BLUE);
- case 4:
- return (TERM_YELLOW);
- case 5:
- return (TERM_ORANGE);
- case 6:
- return (TERM_VIOLET);
- case 7:
- return (TERM_L_RED);
- case 8:
- return (TERM_L_GREEN);
- case 9:
- return (TERM_L_BLUE);
- case 10:
- return (TERM_UMBER);
- case 11:
- return (TERM_L_UMBER);
- case 12:
- return (TERM_SLATE);
- case 13:
- return (TERM_WHITE);
- case 14:
- return (TERM_L_WHITE);
- case 15:
- return (TERM_L_DARK);
- }
-
- return (TERM_WHITE);
-}
-
-
-/*
- * Return a color to use for the bolt/ball spells
- */
-byte spell_color(int type)
-{
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_COLOR, "d", "(d,d)", type, streq(ANGBAND_GRAF, "new")))
- {
- return process_hooks_return[0].num;
- }
-
- /* Check if A.B.'s new graphics should be used (rr9) */
- if (streq(ANGBAND_GRAF, "new"))
- {
- /* Analyze */
- switch (type)
- {
- case GF_MISSILE:
- return (0x0F);
- case GF_ACID:
- return (0x04);
- case GF_ELEC:
- return (0x02);
- case GF_FIRE:
- return (0x00);
- case GF_COLD:
- return (0x01);
- case GF_POIS:
- return (0x03);
- case GF_UNBREATH:
- return (0x03);
- case GF_HOLY_FIRE:
- return (0x00);
- case GF_HELL_FIRE:
- return (0x00);
- case GF_MANA:
- return (0x0E);
- case GF_ARROW:
- return (0x0F);
- case GF_WATER:
- return (0x04);
- case GF_WAVE:
- return (0x04);
- case GF_NETHER:
- return (0x07);
- case GF_CHAOS:
- return (mh_attr(15));
- case GF_DISENCHANT:
- return (0x05);
- case GF_NEXUS:
- return (0x0C);
- case GF_CONFUSION:
- return (mh_attr(4));
- case GF_SOUND:
- return (0x09);
- case GF_SHARDS:
- return (0x08);
- case GF_FORCE:
- return (0x09);
- case GF_INERTIA:
- return (0x09);
- case GF_GRAVITY:
- return (0x09);
- case GF_TIME:
- return (0x09);
- case GF_LITE_WEAK:
- return (0x06);
- case GF_LITE:
- return (0x06);
- case GF_DARK_WEAK:
- return (0x07);
- case GF_DARK:
- return (0x07);
- case GF_PLASMA:
- return (0x0B);
- case GF_METEOR:
- return (0x00);
- case GF_ICE:
- return (0x01);
- case GF_ROCKET:
- return (0x0F);
- case GF_DEATH_RAY:
- return (0x07);
- case GF_NUKE:
- return (mh_attr(2));
- case GF_DISINTEGRATE:
- return (0x05);
- case GF_PSI:
- case GF_PSI_DRAIN:
- case GF_TELEKINESIS:
- case GF_DOMINATION:
- return (0x09);
- }
-
- }
-
- /* Normal tiles or ASCII */
- else
- {
- /* Analyze */
- switch (type)
- {
- case GF_MISSILE:
- return (TERM_SLATE);
- case GF_ACID:
- return (randint(5) < 3 ? TERM_YELLOW : TERM_L_GREEN);
- case GF_ELEC:
- return (randint(7) < 6 ? TERM_WHITE : (randint(4) == 1 ? TERM_BLUE : TERM_L_BLUE));
- case GF_FIRE:
- return (randint(6) < 4 ? TERM_YELLOW : (randint(4) == 1 ? TERM_RED : TERM_L_RED));
- case GF_COLD:
- return (randint(6) < 4 ? TERM_WHITE : TERM_L_WHITE);
- case GF_POIS:
- return (randint(5) < 3 ? TERM_L_GREEN : TERM_GREEN);
- case GF_UNBREATH:
- return (randint(7) < 3 ? TERM_L_GREEN : TERM_GREEN);
- case GF_HOLY_FIRE:
- return (randint(5) == 1 ? TERM_ORANGE : TERM_WHITE);
- case GF_HELL_FIRE:
- return (randint(6) == 1 ? TERM_RED : TERM_L_DARK);
- case GF_MANA:
- return (randint(5) != 1 ? TERM_VIOLET : TERM_L_BLUE);
- case GF_ARROW:
- return (TERM_L_UMBER);
- case GF_WATER:
- return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
- case GF_WAVE:
- return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
- case GF_NETHER:
- return (randint(4) == 1 ? TERM_SLATE : TERM_L_DARK);
- case GF_CHAOS:
- return (mh_attr(15));
- case GF_DISENCHANT:
- return (randint(5) != 1 ? TERM_L_BLUE : TERM_VIOLET);
- case GF_NEXUS:
- return (randint(5) < 3 ? TERM_L_RED : TERM_VIOLET);
- case GF_CONFUSION:
- return (mh_attr(4));
- case GF_SOUND:
- return (randint(4) == 1 ? TERM_VIOLET : TERM_WHITE);
- case GF_SHARDS:
- return (randint(5) < 3 ? TERM_UMBER : TERM_SLATE);
- case GF_FORCE:
- return (randint(5) < 3 ? TERM_L_WHITE : TERM_ORANGE);
- case GF_INERTIA:
- return (randint(5) < 3 ? TERM_SLATE : TERM_L_WHITE);
- case GF_GRAVITY:
- return (randint(3) == 1 ? TERM_L_UMBER : TERM_UMBER);
- case GF_TIME:
- return (randint(2) == 1 ? TERM_WHITE : TERM_L_DARK);
- case GF_LITE_WEAK:
- return (randint(3) == 1 ? TERM_ORANGE : TERM_YELLOW);
- case GF_LITE:
- return (randint(4) == 1 ? TERM_ORANGE : TERM_YELLOW);
- case GF_DARK_WEAK:
- return (randint(3) == 1 ? TERM_DARK : TERM_L_DARK);
- case GF_DARK:
- return (randint(4) == 1 ? TERM_DARK : TERM_L_DARK);
- case GF_PLASMA:
- return (randint(5) == 1 ? TERM_RED : TERM_L_RED);
- case GF_METEOR:
- return (randint(3) == 1 ? TERM_RED : TERM_UMBER);
- case GF_ICE:
- return (randint(4) == 1 ? TERM_L_BLUE : TERM_WHITE);
- case GF_ROCKET:
- return (randint(6) < 4 ? TERM_L_RED : (randint(4) == 1 ? TERM_RED : TERM_L_UMBER));
- case GF_DEATH:
- case GF_DEATH_RAY:
- return (TERM_L_DARK);
- case GF_NUKE:
- return (mh_attr(2));
- case GF_DISINTEGRATE:
- return (randint(3) != 1 ? TERM_L_DARK : (randint(2) == 1 ? TERM_ORANGE : TERM_L_UMBER));
- case GF_PSI:
- case GF_PSI_DRAIN:
- case GF_TELEKINESIS:
- case GF_DOMINATION:
- return (randint(3) != 1 ? TERM_L_BLUE : TERM_WHITE);
- }
- }
-
- /* Standard "color" */
- return (TERM_WHITE);
-}
-
-
-/*
- * Find the attr/char pair to use for a spell effect
- *
- * It is moving (or has moved) from (x,y) to (nx,ny).
- *
- * If the distance is not "one", we (may) return "*".
- */
-static u16b bolt_pict(int y, int x, int ny, int nx, int typ)
-{
- int base;
-
- byte k;
-
- byte a;
- char c;
-
- /* No motion (*) */
- if ((ny == y) && (nx == x)) base = 0x30;
-
- /* Vertical (|) */
- else if (nx == x) base = 0x40;
-
- /* Horizontal (-) */
- else if (ny == y) base = 0x50;
-
- /* Diagonal (/) */
- else if ((ny - y) == (x - nx)) base = 0x60;
-
- /* Diagonal (\) */
- else if ((ny - y) == (nx - x)) base = 0x70;
-
- /* Weird (*) */
- else base = 0x30;
-
- /* Basic spell color */
- k = spell_color(typ);
-
- /* Obtain attr/char */
- a = misc_to_attr[base + k];
- c = misc_to_char[base + k];
-
- /* Create pict */
- return (PICT(a, c));
-}
-
-/*
- * Cast the spelbound spells
- */
-void spellbinder_trigger()
-{
- int i;
-
- cmsg_print(TERM_L_GREEN, "The spellbinder is triggered!");
- for (i = 0; i < p_ptr->spellbinder_num; i++)
- {
- msg_format("Triggering spell %s.", school_spells[p_ptr->spellbinder[i]].name);
- exec_lua(format("cast_school_spell(%d, spell(%d), TRUE)", p_ptr->spellbinder[i], p_ptr->spellbinder[i]));
- }
- p_ptr->spellbinder_num = 0;
- p_ptr->spellbinder_trigger = 0;
-}
-
-
-/*
- * Decreases players hit points and sets death flag if necessary
- *
- * XXX XXX XXX Invulnerability needs to be changed into a "shield"
- *
- * XXX XXX XXX Hack -- this function allows the user to save (or quit)
- * the game when he dies, since the "You die." message is shown before
- * setting the player to "dead".
- */
-void take_hit(int damage, cptr hit_from)
-{
- object_type *o_ptr = &p_ptr->inventory[INVEN_CARRY];
- int old_chp = p_ptr->chp;
-
- bool_ pen_invuln = FALSE;
- bool_ monster_take = FALSE;
-
- char death_message[80];
-
- int warning = (p_ptr->mhp * hitpoint_warn / 10);
- int percent;
-
- /* Paranoia */
- if (death) return;
-
- /* Disturb */
- disturb(1, 0);
-
- /* Apply "invulnerability" */
- if (p_ptr->invuln && (damage < 9000))
- {
- if (randint(PENETRATE_INVULNERABILITY) == 1)
- {
- pen_invuln = TRUE;
- }
- else
- {
- return;
- }
- }
-
- /* Apply disruption shield */
- if (p_ptr->disrupt_shield)
- {
- if (p_ptr->csp > (damage * 2))
- {
- p_ptr->csp -= (damage * 2);
- damage = 0;
- }
- else
- {
- damage -= p_ptr->csp / 2;
- p_ptr->csp = 0;
- p_ptr->csp_frac = 0;
- }
-
- /* Display the mana */
- p_ptr->redraw |= (PR_MANA);
- }
-
- /* Hurt the wielded monster if any */
- if ((o_ptr->k_idx) && (magik(5 + get_skill(SKILL_SYMBIOTIC))) && (!carried_monster_hit))
- {
- cptr sym_name = symbiote_name(TRUE);
-
- if (o_ptr->pval2 - damage <= 0)
- {
- cmsg_format(TERM_L_RED,
- "%s dies from protecting you, you feel very sad...",
- sym_name);
- inc_stack_size_ex(INVEN_CARRY, -1, OPTIMIZE, NO_DESCRIBE);
- damage -= o_ptr->pval2;
- o_ptr->pval2 = 0;
- p_ptr->redraw |= PR_MH;
- }
- else
- {
- msg_format("%s takes the damage instead of you.", sym_name);
- o_ptr->pval2 -= damage;
- monster_take = TRUE;
- }
-
- carried_monster_hit = FALSE;
-
- /* Display the monster hitpoints */
- p_ptr->redraw |= (PR_MH);
- }
-
- /* Hurt the player */
- if (!monster_take) p_ptr->chp -= damage;
-
- /* Display the hitpoints */
- p_ptr->redraw |= (PR_HP);
-
- /* Window stuff */
- p_ptr->window |= (PW_PLAYER);
-
- if (pen_invuln)
- cmsg_print(TERM_YELLOW, "The attack penetrates your shield of invulnerability!");
-
- /* Dead player */
- if (p_ptr->chp < 0)
- {
- /* Necromancers get a special treatment */
- if (((!has_ability(AB_UNDEAD_FORM)) || ((p_ptr->necro_extra & CLASS_UNDEAD))))
- {
- /* Sound */
- sound(SOUND_DEATH);
-
- /* Hack -- Note death */
- if (!last_words)
- {
- cmsg_print(TERM_RED, "You die.");
- msg_print(NULL);
- }
- else
- {
- (void)get_rnd_line("death.txt", death_message);
- cmsg_print(TERM_RED, death_message);
- }
-
- /* Note cause of death */
- (void)strcpy(died_from, hit_from);
-
- if (p_ptr->image) strcat(died_from, "(?)");
-
- /* Leaving */
- p_ptr->leaving = TRUE;
-
- /* No longer a winner */
- total_winner = FALSE;
-
-
- /* Note death */
- death = TRUE;
-
- if (get_check("Dump the screen? "))
- {
- do_cmd_html_dump();
- }
-
- /* Dead */
- return;
- }
- /* Just turn the necromancer into an undead */
- else
- {
- p_ptr->necro_extra |= CLASS_UNDEAD;
- p_ptr->necro_extra2 = p_ptr->lev + (rand_int(p_ptr->lev / 2) - (p_ptr->lev / 4));
- if (p_ptr->necro_extra2 < 1) p_ptr->necro_extra2 = 1;
- cmsg_format(TERM_L_DARK, "You have to kill %d monster%s to be brought back to life.", p_ptr->necro_extra2, (p_ptr->necro_extra2 == 1) ? "" : "s");
-
- /* MEGA-HACK !!! */
- calc_hitpoints();
-
- /* Enforce maximum */
- p_ptr->chp = p_ptr->mhp;
- p_ptr->chp_frac = 0;
-
- do_cmd_wiz_cure_all();
-
- /* Display the hitpoints */
- p_ptr->redraw |= (PR_HP);
-
- /* Window stuff */
- p_ptr->window |= (PW_PLAYER);
- }
- }
-
- /* Hitpoint warning */
- if (p_ptr->chp < warning)
- {
- /* Hack -- bell on first notice */
- if (alert_hitpoint && (old_chp > warning)) bell();
-
- sound(SOUND_WARN);
-
- /* Message */
- if (p_ptr->necro_extra & CLASS_UNDEAD)
- cmsg_print(TERM_RED, "*** LOW DEATHPOINT WARNING! ***");
- else
- cmsg_print(TERM_RED, "*** LOW HITPOINT WARNING! ***");
- msg_print(NULL);
- }
-
- /* How much life is left ? */
- percent = p_ptr->chp * 100 / p_ptr->mhp;
-
- /* Check the spellbinder trigger */
- if (p_ptr->spellbinder_trigger == SPELLBINDER_HP75)
- {
- /* Trigger ?! */
- if (percent <= 75)
- spellbinder_trigger();
- }
- else if (p_ptr->spellbinder_trigger == SPELLBINDER_HP50)
- {
- /* Trigger ?! */
- if (percent <= 50)
- spellbinder_trigger();
- }
- else if (p_ptr->spellbinder_trigger == SPELLBINDER_HP25)
- {
- /* Trigger ?! */
- if (percent <= 25)
- spellbinder_trigger();
- }
-
- /* Melkor acn summon to help you */
- if (percent < 25)
- {
- PRAY_GOD(GOD_MELKOR)
- {
- int chance = p_ptr->grace / 500; /* * 100 / 50000; */
-
- if (magik(chance - 10))
- {
- int i;
- int type = SUMMON_DEMON;
-
- if (magik(50))
- type = SUMMON_UNDEAD;
-
- if (p_ptr->grace > 10000)
- {
- if (type == SUMMON_DEMON)
- type = SUMMON_HI_DEMON;
- else
- type = SUMMON_HI_UNDEAD;
- }
-
- chance /= 10;
- if (chance < 1) chance = 1;
- for (i = 0; i < chance; i++)
- summon_specific_friendly(p_ptr->py, p_ptr->px, dun_level / 2, type, FALSE);
- msg_print("Melkor summons monsters to help you!");
- }
- }
- }
-
- if (player_char_health)
- lite_spot(p_ptr->py, p_ptr->px);
-}
-
-
-/* Decrease player's sanity. This is a copy of the function above. */
-void take_sanity_hit(int damage, cptr hit_from)
-{
- int old_csane = p_ptr->csane;
-
- char death_message[80];
-
- int warning = (p_ptr->msane * hitpoint_warn / 10);
-
-
- /* Paranoia */
- if (death) return;
-
- /* Disturb */
- disturb(1, 0);
-
-
- /* Hurt the player */
- p_ptr->csane -= damage;
-
- /* Display the hitpoints */
- p_ptr->redraw |= (PR_SANITY);
-
- /* Window stuff */
- p_ptr->window |= (PW_PLAYER);
-
- /* Dead player */
- if (p_ptr->csane < 0)
- {
- /* Sound */
- sound(SOUND_DEATH);
-
- /* Hack -- Note death */
- cmsg_print(TERM_VIOLET, "You turn into an unthinking vegetable.");
- if (!last_words)
- {
- cmsg_print(TERM_RED, "You die.");
- msg_print(NULL);
- }
- else
- {
- (void)get_rnd_line("death.txt", death_message);
- cmsg_print(TERM_RED, death_message);
- }
-
- /* Note cause of death */
- (void)strcpy(died_from, hit_from);
-
- if (p_ptr->image) strcat(died_from, "(?)");
-
- /* Leaving */
- p_ptr->leaving = TRUE;
-
- /* Note death */
- death = TRUE;
-
- if (get_check("Dump the screen? "))
- {
- do_cmd_html_dump();
- }
-
- /* Dead */
- return;
- }
-
- /* Hitpoint warning */
- if (p_ptr->csane < warning)
- {
- /* Hack -- bell on first notice */
- if (alert_hitpoint && (old_csane > warning)) bell();
-
- sound(SOUND_WARN);
-
- /* Message */
- cmsg_print(TERM_RED, "*** LOW SANITY WARNING! ***");
- msg_print(NULL);
- }
-}
-
-
-/*
- * Note that amulets, rods, and high-level spell books are immune
- * to "inventory damage" of any kind. Also sling ammo and shovels.
- */
-
-
-/*
- * Does a given class of objects (usually) hate acid?
- * Note that acid can either melt or corrode something.
- */
-static bool_ hates_acid(object_type *o_ptr)
-{
- /* Analyze the type */
- switch (o_ptr->tval)
- {
- /* Wearable items */
- case TV_ARROW:
- case TV_BOLT:
- case TV_BOW:
- case TV_SWORD:
- case TV_AXE:
- case TV_HAFTED:
- case TV_POLEARM:
- case TV_HELM:
- case TV_CROWN:
- case TV_SHIELD:
- case TV_BOOTS:
- case TV_GLOVES:
- case TV_CLOAK:
- case TV_SOFT_ARMOR:
- case TV_HARD_ARMOR:
- case TV_DRAG_ARMOR:
- {
- return (TRUE);
- }
-
- /* Staffs/Scrolls are wood/paper */
- case TV_STAFF:
- case TV_SCROLL:
- {
- return (TRUE);
- }
-
- /* Ouch */
- case TV_CHEST:
- {
- return (TRUE);
- }
-
- /* Junk is useless */
- case TV_SKELETON:
- case TV_BOTTLE:
- case TV_EGG:
- {
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-
-/*
- * Does a given object (usually) hate electricity?
- */
-static bool_ hates_elec(object_type *o_ptr)
-{
- switch (o_ptr->tval)
- {
- case TV_RING:
- case TV_WAND:
- case TV_EGG:
- {
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-
-/*
- * Does a given object (usually) hate fire?
- * Hafted/Polearm weapons have wooden shafts.
- * Arrows/Bows are mostly wooden.
- */
-static bool_ hates_fire(object_type *o_ptr)
-{
- /* Analyze the type */
- switch (o_ptr->tval)
- {
- /* Special case for archers */
- case TV_ARROW:
- {
- return TRUE;
- };
-
- /* Wearable */
- case TV_LITE:
- case TV_BOW:
- case TV_HAFTED:
- case TV_POLEARM:
- case TV_BOOTS:
- case TV_GLOVES:
- case TV_CLOAK:
- case TV_SOFT_ARMOR:
- {
- return (TRUE);
- }
-
- /* Books */
- case TV_BOOK:
- case TV_SYMBIOTIC_BOOK:
- case TV_MUSIC_BOOK:
- {
- return (TRUE);
- }
-
- /* Chests */
- case TV_CHEST:
- {
- return (TRUE);
- }
-
- /* Staffs/Scrolls burn */
- case TV_STAFF:
- case TV_SCROLL:
- case TV_EGG:
- {
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-
-/*
- * Does a given object (usually) hate cold?
- */
-static bool_ hates_cold(object_type *o_ptr)
-{
- switch (o_ptr->tval)
- {
- case TV_POTION2:
- case TV_POTION:
- case TV_FLASK:
- case TV_BOTTLE:
- case TV_EGG:
- {
- return (TRUE);
- }
- }
-
- return (FALSE);
-}
-
-
-
-
-
-
-
-
-
-/*
- * Melt something
- */
-static int set_acid_destroy(object_type *o_ptr)
-{
- u32b f1, f2, f3, f4, f5, esp;
-
- if (!hates_acid(o_ptr)) return (FALSE);
-
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
- if (f3 & (TR3_IGNORE_ACID)) return (FALSE);
- return (TRUE);
-}
-
-
-/*
- * Electrical damage
- */
-static int set_elec_destroy(object_type *o_ptr)
-{
- u32b f1, f2, f3, f4, f5, esp;
-
- if (!hates_elec(o_ptr)) return (FALSE);
-
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
- if (f3 & (TR3_IGNORE_ELEC)) return (FALSE);
- return (TRUE);
-}
-
-
-/*
- * Burn something
- */
-static int set_fire_destroy(object_type *o_ptr)
-{
- u32b f1, f2, f3, f4, f5, esp;
-
- if (!hates_fire(o_ptr)) return (FALSE);
-
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
- if (f3 & (TR3_IGNORE_FIRE)) return (FALSE);
- return (TRUE);
-}
-
-
-/*
- * Freeze things
- */
-static int set_cold_destroy(object_type *o_ptr)
-{
- u32b f1, f2, f3, f4, f5, esp;
-
- if (!hates_cold(o_ptr)) return (FALSE);
-
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
- if (f3 & (TR3_IGNORE_COLD)) return (FALSE);
- return (TRUE);
-}
-
-
-
-
-/*
- * This seems like a pretty standard "typedef"
- */
-typedef int (*inven_func)(object_type *);
-
-/*
- * Destroys a type of item on a given percent chance
- * Note that missiles are no longer necessarily all destroyed
- * Destruction taken from "melee.c" code for "stealing".
- * Returns number of items destroyed.
- */
-static int inven_damage(inven_func typ, int perc)
-{
- int i, j, k, amt;
-
- object_type *o_ptr;
-
- char o_name[80];
-
-
- /* Count the casualties */
- k = 0;
-
- /* Scan through the slots backwards */
- for (i = 0; i < INVEN_PACK; i++)
- {
- o_ptr = &p_ptr->inventory[i];
-
- /* Skip non-objects */
- if (!o_ptr->k_idx) continue;
-
- /* Hack -- for now, skip artifacts */
- if (artifact_p(o_ptr) || o_ptr->art_name) continue;
-
- /* Give this item slot a shot at death */
- if ((*typ)(o_ptr))
- {
- /* Count the casualties */
- for (amt = j = 0; j < o_ptr->number; ++j)
- {
- if (rand_int(100) < perc) amt++;
- }
-
- /* Some casualities */
- if (amt)
- {
- /* Get a description */
- object_desc(o_name, o_ptr, FALSE, 3);
-
- /* Message */
- msg_format("%sour %s (%c) %s destroyed!",
- ((o_ptr->number > 1) ?
- ((amt == o_ptr->number) ? "All of y" :
- (amt > 1 ? "Some of y" : "One of y")) : "Y"),
- o_name, index_to_label(i),
- ((amt > 1) ? "were" : "was"));
-
- /* Potions smash open */
- if (k_info[o_ptr->k_idx].tval == TV_POTION)
- {
- (void)potion_smash_effect(0, p_ptr->py, p_ptr->px, o_ptr->sval);
- }
-
- /*
- * Hack -- If rods or wand are destroyed, the total maximum
- * timeout or charges of the stack needs to be reduced,
- * unless all the items are being destroyed. -LM-
- */
- if ((o_ptr->tval == TV_WAND)
- && (amt < o_ptr->number))
- {
- o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
- }
-
- /* Destroy "amt" items */
- inc_stack_size_ex(i, -amt, OPTIMIZE, NO_DESCRIBE);
-
- /* Count the casualties */
- k += amt;
- }
- }
- }
-
- /* Return the casualty count */
- return (k);
-}
-
-
-
-
-/*
- * Acid has hit the player, attempt to affect some armor.
- *
- * Note that the "base armor" of an object never changes.
- *
- * If any armor is damaged (or resists), the player takes less damage.
- */
-static int minus_ac(void)
-{
- object_type *o_ptr = NULL;
-
- u32b f1, f2, f3, f4, f5, esp;
-
- char o_name[80];
-
-
- /* Pick a (possibly empty) inventory slot */
- switch (randint(6))
- {
- case 1:
- o_ptr = &p_ptr->inventory[INVEN_BODY];
- break;
- case 2:
- o_ptr = &p_ptr->inventory[INVEN_ARM];
- break;
- case 3:
- o_ptr = &p_ptr->inventory[INVEN_OUTER];
- break;
- case 4:
- o_ptr = &p_ptr->inventory[INVEN_HANDS];
- break;
- case 5:
- o_ptr = &p_ptr->inventory[INVEN_HEAD];
- break;
- case 6:
- o_ptr = &p_ptr->inventory[INVEN_FEET];
- break;
- }
-
- /* Nothing to damage */
- if (!o_ptr->k_idx) return (FALSE);
-
- /* No damage left to be done */
- if (o_ptr->ac + o_ptr->to_a <= 0) return (FALSE);
-
-
- /* Describe */
- object_desc(o_name, o_ptr, FALSE, 0);
-
- /* Extract the flags */
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
-
- /* Object resists */
- if (f3 & (TR3_IGNORE_ACID))
- {
- msg_format("Your %s is unaffected!", o_name);
-
- return (TRUE);
- }
-
- /* Message */
- msg_format("Your %s is damaged!", o_name);
-
- /* Damage the item */
- o_ptr->to_a--;
-
- /* Calculate bonuses */
- p_ptr->update |= (PU_BONUS);
-
- /* Window stuff */
- p_ptr->window |= (PW_EQUIP | PW_PLAYER);
-
- /* Item was damaged */
- return (TRUE);
-}
-
-
-/*
- * Hurt the player with Acid
- */
-void acid_dam(int dam, cptr kb_str)
-{
- int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
-
- /* Total Immunity */
- if (p_ptr->immune_acid || (dam <= 0)) return;
-
- /* Resist the damage */
- if (p_ptr->resist_acid) dam = (dam + 2) / 3;
- if (p_ptr->oppose_acid) dam = (dam + 2) / 3;
-
- if ((!(p_ptr->oppose_acid || p_ptr->resist_acid)) &&
- randint(HURT_CHANCE) == 1)
- (void) do_dec_stat(A_CHR, STAT_DEC_NORMAL);
-
- /* If any armor gets hit, defend the player */
- if (minus_ac()) dam = (dam + 1) / 2;
-
- /* Take damage */
- take_hit(dam, kb_str);
-
- /* Inventory damage */
- if (!(p_ptr->oppose_acid && p_ptr->resist_acid))
- inven_damage(set_acid_destroy, inv);
-}
-
-
-/*
- * Hurt the player with electricity
- */
-void elec_dam(int dam, cptr kb_str)
-{
- int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
-
- /* Total immunity */
- if (p_ptr->immune_elec || (dam <= 0)) return;
-
- /* Resist the damage */
- if (p_ptr->oppose_elec) dam = (dam + 2) / 3;
- if (p_ptr->resist_elec) dam = (dam + 2) / 3;
-
- if ((!(p_ptr->oppose_elec || p_ptr->resist_elec)) &&
- randint(HURT_CHANCE) == 1)
- (void) do_dec_stat(A_DEX, STAT_DEC_NORMAL);
-
- /* Take damage */
- take_hit(dam, kb_str);
-
- /* Inventory damage */
- if (!(p_ptr->oppose_elec && p_ptr->resist_elec))
- inven_damage(set_elec_destroy, inv);
-}
-
-
-
-
-/*
- * Hurt the player with Fire
- */
-void fire_dam(int dam, cptr kb_str)
-{
- int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
-
- /* Totally immune */
- if (p_ptr->immune_fire || (dam <= 0)) return;
-
- /* Resist the damage */
- if (p_ptr->sensible_fire) dam = (dam + 2) * 2;
- if (p_ptr->resist_fire) dam = (dam + 2) / 3;
- if (p_ptr->oppose_fire) dam = (dam + 2) / 3;
-
- if ((!(p_ptr->oppose_fire || p_ptr->resist_fire)) &&
- randint(HURT_CHANCE) == 1)
- (void) do_dec_stat(A_STR, STAT_DEC_NORMAL);
-
-
- /* Take damage */
- take_hit(dam, kb_str);
-
- /* Inventory damage */
- if (!(p_ptr->resist_fire && p_ptr->oppose_fire))
- inven_damage(set_fire_destroy, inv);
-}
-
-
-/*
- * Hurt the player with Cold
- */
-void cold_dam(int dam, cptr kb_str)
-{
- int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
-
- /* Total immunity */
- if (p_ptr->immune_cold || (dam <= 0)) return;
-
- /* Resist the damage */
- if (p_ptr->resist_cold) dam = (dam + 2) / 3;
- if (p_ptr->oppose_cold) dam = (dam + 2) / 3;
-
- if ((!(p_ptr->oppose_cold || p_ptr->resist_cold)) &&
- randint(HURT_CHANCE) == 1)
- (void) do_dec_stat(A_STR, STAT_DEC_NORMAL);
-
- /* Take damage */
- take_hit(dam, kb_str);
-
- /* Inventory damage */
- if (!(p_ptr->resist_cold && p_ptr->oppose_cold))
- inven_damage(set_cold_destroy, inv);
-}
-
-
-
-
-
-/*
- * Increases a stat by one randomized level -RAK-
- *
- * Note that this function (used by stat potions) now restores
- * the stat BEFORE increasing it.
- */
-bool_ inc_stat(int stat)
-{
- int value, gain;
-
- /* Then augment the current/max stat */
- value = p_ptr->stat_cur[stat];
-
- /* Cannot go above 18/100 */
- if (value < 18 + 100)
- {
- /* Gain one (sometimes two) points */
- if (value < 18)
- {
- gain = ((rand_int(100) < 75) ? 1 : 2);
- value += gain;
- }
-
- /* Gain 1/6 to 1/3 of distance to 18/100 */
- else if (value < 18 + 98)
- {
- /* Approximate gain value */
- gain = (((18 + 100) - value) / 2 + 3) / 2;
-
- /* Paranoia */
- if (gain < 1) gain = 1;
-
- /* Apply the bonus */
- value += randint(gain) + gain / 2;
-
- /* Maximal value */
- if (value > 18 + 99) value = 18 + 99;
- }
-
- /* Gain one point at a time */
- else
- {
- value++;
- }
-
- /* Save the new value */
- p_ptr->stat_cur[stat] = value;
-
- /* Bring up the maximum too */
- if (value > p_ptr->stat_max[stat])
- {
- p_ptr->stat_max[stat] = value;
- }
-
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
-
- /* Success */
- return (TRUE);
- }
-
- /* Nothing to gain */
- return (FALSE);
-}
-
-
-
-/*
- * Decreases a stat by an amount indended to vary from 0 to 100 percent.
- *
- * Amount could be a little higher in extreme cases to mangle very high
- * stats from massive assaults. -CWS
- *
- * Note that "permanent" means that the *given* amount is permanent,
- * not that the new value becomes permanent. This may not work exactly
- * as expected, due to "weirdness" in the algorithm, but in general,
- * if your stat is already drained, the "max" value will not drop all
- * the way down to the "cur" value.
- */
-bool_ dec_stat(int stat, int amount, int mode)
-{
- int cur, max, loss = 0, same, res = FALSE;
-
-
- /* Acquire current value */
- cur = p_ptr->stat_cur[stat];
- max = p_ptr->stat_max[stat];
-
- /* Note when the values are identical */
- same = (cur == max);
-
- /* Damage "current" value */
- if (cur > 3)
- {
- /* Handle "low" values */
- if (cur <= 18)
- {
- if (amount > 90) cur--;
- if (amount > 50) cur--;
- if (amount > 20) cur--;
- cur--;
- }
-
- /* Handle "high" values */
- else
- {
- /* Hack -- Decrement by a random amount between one-quarter */
- /* and one-half of the stat bonus times the percentage, with a */
- /* minimum damage of half the percentage. -CWS */
- loss = (((cur - 18) / 2 + 1) / 2 + 1);
-
- /* Paranoia */
- if (loss < 1) loss = 1;
-
- /* Randomize the loss */
- loss = ((randint(loss) + loss) * amount) / 100;
-
- /* Maximal loss */
- if (loss < amount / 2) loss = amount / 2;
-
- /* Lose some points */
- cur = cur - loss;
-
- /* Hack -- Only reduce stat to 17 sometimes */
- if (cur < 18) cur = (amount <= 20) ? 18 : 17;
- }
-
- /* Prevent illegal values */
- if (cur < 3) cur = 3;
-
- /* Something happened */
- if (cur != p_ptr->stat_cur[stat]) res = TRUE;
- }
-
- /* Damage "max" value */
- if ((mode == STAT_DEC_PERMANENT) && (max > 3))
- {
- /* Handle "low" values */
- if (max <= 18)
- {
- if (amount > 90) max--;
- if (amount > 50) max--;
- if (amount > 20) max--;
- max--;
- }
-
- /* Handle "high" values */
- else
- {
- /* Hack -- Decrement by a random amount between one-quarter */
- /* and one-half of the stat bonus times the percentage, with a */
- /* minimum damage of half the percentage. -CWS */
- loss = (((max - 18) / 2 + 1) / 2 + 1);
- loss = ((randint(loss) + loss) * amount) / 100;
- if (loss < amount / 2) loss = amount / 2;
-
- /* Lose some points */
- max = max - loss;
-
- /* Hack -- Only reduce stat to 17 sometimes */
- if (max < 18) max = (amount <= 20) ? 18 : 17;
- }
-
- /* Hack -- keep it clean */
- if (same || (max < cur)) max = cur;
-
- /* Something happened */
- if (max != p_ptr->stat_max[stat]) res = TRUE;
- }
-
- /* Apply changes */
- if (res)
- {
- if (mode == STAT_DEC_TEMPORARY)
- {
- u16b dectime;
-
- /* a little crude, perhaps */
- dectime = rand_int(max_dlv[dungeon_type] * 50) + 50;
-
- /* Calculate loss */
- loss = p_ptr->stat_cur[stat] - cur;
-
- /* prevent overflow, stat_cnt = u16b */
- /* or add another temporary drain... */
- if ( ((p_ptr->stat_cnt[stat] + dectime) < p_ptr->stat_cnt[stat]) ||
- (p_ptr->stat_los[stat] > 0) )
-
- {
- p_ptr->stat_cnt[stat] += dectime;
- p_ptr->stat_los[stat] += loss;
- }
- else
- {
- p_ptr->stat_cnt[stat] = dectime;
- p_ptr->stat_los[stat] = loss;
- }
- }
-
- /* Actually set the stat to its new value. */
- p_ptr->stat_cur[stat] = cur;
- p_ptr->stat_max[stat] = max;
-
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
- }
-
- /* Done */
- return (res);
-}
-
-
-/*
- * Restore a stat. Return TRUE only if this actually makes a difference.
- */
-bool_ res_stat(int stat, bool_ full)
-{
- /* Fully restore */
- if (full)
- {
- /* Restore if needed */
- if (p_ptr->stat_cur[stat] != p_ptr->stat_max[stat])
- {
- /* Restore */
- p_ptr->stat_cur[stat] = p_ptr->stat_max[stat];
-
- /* Remove temporary drain */
- p_ptr->stat_cnt[stat] = 0;
- p_ptr->stat_los[stat] = 0;
-
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
-
- /* Something happened */
- return (TRUE);
- }
- }
-
- /* Restore temporary drained stat */
- else
- {
- /* Restore if needed */
- if (p_ptr->stat_los[stat])
- {
- /* Restore */
- p_ptr->stat_cur[stat] += p_ptr->stat_los[stat];
-
- /* Remove temporary drain */
- p_ptr->stat_cnt[stat] = 0;
- p_ptr->stat_los[stat] = 0;
-
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
-
- /* Something happened */
- return (TRUE);
- }
- }
-
- /* Nothing to restore */
- return (FALSE);
-}
-
-
-
-
-/*
- * Apply disenchantment to the player's stuff
- *
- * XXX XXX XXX This function is also called from the "melee" code
- *
- * If "mode is set to 0 then a random slot will be used, if not the "mode"
- * slot will be used.
- *
- * Return "TRUE" if the player notices anything
- */
-bool_ apply_disenchant(int mode)
-{
- int t = mode;
- object_type *o_ptr;
- char o_name[80];
-
- if (!mode)
- {
- /* Pick a random slot */
- switch (randint(8))
- {
- case 1:
- t = INVEN_WIELD;
- break;
- case 2:
- t = INVEN_BOW;
- break;
- case 3:
- t = INVEN_BODY;
- break;
- case 4:
- t = INVEN_OUTER;
- break;
- case 5:
- t = INVEN_ARM;
- break;
- case 6:
- t = INVEN_HEAD;
- break;
- case 7:
- t = INVEN_HANDS;
- break;
- case 8:
- t = INVEN_FEET;
- break;
- }
- }
-
- /* Get the item */
- o_ptr = &p_ptr->inventory[t];
-
- /* No item, nothing happens */
- if (!o_ptr->k_idx) return (FALSE);
-
-
- /* Nothing to disenchant */
- if ((o_ptr->to_h <= 0) && (o_ptr->to_d <= 0) && (o_ptr->to_a <= 0))
- {
- /* Nothing to notice */
- return (FALSE);
- }
-
-
- /* Describe the object */
- object_desc(o_name, o_ptr, FALSE, 0);
-
-
- /* Artifacts have 71% chance to resist */
- if ((artifact_p(o_ptr) || o_ptr->art_name) && (rand_int(100) < 71))
- {
- /* Message */
- msg_format("Your %s (%c) resist%s disenchantment!",
- o_name, index_to_label(t),
- ((o_ptr->number != 1) ? "" : "s"));
-
- /* Notice */
- return (TRUE);
- }
-
-
- /* Disenchant tohit */
- if (o_ptr->to_h > 0) o_ptr->to_h--;
- if ((o_ptr->to_h > 5) && (rand_int(100) < 20)) o_ptr->to_h--;
-
- /* Disenchant todam */
- if (o_ptr->to_d > 0) o_ptr->to_d--;
- if ((o_ptr->to_d > 5) && (rand_int(100) < 20)) o_ptr->to_d--;
-
- /* Disenchant toac */
- if (o_ptr->to_a > 0) o_ptr->to_a--;
- if ((o_ptr->to_a > 5) && (rand_int(100) < 20)) o_ptr->to_a--;
-
- /* Message */
- msg_format("Your %s (%c) %s disenchanted!",
- o_name, index_to_label(t),
- ((o_ptr->number != 1) ? "were" : "was"));
-
- /* Recalculate bonuses */
- p_ptr->update |= (PU_BONUS);
-
- /* Window stuff */
- p_ptr->window |= (PW_EQUIP | PW_PLAYER);
-
- /* Notice */
- return (TRUE);
-}
-
-
-void corrupt_player(void)
-{
- int max1, cur1, max2, cur2, ii, jj;
-
- /* Pick a pair of stats */
- ii = rand_int(6);
- for (jj = ii; jj == ii; jj = rand_int(6)) /* loop */;
-
- max1 = p_ptr->stat_max[ii];
- cur1 = p_ptr->stat_cur[ii];
- max2 = p_ptr->stat_max[jj];
- cur2 = p_ptr->stat_cur[jj];
-
- p_ptr->stat_max[ii] = max2;
- p_ptr->stat_cur[ii] = cur2;
- p_ptr->stat_max[jj] = max1;
- p_ptr->stat_cur[jj] = cur1;
-
- p_ptr->update |= (PU_BONUS);
-}
-
-
-/*
- * Apply Nexus
- */
-static void apply_nexus(monster_type *m_ptr)
-{
- if (m_ptr == NULL) return;
-
- if (!(dungeon_flags2 & DF2_NO_TELEPORT))
- {
- switch (randint(7))
- {
- case 1:
- case 2:
- case 3:
- {
- teleport_player(200);
- break;
- }
-
- case 4:
- case 5:
- {
- teleport_player_to(m_ptr->fy, m_ptr->fx);
- break;
- }
-
- case 6:
- {
- if (rand_int(100) < p_ptr->skill_sav)
- {
- msg_print("You resist the effects!");
- break;
- }
-
- /* Teleport Level */
- teleport_player_level();
- break;
- }
-
- case 7:
- {
- if (rand_int(100) < p_ptr->skill_sav)
- {
- msg_print("You resist the effects!");
- break;
- }
-
- msg_print("Your body starts to scramble...");
- corrupt_player();
- break;
- }
- }
- }
-}
-
-/*
- * Convert 2 couples of coordonates to a direction
- */
-int yx_to_dir(int y2, int x2, int y1, int x1)
-{
- int y = y2 - y1, x = x2 - x1;
-
- if ((y == 0) && (x == 1)) return 6;
- if ((y == 0) && (x == -1)) return 4;
- if ((y == -1) && (x == 0)) return 8;
- if ((y == 1) && (x == 0)) return 2;
- if ((y == -1) && (x == -1)) return 7;
- if ((y == -1) && (x == 1)) return 9;
- if ((y == 1) && (x == 1)) return 3;
- if ((y == 1) && (x == -1)) return 1;
-
- return 5;
-}
-
-/*
- * Give the opposate direction of the given one
- */
-int invert_dir(int dir)
-{
- if (dir == 4) return 6;
- if (dir == 6) return 4;
- if (dir == 8) return 2;
- if (dir == 2) return 8;
- if (dir == 7) return 3;
- if (dir == 9) return 1;
- if (dir == 1) return 9;
- if (dir == 3) return 7;
- return 5;
-}
-
-
-/*
- * Determine which way the mana path follow
- */
-int get_mana_path_dir(int y, int x, int oy, int ox, int pdir, int mana)
-{
- int dir[8] = {5, 5, 5, 5, 5, 5, 5, 5}, n = 0, i, r = 0;
-
- /* Check which case are allowed */
- if (cave[y - 1][x].mana == mana) dir[n++] = 8;
- if (cave[y + 1][x].mana == mana) dir[n++] = 2;
- if (cave[y][x - 1].mana == mana) dir[n++] = 4;
- if (cave[y][x + 1].mana == mana) dir[n++] = 6;
-
- /* If only 2 possibilities select the only good one */
- if (n == 2)
- {
- if (invert_dir(yx_to_dir(y, x, oy, ox)) != dir[0]) return dir[0];
- if (invert_dir(yx_to_dir(y, x, oy, ox)) != dir[1]) return dir[1];
-
- /* Should never happen */
- return 5;
- }
-
-
- /* Check if it's not your last place */
- for (i = 0; i < n; i++)
- {
- if ((oy == y + ddy[dir[i]]) && (ox == x + ddx[dir[i]]))
- {
- if (dir[i] == 8) dir[i] = 2;
- else if (dir[i] == 2) dir[i] = 8;
- else if (dir[i] == 6) dir[i] = 4;
- else if (dir[i] == 4) dir[i] = 6;
- }
- }
-
- /* Select the desired one if possible */
- for (i = 0; i < n; i++)
- {
- if ((dir[i] == pdir) &&
- (cave[y + ddy[dir[i]]][x + ddx[dir[i]]].mana == mana))
- {
- return dir[i];
- }
- }
-
- /* If not select a random one */
- if (n > 2)
- {
- byte nb = 200;
-
- while (nb)
- {
- nb--;
-
- r = rand_int(n);
- if ((dir[r] != 5) && (yx_to_dir(y, x, oy, ox) != dir[r])) break;
- }
- return dir[r];
- }
- /* If nothing is found return 5 */
- else return 5;
-}
-
-
-/*
- * Determine the path taken by a projection.
- *
- * The projection will always start from the grid (y1,x1), and will travel
- * towards the grid (y2,x2), touching one grid per unit of distance along
- * the major axis, and stopping when it enters the destination grid or a
- * wall grid, or has travelled the maximum legal distance of "range".
- *
- * Note that "distance" in this function (as in the "update_view()" code)
- * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
- * actually has an "octagon of projection" not a "circle of projection".
- *
- * The path grids are saved into the grid array pointed to by "gp", and
- * there should be room for at least "range" grids in "gp". Note that
- * due to the way in which distance is calculated, this function normally
- * uses fewer than "range" grids for the projection path, so the result
- * of this function should never be compared directly to "range". Note
- * that the initial grid (y1,x1) is never saved into the grid array, not
- * even if the initial grid is also the final grid. XXX XXX XXX
- *
- * The "flg" flags can be used to modify the behavior of this function.
- *
- * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
- * semantics as they do for the "project" function, namely, that the path
- * will stop as soon as it hits a monster, or that the path will continue
- * through the destination grid, respectively.
- *
- * The "PROJECT_JUMP" flag, which for the "project()" function means to
- * start at a special grid (which makes no sense in this function), means
- * that the path should be "angled" slightly if needed to avoid any wall
- * grids, allowing the player to "target" any grid which is in "view".
- * This flag is non-trivial and has not yet been implemented, but could
- * perhaps make use of the "vinfo" array (above). XXX XXX XXX
- *
- * This function returns the number of grids (if any) in the path. This
- * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
- *
- * This algorithm is similar to, but slightly different from, the one used
- * by "update_view_los()", and very different from the one used by "los()".
- */
-sint project_path(u16b *gp, int range, int y1, int x1, int y2, int x2, int flg)
-{
- int y, x, mana = 0, dir = 0;
-
- int n = 0;
- int k = 0;
-
- /* Absolute */
- int ay, ax;
-
- /* Offsets */
- int sy, sx;
-
- /* Fractions */
- int frac;
-
- /* Scale factors */
- int full, half;
-
- /* Slope */
- int m;
-
-
- /* No path necessary (or allowed) */
- if ((x1 == x2) && (y1 == y2)) return (0);
-
- /* Hack -- to make a bolt/beam/ball follow a mana path */
- if (flg & PROJECT_MANA_PATH)
- {
- int oy = y1, ox = x1, pdir = yx_to_dir(y2, x2, y1, x1);
-
- /* Get the mana path level to follow */
- mana = cave[y1][x1].mana;
-
- /* Start */
- dir = get_mana_path_dir(y1, x1, y1, x1, pdir, mana);
- y = y1 + ddy[dir];
- x = x1 + ddx[dir];
-
- /* Create the projection path */
- while (1)
- {
- /* Save grid */
- gp[n++] = GRID(y, x);
-
- /* Hack -- Check maximum range */
- if (n >= range + 10) return n;
-
- /* Always stop at non-initial wall grids */
- if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x))) return n;
-
- /* Sometimes stop at non-initial monsters/players */
- if (flg & (PROJECT_STOP))
- {
- if ((n > 0) && (cave[y][x].m_idx != 0)) return n;
- }
-
- /* Get the new direction */
- dir = get_mana_path_dir(y, x, oy, ox, pdir, mana);
- if (dir == 5) return n;
- oy = y;
- ox = x;
- y += ddy[dir];
- x += ddx[dir];
- }
- }
-
- /* Analyze "dy" */
- if (y2 < y1)
- {
- ay = (y1 - y2);
- sy = -1;
- }
- else
- {
- ay = (y2 - y1);
- sy = 1;
- }
-
- /* Analyze "dx" */
- if (x2 < x1)
- {
- ax = (x1 - x2);
- sx = -1;
- }
- else
- {
- ax = (x2 - x1);
- sx = 1;
- }
-
-
- /* Number of "units" in one "half" grid */
- half = (ay * ax);
-
- /* Number of "units" in one "full" grid */
- full = half << 1;
-
-
- /* Vertical */
- if (ay > ax)
- {
- /* Start at tile edge */
- frac = ax * ax;
-
- /* Let m = ((dx/dy) * full) = (dx * dx * 2) = (frac * 2) */
- m = frac << 1;
-
- /* Start */
- y = y1 + sy;
- x = x1;
-
- /* Create the projection path */
- while (1)
- {
- /* Save grid */
- gp[n++] = GRID(y, x);
-
- /* Hack -- Check maximum range */
- if ((n + (k >> 1)) >= range) break;
-
- /* Sometimes stop at destination grid */
- if (!(flg & (PROJECT_THRU)))
- {
- if ((x == x2) && (y == y2)) break;
- }
-
- /* Always stop at non-initial wall grids */
- if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
-
- /* Sometimes stop at non-initial monsters/players */
- if (flg & (PROJECT_STOP))
- {
- if ((n > 0) && (cave[y][x].m_idx != 0)) break;
- }
-
- /* Slant */
- if (m)
- {
- /* Advance (X) part 1 */
- frac += m;
-
- /* Horizontal change */
- if (frac >= half)
- {
- /* Advance (X) part 2 */
- x += sx;
-
- /* Advance (X) part 3 */
- frac -= full;
-
- /* Track distance */
- k++;
- }
- }
-
- /* Advance (Y) */
- y += sy;
- }
- }
-
- /* Horizontal */
- else if (ax > ay)
- {
- /* Start at tile edge */
- frac = ay * ay;
-
- /* Let m = ((dy/dx) * full) = (dy * dy * 2) = (frac * 2) */
- m = frac << 1;
-
- /* Start */
- y = y1;
- x = x1 + sx;
-
- /* Create the projection path */
- while (1)
- {
- /* Save grid */
- gp[n++] = GRID(y, x);
-
- /* Hack -- Check maximum range */
- if ((n + (k >> 1)) >= range) break;
-
- /* Sometimes stop at destination grid */
- if (!(flg & (PROJECT_THRU)))
- {
- if ((x == x2) && (y == y2)) break;
- }
-
- /* Always stop at non-initial wall grids */
- if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
-
- /* Sometimes stop at non-initial monsters/players */
- if (flg & (PROJECT_STOP))
- {
- if ((n > 0) && (cave[y][x].m_idx != 0)) break;
- }
-
- /* Slant */
- if (m)
- {
- /* Advance (Y) part 1 */
- frac += m;
-
- /* Vertical change */
- if (frac >= half)
- {
- /* Advance (Y) part 2 */
- y += sy;
-
- /* Advance (Y) part 3 */
- frac -= full;
-
- /* Track distance */
- k++;
- }
- }
-
- /* Advance (X) */
- x += sx;
- }
- }
-
- /* Diagonal */
- else
- {
- /* Start */
- y = y1 + sy;
- x = x1 + sx;
-
- /* Create the projection path */
- while (1)
- {
- /* Save grid */
- gp[n++] = GRID(y, x);
-
- /* Hack -- Check maximum range */
- if ((n + (n >> 1)) >= range) break;
-
- /* Sometimes stop at destination grid */
- if (!(flg & (PROJECT_THRU)))
- {
- if ((x == x2) && (y == y2)) break;
- }
-
- /* Always stop at non-initial wall grids */
- if ((n > 0) && (!cave_sight_bold(y, x) || !cave_floor_bold(y, x)) && !(flg & PROJECT_WALL)) break;
-
- /* Sometimes stop at non-initial monsters/players */
- if (flg & (PROJECT_STOP))
- {
- if ((n > 0) && (cave[y][x].m_idx != 0)) break;
- }
-
- /* Advance (Y) */
- y += sy;
-
- /* Advance (X) */
- x += sx;
- }
- }
-
-
- /* Length */
- return (n);
-}
-
-
-
-/*
- * Mega-Hack -- track "affected" monsters (see "project()" comments)
- */
-static int project_m_n;
-static int project_m_x;
-static int project_m_y;
-
-
-
-/*
- * We are called from "project()" to "damage" terrain features
- *
- * We are called both for "beam" effects and "ball" effects.
- *
- * The "r" parameter is the "distance from ground zero".
- *
- * Note that we determine if the player can "see" anything that happens
- * by taking into account: blindness, line-of-sight, and illumination.
- *
- * We return "TRUE" if the effect of the projection is "obvious".
- *
- * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
- *
- * XXX XXX XXX Perhaps we should affect doors?
- */
-static bool_ project_f(int who, int r, int y, int x, int dam, int typ)
-{
- cave_type *c_ptr = &cave[y][x];
-
- bool_ obvious = FALSE;
-
- bool_ flag = FALSE;
-
- bool_ seen;
-
-
- /* XXX XXX XXX */
- who = who ? who : 0;
-
- /* Reduce damage by distance */
- dam = (dam + r) / (r + 1);
-
- /* Remember if the grid is with the LoS of player */
- seen = player_can_see_bold(y, x);
-
- /* Analyze the type */
- switch (typ)
- {
- /* Ignore most effects */
- case GF_ELEC:
- case GF_SOUND:
- case GF_MANA:
- case GF_PSI:
- case GF_PSI_DRAIN:
- case GF_TELEKINESIS:
- case GF_DOMINATION:
- {
- break;
- }
-
- case GF_COLD:
- case GF_ICE:
- {
- int percent = c_ptr->feat == GF_COLD ? 20 : 50;
-
- /* Only affects "boring" grids */
- if (!cave_plain_floor_bold(y, x)) break;
-
- if (rand_int(100) < percent)
- {
- cave_set_feat(y, x, FEAT_ICE);
-
- if (seen) obvious = TRUE;
- }
-
- break;
- }
-
- case GF_BETWEEN_GATE:
- {
- int y1 = randint(cur_hgt) - 1;
- int x1 = randint(cur_wid) - 1;
- int y2 = y1;
- int x2 = x1;
- int tries = 1000;
-
- /*
- * Avoid "interesting" and/or permanent features
- *
- * If we can make sure that all the "permanent" features
- * have the remember flag set as well, we can simplify
- * the conditional... -- pelpel
- */
- if (!cave_plain_floor_bold(y, x) ||
- (f_info[cave[y][x].feat].flags1 & FF1_PERMANENT)) break;
-
- /* Destination shouldn't be "interesting" either */
- while (tries &&
- (!cave_plain_floor_bold(y2, x2) ||
- (f_info[cave[y2][x2].feat].flags1 & FF1_PERMANENT)))
- {
- y2 = y1 = randint(cur_hgt) - 1;
- x2 = x1 = randint(cur_wid) - 1;
- scatter(&y2, &x2, y1, x1, 20);
- tries --;
- }
-
- /* No boarding grids found */
- if (!tries) break;
-
- /* Place a pair of between gates */
- cave_set_feat(y, x, FEAT_BETWEEN);
- cave[y][x].special = x2 + (y2 << 8);
-
- cave_set_feat(y2, x2, FEAT_BETWEEN);
- cave[y2][x2].special = x + (y << 8);
-
- if (seen)
- {
- obvious = TRUE;
- note_spot(y, x);
- }
-
- if (player_can_see_bold(y2, x2))
- {
- obvious = TRUE;
- note_spot(y2, x2);
- }
-
- break;
- }
-
- /* Burn trees & melt ice */
- case GF_FIRE:
- case GF_METEOR:
- case GF_PLASMA:
- case GF_HOLY_FIRE:
- case GF_HELL_FIRE:
- {
- /* "Permanent" features will stay */
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Trees *will* burn */
- if (c_ptr->feat == FEAT_TREES)
- {
- cave_set_feat(y, x, FEAT_DEAD_TREE);
-
- /* Silly thing to destroy trees when a yavanna worshipper */
- inc_piety(GOD_YAVANNA, -50);
-
- if (seen) obvious = TRUE;
- }
-
- /* Trees *will* burn */
- if (c_ptr->feat == FEAT_SMALL_TREES)
- {
- cave_set_feat(y, x, FEAT_DEAD_SMALL_TREE);
-
- /* Silly thing to destroy trees when a yavanna worshipper */
- inc_piety(GOD_YAVANNA, -60);
-
- if (seen) obvious = TRUE;
- }
-
- /* Ice can melt (chance == 30%) */
- else if (c_ptr->feat == FEAT_ICE)
- {
- int k = rand_int(100);
-
- if (k >= 30) break;
-
- /* Melt ice */
- if (k < 10) cave_set_feat(y, x, FEAT_DIRT);
- else if (k < 30) cave_set_feat(y, x, FEAT_SHAL_WATER);
-
- if (seen) obvious = TRUE;
- }
-
- /* Floors can become ash or lava (chance == 25%) */
- else if (f_info[c_ptr->feat].flags1 & FF1_FLOOR)
- {
- int k = rand_int(100);
-
- if (k >= 25) break;
-
- /* Burn floor */
- if (k < 10) cave_set_feat(y, x, FEAT_SHAL_LAVA);
- else if (k < 25) cave_set_feat(y, x, FEAT_ASH);
-
- if (seen) obvious = TRUE;
- }
-
- /* Sandwall can be turned into glass (chance == 30%) */
- else if ((c_ptr->feat == FEAT_SANDWALL) ||
- (c_ptr->feat == FEAT_SANDWALL_H) ||
- (c_ptr->feat == FEAT_SANDWALL_K))
- {
- int k = rand_int(100);
-
- /* Glass it */
- if (k < 30)
- {
- cave_set_feat(y, x, FEAT_GLASS_WALL);
-
- /* Visibility change */
- p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
-
- if (seen) obvious = TRUE;
- }
-
- }
-
- break;
- }
-
- case GF_WAVE:
- case GF_WATER:
- {
- int p1 = 0;
- int p2 = 0;
- int f1 = 0;
- int f2 = 0;
- int f = 0;
- int k;
-
- /* "Permanent" features will stay */
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Needs more than 30 damage */
- if (dam < 30) break;
-
- if ((c_ptr->feat == FEAT_FLOOR) ||
- (c_ptr->feat == FEAT_DIRT) ||
- (c_ptr->feat == FEAT_GRASS))
- {
- /* 35% chance to create shallow water */
- p1 = 35;
- f1 = FEAT_SHAL_WATER;
-
- /* 5% chance to create deep water */
- p2 = 40;
- f2 = FEAT_DEEP_WATER;
- }
- else if ((c_ptr->feat == FEAT_MAGMA) ||
- (c_ptr->feat == FEAT_MAGMA_H) ||
- (c_ptr->feat == FEAT_MAGMA_K) ||
- (c_ptr->feat == FEAT_SHAL_LAVA))
- {
- /* 15% chance to convert it to normal floor */
- p1 = 15;
- f1 = FEAT_FLOOR;
- }
- else if (c_ptr->feat == FEAT_DEEP_LAVA)
- {
- /* 10% chance to convert it to shallow lava */
- p1 = 10;
- f1 = FEAT_SHAL_LAVA;
-
- /* 5% chance to convert it to normal floor */
- p2 = 15;
- f2 = FEAT_FLOOR;
- }
- else if ((c_ptr->feat == FEAT_SHAL_WATER) ||
- (c_ptr->feat == FEAT_DARK_PIT))
- {
- /* 10% chance to convert it to deep water */
- p1 = 10;
- f1 = FEAT_DEEP_WATER;
- }
-
- k = rand_int(100);
-
- if (k < p1) f = f1;
- else if (k < p2) f = f2;
-
- if (f)
- {
- if (f == FEAT_FLOOR) place_floor_convert_glass(y, x);
- else cave_set_feat(y, x, f);
-
- if (seen) obvious = TRUE;
- }
-
- break;
- }
-
- case GF_NETHER:
- case GF_NEXUS:
- case GF_ACID:
- case GF_SHARDS:
- case GF_TIME:
- case GF_FORCE:
- case GF_NUKE:
- {
- /* "Permanent" features will stay */
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- if ((c_ptr->feat == FEAT_TREES) ||
- (c_ptr->feat == FEAT_SMALL_TREES))
- {
- /* Destroy the grid */
- cave_set_feat(y, x, FEAT_DEAD_TREE);
-
- /* Silly thing to destroy trees when a yavanna worshipper */
- inc_piety(GOD_YAVANNA, -50);
-
- if (seen) obvious = TRUE;
- }
-
- break;
- }
-
- case GF_DISINTEGRATE:
- {
- /* "Permanent" features will stay */
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- if (((c_ptr->feat == FEAT_TREES) ||
- (c_ptr->feat == FEAT_SMALL_TREES) ||
- (f_info[c_ptr->feat].flags1 & FF1_FLOOR)) &&
- (rand_int(100) < 30))
- {
- /* Flow change */
- if (c_ptr->feat == FEAT_TREES) p_ptr->update |= (PU_FLOW);
-
- cave_set_feat(y, x, FEAT_ASH);
-
- /* Silly thing to destroy trees when a yavanna worshipper */
- if (c_ptr->feat == FEAT_TREES || c_ptr->feat == FEAT_SMALL_TREES)
- inc_piety(GOD_YAVANNA, -50);
-
- /* Visibility change */
- p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
-
- if (seen) obvious = TRUE;
- }
-
- break;
- }
-
- /* Destroy Traps (and Locks) */
- case GF_KILL_TRAP:
- {
- /* Destroy normal traps and disarm monster traps */
- if ((c_ptr->t_idx != 0) || (c_ptr->feat == FEAT_MON_TRAP))
- {
- /* Check line of sight */
- if (player_has_los_bold(y, x))
- {
- msg_print("There is a bright flash of light!");
- obvious = TRUE;
- }
-
- /* Forget the trap */
- c_ptr->info &= ~(CAVE_MARK | CAVE_TRDT);
-
- /* Destroy normal traps */
- c_ptr->t_idx = 0;
-
- /* Disarm monster traps */
- if (c_ptr->feat == FEAT_MON_TRAP)
- {
- c_ptr->special = c_ptr->special2 = 0;
-
- /* Remove the feature */
- if (!(f_info[c_ptr->feat].flags1 & FF1_PERMANENT))
- place_floor_convert_glass(y, x);
- }
-
- /* Hack -- Force redraw */
- note_spot(y, x);
- lite_spot(y, x);
- }
-
- /* Secret / Locked doors are found and unlocked */
- else if ((c_ptr->feat == FEAT_SECRET) ||
- ((c_ptr->feat >= FEAT_DOOR_HEAD + 0x01) &&
- (c_ptr->feat <= FEAT_DOOR_HEAD + 0x07)))
- {
-
- /* Check line of sound */
- if (player_has_los_bold(y, x))
- {
- msg_print("Click!");
- obvious = TRUE;
- }
-
- /* Remove feature mimic */
- cave[y][x].mimic = 0;
-
- /* Unlock the door */
- cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
- }
-
- break;
- }
-
- /* Destroy Doors (and traps) */
- case GF_KILL_DOOR:
- {
- /* Destroy all doors and traps, and disarm monster traps */
- if ((c_ptr->feat == FEAT_OPEN) ||
- (c_ptr->feat == FEAT_BROKEN) ||
- (c_ptr->t_idx != 0) ||
- (c_ptr->feat == FEAT_MON_TRAP) ||
- ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
- (c_ptr->feat <= FEAT_DOOR_TAIL)))
- {
- /* Check line of sight */
- if (player_has_los_bold(y, x))
- {
- /* Message */
- msg_print("There is a bright flash of light!");
- obvious = TRUE;
-
- /* Visibility change */
- if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
- (c_ptr->feat <= FEAT_DOOR_TAIL))
- {
- /* Update some things */
- p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
- }
- }
-
- /* Forget the door */
- c_ptr->info &= ~(CAVE_MARK | CAVE_TRDT);
-
- /* Remove normal traps */
- c_ptr->t_idx = 0;
-
- /* Disarm monster traps */
- if (c_ptr->feat == FEAT_MON_TRAP)
- c_ptr->special = c_ptr->special2 = 0;
-
- /* Remove the feature */
- if (!(f_info[c_ptr->feat].flags1 & FF1_PERMANENT))
- place_floor_convert_glass(y, x);
-
- /* Hack -- Force redraw */
- note_spot(y, x);
- lite_spot(y, x);
- }
-
- break;
- }
-
- case GF_JAM_DOOR: /* Jams a door (as if with a spike) */
- {
- if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
- (c_ptr->feat <= FEAT_DOOR_TAIL))
- {
- /* Convert "locked" to "stuck" XXX XXX XXX */
- if (c_ptr->feat < FEAT_DOOR_HEAD + 0x08) c_ptr->feat += 0x08;
-
- /* Add one spike to the door */
- if (c_ptr->feat < FEAT_DOOR_TAIL) c_ptr->feat++;
-
- /* Check line of sight */
- if (player_has_los_bold(y, x))
- {
- /* Message */
- msg_print("The door seems stuck.");
- obvious = TRUE;
- }
- }
-
- break;
- }
-
- /* Destroy walls (and doors) */
- case GF_KILL_WALL:
- {
- /* Non-walls (etc) */
- if (cave_floor_bold(y, x)) break;
-
- /* "Permanent" features will stay */
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Granite -- How about other wall types? */
- if ((c_ptr->feat >= FEAT_WALL_EXTRA) &&
- (c_ptr->feat <= FEAT_WALL_SOLID))
- {
- /* Message */
- if (c_ptr->info & (CAVE_MARK))
- {
- msg_print("The wall turns into mud!");
- obvious = TRUE;
- }
-
- /* Forget the wall */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Destroy the wall */
- cave_set_feat(y, x, FEAT_FLOOR);
- }
-
- /* Quartz / Magma / Sand with treasure */
- else if (((c_ptr->feat >= FEAT_MAGMA_H) &&
- (c_ptr->feat <= FEAT_QUARTZ_K)) ||
- (c_ptr->feat == FEAT_SANDWALL_K))
- {
- /* Message */
- if (c_ptr->info & (CAVE_MARK))
- {
- msg_print("The vein turns into mud!");
- msg_print("You have found something!");
- obvious = TRUE;
- }
-
- /* Forget the wall */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Destroy the wall */
- cave_set_feat(y, x, FEAT_FLOOR);
-
- /* Place some gold */
- place_gold(y, x);
- }
-
- /* Quartz / Magma / Sand */
- else if ((c_ptr->feat == FEAT_MAGMA) ||
- (c_ptr->feat == FEAT_QUARTZ) ||
- (c_ptr->feat == FEAT_SANDWALL) ||
- (c_ptr->feat == FEAT_SANDWALL_H))
- {
- /* Message */
- if (c_ptr->info & (CAVE_MARK))
- {
- msg_print("The vein turns into mud!");
- obvious = TRUE;
- }
-
- /* Forget the wall */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Destroy the wall */
- cave_set_feat(y, x, FEAT_FLOOR);
- }
-
- /* Rubble */
- else if (c_ptr->feat == FEAT_RUBBLE)
- {
- /* Message */
- if (c_ptr->info & (CAVE_MARK))
- {
- msg_print("The rubble turns into mud!");
- obvious = TRUE;
- }
-
- /* Forget the wall */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Destroy the rubble */
- cave_set_feat(y, x, FEAT_FLOOR);
-
- /* Hack -- place an object */
- if (rand_int(100) < 10)
- {
- /* Found something */
- if (seen)
- {
- msg_print("There was something buried in the rubble!");
- obvious = TRUE;
- }
-
- /* Place gold */
- place_object(y, x, FALSE, FALSE, OBJ_FOUND_RUBBLE);
- }
- }
-
- /* Destroy doors (and secret doors) */
- else if (((c_ptr->feat >= FEAT_DOOR_HEAD) &&
- (c_ptr->feat <= FEAT_DOOR_TAIL)) ||
- (c_ptr->feat == FEAT_SECRET))
- {
- /* Hack -- special message */
- if (c_ptr->info & (CAVE_MARK))
- {
- msg_print("The door turns into mud!");
- obvious = TRUE;
- }
-
- /* Forget the wall */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Remove mimic */
- c_ptr->mimic = 0;
-
- /* Destroy the feature */
- cave_set_feat(y, x, FEAT_FLOOR);
- }
-
- /* Update some things */
- p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
-
- break;
- }
-
- /* Make doors */
- case GF_MAKE_DOOR:
- {
- /* Require a "naked" floor grid */
- if (!cave_clean_bold(y, x)) break;
-
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Create a closed door */
- cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
-
- /* Observe */
- if (c_ptr->info & (CAVE_MARK)) obvious = TRUE;
-
- /* Update some things */
- p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
-
- break;
- }
-
- /* Make traps */
- case GF_MAKE_TRAP:
- {
- /* Require a "naked" floor grid */
- if (!cave_clean_bold(y, x)) break;
-
- /* Place a trap */
- place_trap(y, x);
-
- break;
- }
-
-
- case GF_MAKE_GLYPH:
- {
- /* Require a "naked" floor grid */
- if (!cave_clean_bold(y, x)) break;
-
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- cave_set_feat(y, x, FEAT_GLYPH);
-
- if (seen) obvious = TRUE;
-
- break;
- }
-
-
-
- case GF_STONE_WALL:
- {
- /* Require a "naked" floor grid */
- if (!cave_clean_bold(y, x)) break;
-
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
- if (!(f_info[c_ptr->feat].flags1 & FF1_FLOOR)) break;
-
- /* Place a wall */
- cave_set_feat(y, x, FEAT_WALL_EXTRA);
-
- if (seen) obvious = TRUE;
-
- /* Update some things */
- p_ptr->update |= (PU_VIEW | PU_MONSTERS | PU_MON_LITE);
-
- break;
- }
-
- case GF_WINDS_MANA:
- {
- if (dam >= 256)
- {
- /* With erase mana */
-
- /* Absorb some of the mana of the grid */
- p_ptr->csp += cave[y][x].mana / 80;
- if (p_ptr->csp > p_ptr->msp) p_ptr->csp = p_ptr->msp;
-
- /* Set the new amount */
- cave[y][x].mana = dam - 256;
- }
- else
- {
- /* Without erase mana */
- int amt = cave[y][x].mana + dam;
-
- /* Check if not overflow */
- if (amt > 255) amt = 255;
-
- /* Set the new amount */
- cave[y][x].mana = amt;
- }
-
- break;
- }
-
- case GF_LAVA_FLOW:
- {
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Shallow Lava */
- if (dam == 1)
- {
- /* Require a "naked" floor grid */
- if (!cave_naked_bold(y, x)) break;
-
- /* Place a shallow lava */
- cave_set_feat(y, x, FEAT_SHAL_LAVA);
-
- if (seen) obvious = TRUE;
- }
-
- /* Deep Lava */
- else
- {
- /* Require a "naked" floor grid */
- if (cave_perma_bold(y, x) || !dam) break;
-
- /* Place a deep lava */
- cave_set_feat(y, x, FEAT_DEEP_LAVA);
-
- if (seen) obvious = TRUE;
-
- /* Dam is used as a counter for the number of grid to convert */
- dam--;
- }
-
- break;
- }
-
- /* Lite up the grid */
- case GF_LITE_WEAK:
- case GF_LITE:
- {
- /* Turn on the light */
- c_ptr->info |= (CAVE_GLOW);
-
- /* Notice */
- note_spot(y, x);
-
- /* Redraw */
- lite_spot(y, x);
-
- /* Observe */
- if (seen) obvious = TRUE;
-
- /*
- * Mega-Hack -- Update the monster in the affected grid
- * This allows "spear of light" (etc) to work "correctly"
- */
- if (c_ptr->m_idx) update_mon(c_ptr->m_idx, FALSE);
-
- break;
- }
-
- /* Darken the grid */
- case GF_DARK_WEAK:
- case GF_DARK:
- {
- /* Notice */
- if (seen) obvious = TRUE;
-
- /* Turn off the light. */
- c_ptr->info &= ~(CAVE_GLOW);
-
- /* Hack -- Forget "boring" grids */
- if (cave_plain_floor_grid(c_ptr))
- {
- /* Forget */
- c_ptr->info &= ~(CAVE_MARK);
-
- /* Notice */
- note_spot(y, x);
- }
-
- /* Redraw */
- lite_spot(y, x);
-
- /*
- * Mega-Hack -- Update the monster in the affected grid
- * This allows "spear of light" (etc) to work "correctly"
- */
- if (c_ptr->m_idx) update_mon(c_ptr->m_idx, FALSE);
-
- /* All done */
- break;
- }
-
- case GF_DESTRUCTION:
- {
- int t;
-
- /* Lose room and vault */
- c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
-
- /* Lose light and knowledge */
- c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
-
- /* Hack -- Notice player affect */
- if ((x == p_ptr->px) && (y == p_ptr->py))
- {
- /* Hurt the player later */
- flag = TRUE;
-
- /* Do not hurt this grid */
- break;
- ;
- }
-
- /* Delete the monster (if any) */
- delete_monster(y, x);
-
- if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
-
- /* Destroy "valid" grids */
- if (cave_valid_bold(y, x))
- {
- /* Delete objects */
- delete_object(y, x);
-
- /* Wall (or floor) type */
- t = rand_int(200);
-
- /* Granite */
- if (t < 20)
- {
- /* Create granite wall */
- cave_set_feat(y, x, FEAT_WALL_EXTRA);
- }
-
- /* Quartz */
- else if (t < 60)
- {
- /* Create quartz vein */
- cave_set_feat(y, x, FEAT_QUARTZ);
- }
-
- /* Magma */
- else if (t < 90)
- {
- /* Create magma vein */
- cave_set_feat(y, x, FEAT_MAGMA);
- }
-
- /* Sand */
- else if (t < 110)
- {
- /* Create sand vein */
- cave_set_feat(y, x, FEAT_SANDWALL);
- }
-
- /* Floor */
- else
- {
- /* Create floor */
- cave_set_feat(y, x, FEAT_FLOOR);
- }
-
- /* Visibility and flow changes */
- p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
- }
-
- obvious = TRUE;
- break;
- }
- default:
- {
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d)", "grid", who, typ, dam, r, y, x))
- {
- obvious = process_hooks_return[0].num;
- flag = process_hooks_return[1].num;
- }
- break;
- }
- }
-
- /* Hack -- Affect player */
- if (flag)
- {
- /* Message */
- msg_print("There is a searing blast of light!");
-
- /* Blind the player */
- if (!p_ptr->resist_blind && !p_ptr->resist_lite)
- {
- /* Become blind */
- (void)set_blind(p_ptr->blind + 10 + randint(10));
- }
- }
-
- /* Return "Anything seen?" */
- return (obvious);
-}
-
-
-/* Array of raisable ego monster */
-#define MAX_RAISE 10
-static int raise_ego[MAX_RAISE] =
-{
- 1, /* Skeleton */
- 1, /* Skeleton */
- 1, /* Skeleton */
- 1, /* Skeleton */
- 2, /* Zombie */
- 2, /* Zombie */
- 2, /* Zombie */
- 4, /* Spectre */
- 4, /* Spectre */
- 3, /* Lich */
-};
-
-
-/*
- * We are called from "project()" to "damage" objects
- *
- * We are called both for "beam" effects and "ball" effects.
- *
- * Perhaps we should only SOMETIMES damage things on the ground.
- *
- * The "r" parameter is the "distance from ground zero".
- *
- * Note that we determine if the player can "see" anything that happens
- * by taking into account: blindness, line-of-sight, and illumination.
- *
- * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
- *
- * We return "TRUE" if the effect of the projection is "obvious".
- */
-static bool_ project_o(int who, int r, int y, int x, int dam, int typ)
-{
- cave_type *c_ptr = &cave[y][x];
-
- s16b this_o_idx, next_o_idx = 0;
-
- bool_ obvious = FALSE;
-
- u32b f1, f2, f3, f4, f5, esp;
-
- char o_name[80];
-
- int o_sval = 0;
- bool_ is_potion = FALSE;
-
-
- /* XXX XXX XXX */
- who = who ? who : 0;
-
- /* Reduce damage by distance */
- dam = (dam + r) / (r + 1);
-
-
- /* Scan all objects in the grid */
- for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
- {
- object_type * o_ptr;
-
- bool_ is_art = FALSE;
- bool_ ignore = FALSE;
- bool_ plural = FALSE;
- bool_ do_kill = FALSE;
-
- cptr note_kill = NULL;
-
- /* Acquire object */
- o_ptr = &o_list[this_o_idx];
-
- /* Acquire next object */
- next_o_idx = o_ptr->next_o_idx;
-
- /* Extract the flags */
- object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);
-
- /* Get the "plural"-ness */
- if (o_ptr->number > 1) plural = TRUE;
-
- /* Check for artifact */
- if ((artifact_p(o_ptr) || o_ptr->art_name)) is_art = TRUE;
-
- /* Analyze the type */
- switch (typ)
- {
- /* makes corpses explode */
- case GF_CORPSE_EXPL:
- {
- if (o_ptr->tval == TV_CORPSE)
- {
- monster_race *r_ptr = &r_info[o_ptr->pval2];
- s32b dama, radius = 7;
-
- if (r_ptr->flags1 & RF1_FORCE_MAXHP)
- dama = maxroll(r_ptr->hdice, r_ptr->hside);
- else
- dama = damroll(r_ptr->hdice, r_ptr->hside);
-
- /* Adjust the damage */
- dama = dama * dam / 100;
-
- /* Adjust the radius */
- radius = radius * dam / 100;
-
- do_kill = TRUE;
- note_kill = (plural ? " explode!" : " explodes!");
- project(who, radius, y, x, dama, GF_SHARDS, PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL);
- }
- break;
- }
-
- /* Acid -- Lots of things */
- case GF_ACID:
- {
- if (hates_acid(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " melt!" : " melts!");
- if (f3 & (TR3_IGNORE_ACID)) ignore = TRUE;
- }
- break;
- }
-
- /* Elec -- Rings and Wands */
- case GF_ELEC:
- {
- if (hates_elec(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " are destroyed!" : " is destroyed!");
- if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
- }
- break;
- }
-
- /* Fire -- Flammable objects */
- case GF_FIRE:
- {
- if (hates_fire(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " burn up!" : " burns up!");
- if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
- }
- break;
- }
-
- /* Cold -- potions and flasks */
- case GF_COLD:
- {
- if (hates_cold(o_ptr))
- {
- note_kill = (plural ? " shatter!" : " shatters!");
- do_kill = TRUE;
- if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
- }
- break;
- }
-
- /* Fire + Elec */
- case GF_PLASMA:
- {
- if (hates_fire(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " burn up!" : " burns up!");
- if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
- }
- if (hates_elec(o_ptr))
- {
- ignore = FALSE;
- do_kill = TRUE;
- note_kill = (plural ? " are destroyed!" : " is destroyed!");
- if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
- }
- break;
- }
-
- /* Fire + Cold */
- case GF_METEOR:
- {
- if (hates_fire(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " burn up!" : " burns up!");
- if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
- }
- if (hates_cold(o_ptr))
- {
- ignore = FALSE;
- do_kill = TRUE;
- note_kill = (plural ? " shatter!" : " shatters!");
- if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
- }
- break;
- }
-
- /* Hack -- break potions and such */
- case GF_ICE:
- case GF_SHARDS:
- case GF_FORCE:
- case GF_SOUND:
- {
- if (hates_cold(o_ptr))
- {
- note_kill = (plural ? " shatter!" : " shatters!");
- do_kill = TRUE;
- }
- break;
- }
-
- /* Mana and Chaos -- destroy everything */
- case GF_MANA:
- {
- do_kill = TRUE;
- note_kill = (plural ? " are destroyed!" : " is destroyed!");
- break;
- }
-
- case GF_DISINTEGRATE:
- {
- do_kill = TRUE;
- note_kill = (plural ? " evaporate!" : " evaporates!");
- break;
- }
-
- case GF_CHAOS:
- {
- do_kill = TRUE;
- note_kill = (plural ? " are destroyed!" : " is destroyed!");
- if (f2 & (TR2_RES_CHAOS)) ignore = TRUE;
- break;
- }
-
- /* Holy Fire and Hell Fire -- destroys cursed non-artifacts */
- case GF_HOLY_FIRE:
- case GF_HELL_FIRE:
- {
- if (cursed_p(o_ptr))
- {
- do_kill = TRUE;
- note_kill = (plural ? " are destroyed!" : " is destroyed!");
- }
- break;
- }
-
- /* Unlock chests */
- case GF_KILL_TRAP:
- case GF_KILL_DOOR:
- {
- /* Chests are noticed only if trapped or locked */
- if (o_ptr->tval == TV_CHEST)
- {
- /* Disarm/Unlock traps */
- if (o_ptr->pval > 0)
- {
- /* Disarm or Unlock */
- o_ptr->pval = (0 - o_ptr->pval);
-
- /* Identify */
- object_known(o_ptr);
-
- /* Notice */
- if (o_ptr->marked)
- {
- msg_print("Click!");
- obvious = TRUE;
- }
- }
- }
-
- break;
- }
- case GF_STAR_IDENTIFY:
- {
- /* Identify it fully */
- object_aware(o_ptr);
- object_known(o_ptr);
-
- /* Mark the item as fully known */
- o_ptr->ident |= (IDENT_MENTAL);
-
- /* Process the appropriate hooks */
- process_hooks(HOOK_IDENTIFY, "(d,s)", 0 - this_o_idx, "full");
-
- /* Squelch ! */
- squeltch_grid();
-
- break;
- }
- case GF_IDENTIFY:
- {
- object_aware(o_ptr);
- object_known(o_ptr);
-
- /* Process the appropriate hooks */
- process_hooks(HOOK_IDENTIFY, "(d,s)", 0 - this_o_idx, "normal");
-
- /* Squelch ! */
- squeltch_grid();
-
- break;
- }
- case GF_RAISE:
- {
- get_pos_player(7, &y, &x);
-
- /* Only corpses can be raised */
- if (o_ptr->tval == TV_CORPSE)
- {
- int ego = raise_ego[rand_int(MAX_RAISE)];
-
- if (place_monster_one(y, x, o_ptr->pval2, ego, FALSE, (!who) ? MSTATUS_PET : MSTATUS_ENEMY))
- msg_print("A monster rises from the grave!");
- do_kill = TRUE;
- }
- break;
- }
- case GF_RAISE_DEMON:
- {
- monster_race *r_ptr = &r_info[o_ptr->pval2];
- cptr name;
-
- if (o_ptr->tval != TV_CORPSE) break;
-
- if (randint(100) > r_ptr->level - p_ptr->lev)
- {
- if (r_ptr->level < 10) name = "Manes";
- else if (r_ptr->level < 18) name = "Tengu";
- else if (r_ptr->level < 26) name = "Imp";
- else if (r_ptr->level < 34) name = "Arch-vile";
- else if (r_ptr->level < 42) name = "Bodak";
- else if (r_ptr->level < 50) name = "Erynies";
- else if (r_ptr->level < 58) name = "Vrock";
- else if (r_ptr->level < 66) name = "Hezrou";
- else if (r_ptr->level < 74) name = "Glabrezu";
- else if (r_ptr->level < 82) name = "Nalfeshnee";
- else if (r_ptr->level < 90) name = "Marilith";
- else name = "Nycadaemon";
-
- if (place_monster_one(y, x, test_monster_name(name), 0, FALSE, (!who) ? MSTATUS_PET : MSTATUS_ENEMY))
- msg_print("A demon emerges from Hell!");
- }
-
- do_kill = TRUE;
- break;
- }
- default:
- {
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d,O)", "object", who, typ, dam, r, y, x, o_ptr))
- {
- obvious = process_hooks_return[0].num;
- do_kill = process_hooks_return[1].num;
- }
- break;
- }
- }
-
-
- /* Attempt to destroy the object */
- if (do_kill)
- {
- /* Effect "observed" */
- if (o_ptr->marked)
- {
- obvious = TRUE;
- object_desc(o_name, o_ptr, FALSE, 0);
- }
-
- /* Artifacts, and other objects, get to resist */
- if (is_art || ignore)
- {
- /* Observe the resist */
- if (o_ptr->marked)
- {
- msg_format("The %s %s unaffected!",
- o_name, (plural ? "are" : "is"));
- }
- }
-
- /* Kill it */
- else
- {
- /* Describe if needed */
- if (o_ptr->marked && note_kill)
- {
- msg_format("The %s%s", o_name, note_kill);
- }
-
- o_sval = o_ptr->sval;
- is_potion = ((k_info[o_ptr->k_idx].tval == TV_POTION) || (k_info[o_ptr->k_idx].tval == TV_POTION2));
-
-
- /* Delete the object */
- delete_object_idx(this_o_idx);
-
- /* Potions produce effects when 'shattered' */
- if (is_potion)
- {
- (void)potion_smash_effect(who, y, x, o_sval);
- }
-
-
- /* Redraw */
- lite_spot(y, x);
- }
- }
- }
-
- /* Return "Anything seen?" */
- return (obvious);
-}
-
-/* Can the monster be hurt ? */
-bool_ hurt_monster(monster_type *m_ptr)
-{
- if (m_ptr->status == MSTATUS_COMPANION) return FALSE;
- else return TRUE;
-}
-
-/*
- * Helper function for "project()" below.
- *
- * Handle a beam/bolt/ball causing damage to a monster.
- *
- * This routine takes a "source monster" (by index) which is mostly used to
- * determine if the player is causing the damage, and a "radius" (see below),
- * which is used to decrease the power of explosions with distance, and a
- * location, via integers which are modified by certain types of attacks
- * (polymorph and teleport being the obvious ones), a default damage, which
- * is modified as needed based on various properties, and finally a "damage
- * type" (see below).
- *
- * Note that this routine can handle "no damage" attacks (like teleport) by
- * taking a "zero" damage, and can even take "parameters" to attacks (like
- * confuse) by accepting a "damage", using it to calculate the effect, and
- * then setting the damage to zero. Note that the "damage" parameter is
- * divided by the radius, so monsters not at the "epicenter" will not take
- * as much damage (or whatever)...
- *
- * Note that "polymorph" is dangerous, since a failure in "place_monster()"'
- * may result in a dereference of an invalid pointer. XXX XXX XXX
- *
- * Various messages are produced, and damage is applied.
- *
- * Just "casting" a substance (i.e. plasma) does not make you immune, you must
- * actually be "made" of that substance, or "breathe" big balls of it.
- *
- * We assume that "Plasma" monsters, and "Plasma" breathers, are immune
- * to plasma.
- *
- * We assume "Nether" is an evil, necromantic force, so it doesn't hurt undead,
- * and hurts evil less. If can breath nether, then it resists it as well.
- *
- * Damage reductions use the following formulas:
- * Note that "dam = dam * 6 / (randint(6) + 6);"
- * gives avg damage of .655, ranging from .858 to .500
- * Note that "dam = dam * 5 / (randint(6) + 6);"
- * gives avg damage of .544, ranging from .714 to .417
- * Note that "dam = dam * 4 / (randint(6) + 6);"
- * gives avg damage of .444, ranging from .556 to .333
- * Note that "dam = dam * 3 / (randint(6) + 6);"
- * gives avg damage of .327, ranging from .427 to .250
- * Note that "dam = dam * 2 / (randint(6) + 6);"
- * gives something simple.
- *
- * In this function, "result" messages are postponed until the end, where
- * the "note" string is appended to the monster name, if not NULL. So,
- * to make a spell have "no effect" just set "note" to NULL. You should
- * also set "notice" to FALSE, or the player will learn what the spell does.
- *
- * We attempt to return "TRUE" if the player saw anything "useful" happen.
- */
-bool_ project_m(int who, int r, int y, int x, int dam, int typ)
-{
- int tmp;
-
- cave_type *c_ptr = &cave[y][x];
-
- monster_type *m_ptr = &m_list[c_ptr->m_idx];
-
- monster_race *r_ptr = race_inf(m_ptr);
-
- char killer [80];
-
- cptr name = (r_name + r_ptr->name);
-
- /* Is the monster "seen"? */
- bool_ seen;
-
- /* Were the effects "obvious" (if seen)? */
- bool_ obvious = FALSE;
-
- /* Were the effects "irrelevant"? */
- bool_ skipped = FALSE;
-
-
- /* Move setting */
- int x1 = 0;
- int y1 = 0;
- int a = 0;
- int b = 0;
- int do_move = 0;
-
- /* Polymorph setting (true or false) */
- int do_poly = 0;
-
- /* Teleport setting (max distance) */
- int do_dist = 0;
-
- /* Confusion setting (amount to confuse) */
- int do_conf = 0;
-
- /* Stunning setting (amount to stun) */
- int do_stun = 0;
-
- /* Bleeding amount */
- int do_cut = 0;
-
- /* Poison amount */
- int do_pois = 0;
-
- /* Sleep amount (amount to sleep) */
- int do_sleep = 0;
-
- /* Fear amount (amount to fear) */
- int do_fear = 0;
-
-
- /* Hold the monster name */
- char m_name[80];
-
- /* Assume no note */
- cptr note = NULL;
-
- /* Assume a default death */
- cptr note_dies = " dies.";
-
-
- /* Nobody here */
- if (!c_ptr->m_idx) return (FALSE);
-
- /* Never affect projector */
- if (who && (c_ptr->m_idx == who)) return (FALSE);
-
- /*
- * Don't affect already dead monsters
- * Prevents problems with chain reactions of exploding monsters
- */
- if (m_ptr->hp < 0) return (FALSE);
-
-
- /* Remember if the monster is within player's line of sight */
- seen = (m_ptr->ml && ((who != -101) && (who != -100))) ? TRUE : FALSE;
-
- /* Reduce damage by distance */
- dam = (dam + r) / (r + 1);
-
-
- /* Get the monster name (BEFORE polymorphing) */
- monster_desc(m_name, m_ptr, 0);
-
- /* Mega Gachk */
- if (r_ptr->flags2 & RF2_DEATH_ORB)
- {
- msg_format("%^s is immune to magic.", m_name);
- return seen;
- }
-
- /* Some monsters get "destroyed" */
- if ((r_ptr->flags3 & (RF3_DEMON)) ||
- (r_ptr->flags3 & (RF3_UNDEAD)) ||
- (r_ptr->flags2 & (RF2_STUPID)) ||
- (r_ptr->flags3 & (RF3_NONLIVING)) ||
- (strchr("Evg", r_ptr->d_char)))
- {
- /* Special note at death */
- note_dies = " is destroyed.";
- }
-
- if (!who && (is_friend(m_ptr) >= 0))
- {
- bool_ get_angry = FALSE;
- /* Grrr? */
- switch (typ)
- {
- case GF_AWAY_UNDEAD:
- case GF_AWAY_EVIL:
- case GF_AWAY_ALL:
- case GF_CHARM:
- case GF_CHARM_UNMOVING:
- case GF_STAR_CHARM:
- case GF_CONTROL_UNDEAD:
- case GF_CONTROL_ANIMAL:
- case GF_CONTROL_DEMON:
- case GF_OLD_HEAL:
- case GF_OLD_SPEED:
- case GF_DARK_WEAK:
- case GF_JAM_DOOR:
- case GF_RAISE:
- case GF_RAISE_DEMON:
- case GF_IDENTIFY:
- break; /* none of the above anger */
- case GF_TRAP_DEMONSOUL:
- if (r_ptr->flags3 & RF3_DEMON)
- get_angry = TRUE;
- break;
- case GF_KILL_WALL:
- if (r_ptr->flags3 & (RF3_HURT_ROCK))
- get_angry = TRUE;
- break;
- case GF_HOLY_FIRE:
- if (!(r_ptr->flags3 & (RF3_GOOD)))
- get_angry = TRUE;
- break;
- case GF_TURN_UNDEAD:
- case GF_DISP_UNDEAD:
- if (r_ptr->flags3 & RF3_UNDEAD)
- get_angry = TRUE;
- break;
- case GF_TURN_EVIL:
- case GF_DISP_EVIL:
- if (r_ptr->flags3 & RF3_EVIL)
- get_angry = TRUE;
- break;
- case GF_DISP_GOOD:
- if (r_ptr->flags3 & RF3_GOOD)
- get_angry = TRUE;
- break;
- case GF_DISP_DEMON:
- if (r_ptr->flags3 & RF3_DEMON)
- get_angry = TRUE;
- break;
- case GF_DISP_LIVING:
- case GF_UNBREATH:
- if (!(r_ptr->flags3 & (RF3_UNDEAD)) &&
- !(r_ptr->flags3 & (RF3_NONLIVING)))
- get_angry = TRUE;
- break;
- case GF_PSI:
- case GF_PSI_DRAIN:
- if (!(r_ptr->flags2 & (RF2_EMPTY_MIND)))
- get_angry = TRUE;
- break;
- case GF_DOMINATION:
- if (!(r_ptr->flags3 & (RF3_NO_CONF)))
- get_angry = TRUE;
- break;
- case GF_OLD_POLY:
- case GF_OLD_CLONE:
- if (randint(8) == 1)
- get_angry = TRUE;
- break;
- case GF_LITE:
- case GF_LITE_WEAK:
- if (r_ptr->flags3 & RF3_HURT_LITE)
- get_angry = TRUE;
- break;
- default:
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_EXEC, "d", "(s,d,d,d,d,d,d,M)", "angry", who, typ, dam, r, y, x, m_ptr))
- {
- get_angry = process_hooks_return[0].num;
- }
- else
- get_angry = TRUE;
- }
-
- /* Now anger it if appropriate */
- if (get_angry == TRUE && !(who))
- {
- switch (is_friend(m_ptr))
- {
- case 1:
- if (change_side(m_ptr)) msg_format("%^s gets angry!", m_name);
- break;
- case 0:
- msg_format("%^s gets angry!", m_name);
- m_ptr->status = MSTATUS_NEUTRAL_M;
- break;
- }
- }
- }
-
-
- /* Analyze the damage type */
- switch (typ)
- {
- case GF_ATTACK:
- {
- if (seen) obvious = TRUE;
-
- py_attack(y, x, dam);
-
- skipped = TRUE;
-
- dam = 0;
- break;
- }
-
- case GF_IDENTIFY:
- {
- if (seen) obvious = TRUE;
-
- /* Probe */
- do_probe(c_ptr->m_idx);
-
- dam = 0;
- break;
- }
-
- /* Death -- instant death */
- case GF_DEATH:
- {
- if (seen) obvious = TRUE;
-
- if (r_ptr->r_flags1 & RF1_UNIQUE)
- {
- note = " resists.";
- dam = 0;
- }
- else
- {
- /* It KILLS */
- dam = 32535;
- }
- break;
- }
- /* Magic Missile -- pure damage */
- case GF_MISSILE:
- {
- if (seen) obvious = TRUE;
- break;
- }
-
- /* Acid */
- case GF_ACID:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags9 & (RF9_SUSCEP_ACID))
- {
- note = " is hit hard.";
- dam *= 3;
- if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_ACID);
- }
- if (r_ptr->flags3 & (RF3_IM_ACID))
- {
- note = " resists a lot.";
- dam /= 9;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_ACID);
- }
- break;
- }
-
- /* Electricity */
- case GF_ELEC:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags9 & (RF9_SUSCEP_ELEC))
- {
- note = " is hit hard.";
- dam *= 3;
- if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_ELEC);
- }
- if (r_ptr->flags3 & (RF3_IM_ELEC))
- {
- note = " resists a lot.";
- dam /= 9;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_ELEC);
- }
- break;
- }
-
- /* Fire damage */
- case GF_FIRE:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_SUSCEP_FIRE))
- {
- note = " is hit hard.";
- dam *= 3;
- if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_FIRE);
- }
- if (r_ptr->flags3 & (RF3_IM_FIRE))
- {
- note = " resists a lot.";
- dam /= 9;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_FIRE);
- }
- break;
- }
-
- /* Cold */
- case GF_COLD:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_SUSCEP_COLD))
- {
- note = " is hit hard.";
- dam *= 3;
- if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_COLD);
- }
- if (r_ptr->flags3 & (RF3_IM_COLD))
- {
- note = " resists a lot.";
- dam /= 9;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_COLD);
- }
- break;
- }
-
- /* Poison */
- case GF_POIS:
- {
- if (seen) obvious = TRUE;
- if (magik(25)) do_pois = (10 + randint(11) + r) / (r + 1);
- if (r_ptr->flags9 & (RF9_SUSCEP_POIS))
- {
- note = " is hit hard.";
- dam *= 3;
- do_pois *= 2;
- if (seen) r_ptr->r_flags9 |= (RF9_SUSCEP_POIS);
- }
- if (r_ptr->flags3 & (RF3_IM_POIS))
- {
- note = " resists a lot.";
- dam /= 9;
- do_pois = 0;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_POIS);
- }
- break;
- }
-
-
- /* Thick Poison */
- case GF_UNBREATH:
- {
- if (seen) obvious = TRUE;
- if (magik(15)) do_pois = (10 + randint(11) + r) / (r + 1);
- if ((r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)))
- {
- note = " is immune.";
- dam = 0;
- do_pois = 0;
- }
- break;
- }
-
- /* Nuclear waste */
- case GF_NUKE:
- {
- if (seen) obvious = TRUE;
-
- if (r_ptr->flags3 & (RF3_IM_POIS))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen) r_ptr->r_flags3 |= (RF3_IM_POIS);
- }
- else if (randint(3) == 1) do_poly = TRUE;
- break;
- }
-
- /* Holy Orb -- hurts Evil (replaced with Hellfire) */
- case GF_HELL_FIRE:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_EVIL))
- {
- dam *= 2;
- note = " is hit hard.";
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
- }
- break;
- }
-
- /* Holy Fire -- hurts Evil, Good are immune, others _resist_ */
- case GF_HOLY_FIRE:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_GOOD))
- {
- dam = 0;
- note = " is immune.";
- if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
- }
- else if (r_ptr->flags3 & (RF3_EVIL))
- {
- dam *= 2;
- note = " is hit hard.";
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
- }
- else
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- }
- break;
- }
-
- /* Arrow -- XXX no defense */
- case GF_ARROW:
- {
- if (seen) obvious = TRUE;
- break;
- }
-
- /* Plasma -- XXX perhaps check ELEC or FIRE */
- case GF_PLASMA:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_RES_PLAS))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen)
- r_ptr->r_flags3 |= (RF3_RES_PLAS);
- }
- break;
- }
-
- /* Nether -- see above */
- case GF_NETHER:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- note = " is immune.";
- dam = 0;
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
- }
- else if (r_ptr->flags3 & (RF3_RES_NETH))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
-
- if (seen) r_ptr->r_flags3 |= (RF3_RES_NETH);
- }
- else if (r_ptr->flags3 & (RF3_EVIL))
- {
- dam /= 2;
- note = " resists somewhat.";
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
- }
- break;
- }
-
- /* Water (acid) damage -- Water spirits/elementals are immune */
- case GF_WATER:
- {
- if (seen) obvious = TRUE;
- if ((r_ptr->d_char == 'E') &&
- (prefix(name, "W") ||
- (strstr((r_name + r_ptr->name), "Unmaker"))))
- {
- note = " is immune.";
- dam = 0;
- }
- else if (r_ptr->flags3 & (RF3_RES_WATE))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen) r_ptr->r_flags3 |= (RF3_RES_WATE);
- }
- break;
- }
-
- /* Wave = Water + Force */
- case GF_WAVE:
- {
- if (seen) obvious = TRUE;
- if ((r_ptr->d_char == 'E') &&
- (prefix(name, "W") ||
- (strstr((r_name + r_ptr->name), "Unmaker"))))
- {
- note = " is immune.";
- dam = 0;
- }
- else if (r_ptr->flags3 & (RF3_RES_WATE))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen) r_ptr->r_flags3 |= (RF3_RES_WATE);
- }
-
- if (who == 0)
- {
- a = 0;
- b = 0;
-
- /* Get vector from firer to target */
- x1 = (m_ptr->fx - p_ptr->px) * 10;
- y1 = (m_ptr->fy - p_ptr->py) * 10;
-
- /* Make sure no zero divides */
- if (x1 == 0) x1 = 1;
- if (y1 == 0) y1 = 1;
-
- /* Select direction monster is being pushed */
-
- /* Roughly horizontally */
- if ((2*y1) / x1 == 0)
- {
- if (x1 > 0)
- {
- a = 1, b = 0;
- }
- else
- {
- a = -1, b = 0;
- }
- }
-
- /* Roughly vertically */
- else if ((2*x1) / y1 == 0)
- {
- if (y1 > 0)
- {
- a = 0, b = 1;
- }
- else
- {
- a = 0, b = -1;
- }
- }
-
- /* Take diagonals */
- else
- {
- if (y1 > 0)
- {
- b = 1;
- }
- else
- {
- b = -1;
- }
- if (x1 > 0)
- {
- a = 1;
- }
- else
- {
- a = -1;
- }
- }
-
- /* Move monster 2 offsets back */
- do_move = 2;
-
- /* Old monster coords in x,y */
- y1 = m_ptr->fy;
- x1 = m_ptr->fx;
-
- /* Monster move offsets in a,b */
- note = " is thrown away.";
- }
- break;
- }
-
- /* Chaos -- Chaos breathers resist */
- case GF_CHAOS:
- {
- if (seen) obvious = TRUE;
- do_poly = TRUE;
- do_conf = (5 + randint(11) + r) / (r + 1);
- if ((r_ptr->flags4 & (RF4_BR_CHAO)) ||
- ((r_ptr->flags3 & (RF3_DEMON)) && (randint(3) == 1)))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- do_poly = FALSE;
- }
- break;
- }
-
- /* Shards -- Shard breathers resist */
- case GF_SHARDS:
- {
- if (seen) obvious = TRUE;
- if (magik(33)) do_cut = (10 + randint(15) + r) / (r + 1);
- if (r_ptr->flags4 & (RF4_BR_SHAR))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- do_cut = 0;
- }
- break;
- }
-
- /* Rocket: Shard resistance helps */
- case GF_ROCKET:
- {
- if (seen) obvious = TRUE;
-
- if (magik(12)) do_cut = (10 + randint(15) + r) / (r + 1);
- if (r_ptr->flags4 & (RF4_BR_SHAR))
- {
- note = " resists somewhat.";
- dam /= 2;
- do_cut = 0;
- }
- break;
- }
-
-
- /* Sound -- Sound breathers resist */
- case GF_SOUND:
- {
- if (seen) obvious = TRUE;
- if (who <= 0)
- {
- if (rand_int(100 - p_ptr->lev) < 50)
- do_stun = (10 + randint(15) + r) / (r + 1);
- }
- else
- do_stun = (10 + randint(15) + r) / (r + 1);
- if (r_ptr->flags4 & (RF4_BR_SOUN))
- {
- note = " resists.";
- dam *= 2;
- dam /= (randint(6) + 6);
- }
- break;
- }
-
- /* Confusion */
- case GF_CONFUSION:
- {
- if (seen) obvious = TRUE;
- do_conf = (10 + randint(15) + r) / (r + 1);
- if (r_ptr->flags4 & (RF4_BR_CONF))
- {
- note = " resists.";
- dam *= 2;
- dam /= (randint(6) + 6);
- }
- else if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- note = " resists somewhat.";
- dam /= 2;
- }
- break;
- }
-
- /* Disenchantment -- Breathers and Disenchanters resist */
- case GF_DISENCHANT:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_RES_DISE))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen) r_ptr->r_flags3 |= (RF3_RES_DISE);
- }
- break;
- }
-
- /* Nexus -- Breathers and Existers resist */
- case GF_NEXUS:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_RES_NEXU))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- if (seen) r_ptr->r_flags3 |= (RF3_RES_NEXU);
- }
- break;
- }
-
- /* Force */
- case GF_FORCE:
- {
- if (seen) obvious = TRUE;
-
- /*
- * If fired by player, try pushing monster.
- * First get vector from player to monster.
- * x10 so we can use pseudo-fixed point maths.
- *
- * Really should use get_angle_to_grid (util.c)
- */
- if (who == 0)
- {
- a = 0;
- b = 0;
-
- /* Get vector from firer to target */
- x1 = (m_ptr->fx - p_ptr->px) * 10;
- y1 = (m_ptr->fy - p_ptr->py) * 10;
-
- /* Make sure no zero divides */
- if (x1 == 0) x1 = 1;
- if (y1 == 0) y1 = 1;
-
- /* Select direction monster is being pushed */
-
- /* Roughly horizontally */
- if ((2*y1) / x1 == 0)
- {
- if (x1 > 0)
- {
- a = 1, b = 0;
- }
- else
- {
- a = -1, b = 0;
- }
- }
-
- /* Roughly vertically */
- else if ((2*x1) / y1 == 0)
- {
- if (y1 > 0)
- {
- a = 0, b = 1;
- }
- else
- {
- a = 0, b = -1;
- }
- }
-
- /* Take diagonals */
- else
- {
- if (y1 > 0)
- {
- b = 1;
- }
- else
- {
- b = -1;
- }
- if (x1 > 0)
- {
- a = 1;
- }
- else
- {
- a = -1;
- }
- }
-
- /* Move monster 2 offsets back */
- do_move = 2;
-
- /* Old monster coords in x,y */
- y1 = m_ptr->fy;
- x1 = m_ptr->fx;
-
- /* Monster move offsets in a,b */
- note = " is thrown away.";
- }
-
- /* --hack-- Only stun if a monster fired it */
- else do_stun = (randint(15) + r) / (r + 1);
-
- if (r_ptr->flags4 & (RF4_BR_WALL))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- }
- break;
- }
-
- /* Inertia -- breathers resist */
- case GF_INERTIA:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags4 & (RF4_BR_INER))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- }
- else
- {
- /* Powerful monsters can resist */
- if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
- {
- obvious = FALSE;
- }
- /* Normal monsters slow down */
- else
- {
- if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
- note = " starts moving slower.";
- }
- }
- break;
- }
-
- /* Time -- breathers resist */
- case GF_TIME:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags4 & (RF4_BR_TIME))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- }
- break;
- }
-
- /* Gravity -- breathers resist */
- case GF_GRAVITY:
- {
- bool_ resist_tele = FALSE;
-
- if (seen) obvious = TRUE;
-
- if (r_ptr->flags3 & (RF3_RES_TELE))
- {
- if (r_ptr->flags1 & (RF1_UNIQUE))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " is unaffected!";
- resist_tele = TRUE;
- }
- else if (m_ptr->level > randint(100))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " resists!";
- resist_tele = TRUE;
- }
- }
-
- if (!resist_tele) do_dist = 10;
- else do_dist = 0;
-
- if (r_ptr->flags4 & (RF4_BR_GRAV))
- {
- note = " resists.";
- dam *= 3;
- dam /= (randint(6) + 6);
- do_dist = 0;
- }
- else
- {
- /* 1. slowness */
- /* Powerful monsters can resist */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- obvious = FALSE;
- }
- /* Normal monsters slow down */
- else
- {
- if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
- note = " starts moving slower.";
- }
-
- /* 2. stun */
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- do_stun = 0;
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- }
- break;
- }
-
- /* Pure damage */
- case GF_MANA:
- {
- if (seen) obvious = TRUE;
- break;
- }
-
-
- /* Pure damage */
- case GF_DISINTEGRATE:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags3 & (RF3_HURT_ROCK))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_HURT_ROCK);
- note = " loses some skin!";
- note_dies = " evaporates!";
- dam *= 2;
- }
-
- if (r_ptr->flags1 & RF1_UNIQUE)
- {
- if (rand_int(m_ptr->level + 10) > rand_int(p_ptr->lev))
- {
- note = " resists.";
- dam >>= 3;
- }
- }
- break;
- }
-
- case GF_FEAR:
- {
- if (r_ptr->flags3 & (RF3_NO_FEAR))
- note = " is unaffected.";
- else
- set_afraid(p_ptr->afraid + (dam / 2) + randint(dam / 2));
-
- /* No damage */
- dam = 0;
- break;
- }
-
- case GF_PSI:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags2 & RF2_EMPTY_MIND)
- {
- dam = 0;
- note = " is immune!";
- }
- else if ((r_ptr->flags2 & RF2_STUPID) ||
- (r_ptr->flags2 & RF2_WEIRD_MIND) ||
- (r_ptr->flags3 & RF3_ANIMAL) ||
- (m_ptr->level > randint(3 * dam)))
- {
- dam /= 3;
- note = " resists.";
-
- /* Powerful demons & undead can turn a mindcrafter's
- * attacks back on them */
- if (((r_ptr->flags3 & RF3_UNDEAD) ||
- (r_ptr->flags3 & RF3_DEMON)) &&
- (m_ptr->level > p_ptr->lev / 2) &&
- (randint(2) == 1))
- {
- note = NULL;
- msg_format("%^s%s corrupted mind backlashes your attack!",
- m_name, (seen ? "'s" : "s"));
- /* Saving throw */
- if (rand_int(100) < p_ptr->skill_sav)
- {
- msg_print("You resist the effects!");
- }
- else
- {
- /* Injure +/- confusion */
- monster_desc(killer, m_ptr, 0x88);
- take_hit(dam, killer); /* has already been /3 */
- if (randint(4) == 1)
- {
- switch (randint(4))
- {
- case 1:
- set_confused(p_ptr->confused + 3 + randint(dam));
- break;
- case 2:
- set_stun(p_ptr->stun + randint(dam));
- break;
- case 3:
- {
- if (r_ptr->flags3 & (RF3_NO_FEAR))
- note = " is unaffected.";
- else
- set_afraid(p_ptr->afraid + 3 + randint(dam));
- break;
- }
- default:
- if (!p_ptr->free_act)
- (void)set_paralyzed(p_ptr->paralyzed + randint(dam));
- break;
- }
- }
- }
- dam = 0;
- }
- }
-
- if ((dam > 0) && (randint(4) == 1))
- {
- switch (randint(4))
- {
- case 1:
- do_conf = 3 + randint(dam);
- break;
- case 2:
- do_stun = 3 + randint(dam);
- break;
- case 3:
- do_fear = 3 + randint(dam);
- break;
- default:
- do_sleep = 3 + randint(dam);
- break;
- }
- }
-
- note_dies = " collapses, a mindless husk.";
- break;
- }
-
- case GF_PSI_DRAIN:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags2 & RF2_EMPTY_MIND)
- {
- dam = 0;
- note = " is immune!";
- }
- else if ((r_ptr->flags2 & RF2_STUPID) ||
- (r_ptr->flags2 & RF2_WEIRD_MIND) ||
- (r_ptr->flags3 & RF3_ANIMAL) ||
- (m_ptr->level > randint(3 * dam)))
- {
- dam /= 3;
- note = " resists.";
-
- /*
- * Powerful demons & undead can turn a mindcrafter's
- * attacks back on them
- */
- if (((r_ptr->flags3 & RF3_UNDEAD) ||
- (r_ptr->flags3 & RF3_DEMON)) &&
- (m_ptr->level > p_ptr->lev / 2) &&
- (randint(2) == 1))
- {
- note = NULL;
- msg_format("%^s%s corrupted mind backlashes your attack!",
- m_name, (seen ? "'s" : "s"));
- /* Saving throw */
- if (rand_int(100) < p_ptr->skill_sav)
- {
- msg_print("You resist the effects!");
- }
- else
- {
- /* Injure + mana drain */
- monster_desc(killer, m_ptr, 0x88);
- msg_print("Your psychic energy is drained!");
- p_ptr->csp = MAX(0, p_ptr->csp - damroll(5, dam) / 2);
- p_ptr->redraw |= PR_MANA;
- take_hit(dam, killer); /* has already been /3 */
- }
- dam = 0;
- }
- }
- else if (dam > 0)
- {
- int b = damroll(5, dam) / 4;
- msg_format("You convert %s%s pain into psychic energy!",
- m_name, (seen ? "'s" : "s"));
- b = MIN(p_ptr->msp, p_ptr->csp + b);
- p_ptr->csp = b;
- p_ptr->redraw |= PR_MANA;
- }
-
- note_dies = " collapses, a mindless husk.";
- break;
- }
-
- case GF_TELEKINESIS:
- {
- if (seen) obvious = TRUE;
- do_dist = 7;
- /* 1. stun */
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > 5 + randint(dam)))
- {
- /* Resist */
- do_stun = 0;
- /* No obvious effect */
- obvious = FALSE;
- }
- break;
- }
-
- /* Meteor -- powerful magic missile */
- case GF_METEOR:
- {
- if (seen) obvious = TRUE;
- break;
- }
-
- case GF_DOMINATION:
- {
- if (is_friend(m_ptr) > 0) break;
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (r_ptr->flags3 & (RF3_NO_CONF)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- do_conf = 0;
-
- /*
- * Powerful demons & undead can turn a mindcrafter's
- * attacks back on them
- */
- if (((r_ptr->flags3 & RF3_UNDEAD) ||
- (r_ptr->flags3 & RF3_DEMON)) &&
- (m_ptr->level > p_ptr->lev / 2) &&
- (randint(2) == 1))
- {
- note = NULL;
- msg_format("%^s%s corrupted mind backlashes your attack!",
- m_name, (seen ? "'s" : "s"));
- /* Saving throw */
- if (rand_int(100) < p_ptr->skill_sav)
- {
- msg_print("You resist the effects!");
- }
- else
- {
- /* Confuse, stun, terrify */
- switch (randint(4))
- {
- case 1:
- set_stun(p_ptr->stun + dam / 2);
- break;
- case 2:
- set_confused(p_ptr->confused + dam / 2);
- break;
- default:
- {
- if (r_ptr->flags3 & (RF3_NO_FEAR))
- note = " is unaffected.";
- else
- set_afraid(p_ptr->afraid + dam);
- }
- }
- }
- }
- else
- {
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- }
- else
- {
- if ((dam > 29) && (randint(100) < dam))
- {
- note = " is in your thrall!";
- m_ptr->status = MSTATUS_PET;
- if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
- inc_piety(GOD_YAVANNA, m_ptr->level * 2);
- }
- else
- {
- switch (randint(4))
- {
- case 1:
- do_stun = dam / 2;
- break;
- case 2:
- do_conf = dam / 2;
- break;
- default:
- do_fear = dam;
- }
- }
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
-
- /* Ice -- Cold + Cuts + Stun */
- case GF_ICE:
- {
- if (seen) obvious = TRUE;
- do_stun = (randint(15) + 1) / (r + 1);
- if (magik(33)) do_cut = (10 + randint(15) + r) / (r + 1);
- if (r_ptr->flags3 & (RF3_SUSCEP_COLD))
- {
- note = " is hit hard.";
- dam *= 3;
- do_cut *= 2;
- if (seen) r_ptr->r_flags3 |= (RF3_SUSCEP_COLD);
- }
- if (r_ptr->flags3 & (RF3_IM_COLD))
- {
- note = " resists a lot.";
- dam /= 9;
- do_cut = 0;
- if (seen) r_ptr->r_flags3 |= (RF3_IM_COLD);
- }
- break;
- }
-
-
- /* Drain Life */
- case GF_OLD_DRAIN:
- {
- if (seen) obvious = TRUE;
-
- if ((r_ptr->flags3 & (RF3_UNDEAD)) ||
- (r_ptr->flags3 & (RF3_DEMON)) ||
- (r_ptr->flags3 & (RF3_NONLIVING)) ||
- (strchr("Egv", r_ptr->d_char)))
- {
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
- }
- if (r_ptr->flags3 & (RF3_DEMON))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_DEMON);
- }
-
- note = " is unaffected!";
- obvious = FALSE;
- dam = 0;
- }
-
- break;
- }
-
- /* Death Ray */
- case GF_DEATH_RAY:
- {
- if (seen) obvious = TRUE;
- if ((r_ptr->flags3 & (RF3_UNDEAD)) ||
- (r_ptr->flags3 & (RF3_NONLIVING)))
- {
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
- }
-
- note = " is immune.";
- obvious = FALSE;
- dam = 0;
- }
- else if (((r_ptr->flags1 & (RF1_UNIQUE)) &&
- (randint(888) != 666)) ||
- (((m_ptr->level + randint(20)) > randint((dam) + randint(10))) &&
- randint(100) != 66 ))
- {
- note = " resists!";
- obvious = FALSE;
- dam = 0;
- }
-
- else dam = (p_ptr->lev) * 200;
-
- break;
- }
-
- /* Polymorph monster (Use "dam" as "power") */
- case GF_OLD_POLY:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt to polymorph (see below) */
- do_poly = TRUE;
-
- /* Powerful monsters can resist */
- if ((r_ptr->flags1 & RF1_UNIQUE) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- note = " is unaffected!";
- do_poly = FALSE;
- obvious = FALSE;
- }
-
- /* No "real" damage */
- dam = 0;
-
- break;
- }
-
-
- /* Clone monsters (Ignore "dam") */
- case GF_OLD_CLONE:
- {
- bool_ is_frien = FALSE;
-
- if (seen) obvious = TRUE;
- if ((is_friend(m_ptr) > 0) && (randint(3) != 1))
- is_frien = TRUE;
-
- /* Heal fully */
- m_ptr->hp = m_ptr->maxhp;
-
- /* Speed up */
- if (m_ptr->mspeed < 150) m_ptr->mspeed += 10;
-
- /* Attempt to clone. */
- if (multiply_monster(c_ptr->m_idx, is_frien, TRUE))
- {
- note = " spawns!";
- }
-
- /* No "real" damage */
- dam = 0;
-
- break;
- }
-
-
- /* Heal Monster (use "dam" as amount of healing) */
- case GF_OLD_HEAL:
- {
- if (seen) obvious = TRUE;
-
- /* Wake up */
- m_ptr->csleep = 0;
-
- /* Heal */
- m_ptr->hp += dam;
-
- /* No overflow */
- if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
-
- /* Redraw (later) if needed */
- if (health_who == c_ptr->m_idx) p_ptr->redraw |= (PR_HEALTH);
-
- /* Message */
- note = " looks healthier.";
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Speed Monster (Ignore "dam") */
- case GF_OLD_SPEED:
- {
- if (seen) obvious = TRUE;
-
- /* Speed up */
- if (m_ptr->mspeed < m_ptr->speed + 15) m_ptr->mspeed += 10;
- note = " starts moving faster.";
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Slow Monster (Use "dam" as "power") */
- case GF_OLD_SLOW:
- {
- if (seen) obvious = TRUE;
-
- /* Powerful monsters can resist */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- note = " is unaffected!";
- obvious = FALSE;
- }
-
- /* Normal monsters slow down */
- else
- {
- if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
- note = " starts moving slower.";
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Sleep (Use "dam" as "power") */
- case GF_OLD_SLEEP:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags3 & (RF3_NO_SLEEP)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_SLEEP))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_SLEEP);
- }
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else
- {
- /* Go to sleep (much) later */
- note = " falls asleep!";
- do_sleep = 500;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Sleep (Use "dam" as "power") */
- case GF_STASIS:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- note = " is unaffected!";
- obvious = FALSE;
- }
- else
- {
- /* Go to sleep (much) later */
- note = " is suspended!";
- do_sleep = 500;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Charm monster */
- case GF_CHARM:
- {
- dam += (adj_con_fix[p_ptr->stat_ind[A_CHR]] - 1);
-
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((m_ptr->mflag & MFLAG_QUEST) ||
- (r_ptr->flags3 & RF3_NO_CONF) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 5))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- if (is_friend(m_ptr) < 0)
- {
- note = " suddenly seems friendly!";
- m_ptr->status = MSTATUS_FRIEND;
- if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
- inc_piety(GOD_YAVANNA, m_ptr->level * 2);
- }
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* *Charm* monster */
- case GF_STAR_CHARM:
- {
- dam += (adj_con_fix[p_ptr->stat_ind[A_CHR]] - 1);
-
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((m_ptr->mflag & MFLAG_QUEST) ||
- (r_ptr->flags3 & RF3_NO_CONF) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 5))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- if (is_friend(m_ptr) < 0)
- {
- note = " suddenly seems friendly!";
- if (can_create_companion()) m_ptr->status = MSTATUS_COMPANION;
- else m_ptr->status = MSTATUS_PET;
-
- if ((r_ptr->flags3 & RF3_ANIMAL) && (!(r_ptr->flags3 & RF3_EVIL)))
- inc_piety(GOD_YAVANNA, m_ptr->level * 2);
- }
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Control undead */
- case GF_CONTROL_UNDEAD:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & RF1_UNIQUE) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (!(r_ptr->flags3 & RF3_UNDEAD)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- note = " is in your thrall!";
- m_ptr->status = MSTATUS_PET;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Control never-moving */
- case GF_CHARM_UNMOVING:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & RF1_UNIQUE) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (!(r_ptr->flags1 & RF1_NEVER_MOVE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- note = " is in your thrall!";
- m_ptr->status = MSTATUS_PET;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Tame animal */
- case GF_CONTROL_ANIMAL:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (!(r_ptr->flags3 & (RF3_ANIMAL))) ||
- (r_ptr->flags3 & (RF3_NO_CONF)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- note = " is tamed!";
- m_ptr->status = MSTATUS_PET;
- inc_piety(GOD_YAVANNA, m_ptr->level * 2);
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Control demon */
- case GF_CONTROL_DEMON:
- {
- if (seen) obvious = TRUE;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (!(r_ptr->flags3 & (RF3_DEMON))) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- else if (p_ptr->aggravate)
- {
- note = " hates you too much!";
- }
- else
- {
- note = " obeys your commands!";
- m_ptr->status = MSTATUS_PET;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Confusion (Use "dam" as "power") */
- case GF_OLD_CONF:
- {
- if (seen) obvious = TRUE;
-
- /* Get confused later */
- do_conf = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- do_conf = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- case GF_STUN:
- {
- if (seen) obvious = TRUE;
-
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- do_stun = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Confusion (Use "dam" as "power") */
- case GF_CONF_DAM:
- {
- if (seen) obvious = TRUE;
-
- /* Get confused later */
- do_conf = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- do_conf = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- break;
- }
-
- case GF_STUN_DAM:
- {
- if (seen) obvious = TRUE;
-
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- do_stun = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- break;
- }
-
- /* Implosion is the same than Stun_dam but only affect the living */
- case GF_IMPLOSION:
- {
- if (seen) obvious = TRUE;
-
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- do_stun = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
-
- /* Non_living resists */
- if (r_ptr->flags3 & (RF3_NONLIVING))
- {
- /* Resist */
- do_stun = 0;
- dam = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- break;
- }
-
- /* Confusion & Stunning (Use "dam" as "power") */
- case GF_STUN_CONF:
- {
- if (seen) obvious = TRUE;
-
- /* Get confused later */
- do_conf = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags3 & (RF3_NO_CONF)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Memorize a flag */
- if (r_ptr->flags3 & (RF3_NO_CONF))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_NO_CONF);
- }
-
- /* Resist */
- do_conf = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
-
- do_stun = damroll((p_ptr->lev / 10) + 3 , (dam)) + 1;
-
- /* Attempt a saving throw */
- if ((m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* Resist */
- do_stun = 0;
-
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- }
- break;
- }
-
-
- /* Lite, but only hurts susceptible creatures */
- case GF_LITE_WEAK:
- {
- /* Hurt by light */
- if (r_ptr->flags3 & (RF3_HURT_LITE))
- {
- /* Obvious effect */
- if (seen) obvious = TRUE;
-
- /* Memorize the effects */
- if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
-
- /* Special effect */
- note = " cringes from the light!";
- note_dies = " shrivels away in the light!";
- }
-
- /* Normally no damage */
- else
- {
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
-
-
- /* Lite -- opposite of Dark */
- case GF_LITE:
- {
- if (seen) obvious = TRUE;
- if (r_ptr->flags4 & (RF4_BR_LITE))
- {
- note = " resists.";
- dam *= 2;
- dam /= (randint(6) + 6);
- }
- else if (r_ptr->flags3 & (RF3_HURT_LITE))
- {
- if (seen) r_ptr->r_flags3 |= (RF3_HURT_LITE);
- note = " cringes from the light!";
- note_dies = " shrivels away in the light!";
- dam *= 2;
- }
- break;
- }
-
-
- /* Dark -- opposite of Lite */
- case GF_DARK:
- {
- if (seen) obvious = TRUE;
-
- /* Likes darkness... */
- if ((r_ptr->flags4 & (RF4_BR_DARK)) ||
- (r_ptr->flags3 & RF3_ORC) ||
- (r_ptr->flags3 & RF3_HURT_LITE))
- {
- note = " resists.";
- dam *= 2;
- dam /= (randint(6) + 6);
- }
- break;
- }
-
-
- /* Stone to Mud */
- case GF_KILL_WALL:
- {
- /* Hurt by rock remover */
- if (r_ptr->flags3 & (RF3_HURT_ROCK))
- {
- /* Notice effect */
- if (seen) obvious = TRUE;
-
- /* Memorize the effects */
- if (seen) r_ptr->r_flags3 |= (RF3_HURT_ROCK);
-
- /* Cute little message */
- note = " loses some skin!";
- note_dies = " dissolves!";
- }
-
- /* Usually, ignore the effects */
- else
- {
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
-
- /* Teleport undead (Use "dam" as "power") */
- case GF_AWAY_UNDEAD:
- {
-
- if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
- /* Only affect undead */
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- bool_ resists_tele = FALSE;
-
- if (r_ptr->flags3 & (RF3_RES_TELE))
- {
- if (r_ptr->flags1 & (RF1_UNIQUE))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " is unaffected!";
- resists_tele = TRUE;
- }
- else if (m_ptr->level > randint(100))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " resists!";
- resists_tele = TRUE;
- }
- }
-
- if (!resists_tele)
- {
- if (seen) obvious = TRUE;
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
- do_dist = dam;
- }
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Teleport evil (Use "dam" as "power") */
- case GF_AWAY_EVIL:
- {
- if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
- /* Only affect evil */
- if (r_ptr->flags3 & (RF3_EVIL))
- {
- bool_ resists_tele = FALSE;
-
- if (r_ptr->flags3 & (RF3_RES_TELE))
- {
- if (r_ptr->flags1 & (RF1_UNIQUE))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " is unaffected!";
- resists_tele = TRUE;
- }
- else if (m_ptr->level > randint(100))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " resists!";
- resists_tele = TRUE;
- }
- }
-
- if (!resists_tele)
- {
- if (seen) obvious = TRUE;
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
- do_dist = dam;
- }
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Teleport monster (Use "dam" as "power") */
- case GF_AWAY_ALL:
- {
- bool_ resists_tele = FALSE;
-
- if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
- if (r_ptr->flags3 & (RF3_RES_TELE))
- {
- if (r_ptr->flags1 & (RF1_UNIQUE))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " is unaffected!";
- resists_tele = TRUE;
- }
- else if (m_ptr->level > randint(100))
- {
- if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
- note = " resists!";
- resists_tele = TRUE;
- }
- }
-
- if (!resists_tele)
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Prepare to teleport */
- do_dist = dam;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Turn undead (Use "dam" as "power") */
- case GF_TURN_UNDEAD:
- {
- /* Only affect undead */
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Apply some fear */
- do_fear = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
- {
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- do_fear = 0;
- }
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Turn evil (Use "dam" as "power") */
- case GF_TURN_EVIL:
- {
- /* Only affect evil */
- if (r_ptr->flags3 & (RF3_EVIL))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Apply some fear */
- do_fear = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
- {
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- do_fear = 0;
- }
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Turn monster (Use "dam" as "power") */
- case GF_TURN_ALL:
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Apply some fear */
- do_fear = damroll(3, (dam / 2)) + 1;
-
- /* Attempt a saving throw */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (r_ptr->flags3 & (RF3_NO_FEAR)) ||
- (m_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
- {
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- do_fear = 0;
- }
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
-
- /* Dispel undead */
- case GF_DISP_UNDEAD:
- {
- /* Only affect undead */
- if (r_ptr->flags3 & (RF3_UNDEAD))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
-
- /* Dispel evil */
- case GF_DISP_EVIL:
- {
- /* Only affect evil */
- if (r_ptr->flags3 & (RF3_EVIL))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
- /* Dispel good */
- case GF_DISP_GOOD:
- {
- /* Only affect good */
- if (r_ptr->flags3 & (RF3_GOOD))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
- /* Dispel living */
- case GF_DISP_LIVING:
- {
- /* Only affect non-undead */
- if (!(r_ptr->flags3 & (RF3_UNDEAD)) &&
- !(r_ptr->flags3 & (RF3_NONLIVING)))
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
- /* Dispel demons */
- case GF_DISP_DEMON:
- {
- /* Only affect demons */
- if (r_ptr->flags3 & (RF3_DEMON))
- {
- /* Learn about type */
- if (seen) r_ptr->r_flags3 |= (RF3_DEMON);
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
- }
-
- /* Others ignore */
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
-
- break;
- }
-
- /* Dispel monster */
- case GF_DISP_ALL:
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " shudders.";
- note_dies = " dissolves!";
-
- break;
- }
-
- /* Raise Death -- Heal monster */
- case GF_RAISE:
- {
- if (seen) obvious = TRUE;
-
- /* Wake up */
- m_ptr->csleep = 0;
-
- /* Heal */
- m_ptr->hp += dam;
-
- /* No overflow */
- if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
-
- /* Redraw (later) if needed */
- if (health_who == c_ptr->m_idx) p_ptr->redraw |= (PR_HEALTH);
-
- /* Message */
- note = " looks healthier.";
-
- /* No "real" damage */
- dam = 0;
- break;
- }
-
- /* Trap the soul of a demon and leave body */
- case GF_TRAP_DEMONSOUL:
- {
- if (seen) obvious = TRUE;
-
- /* Check race */
- if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
- (m_ptr->mflag & MFLAG_QUEST) ||
- (!(r_ptr->flags3 & (RF3_DEMON))))
- {
- /* No obvious effect */
- note = " is unaffected!";
- obvious = FALSE;
- dam = 0;
- }
- /* Hack : drop corpse if the demon is killed by this
- * spell */
- else if (dam > m_ptr->hp)
- {
- object_type forge, *i_ptr = &forge;
-
- /* Wipe the object */
- object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_CORPSE));
-
- /* Unique corpses are unique */
- if (r_ptr->flags1 & RF1_UNIQUE)
- {
- object_aware(i_ptr);
- i_ptr->name1 = 201;
- }
-
- /* Length of decay - very long time */
- i_ptr->pval = 100000;
-
- /* Set weight */
- i_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 10) + 1;
-
- /* Remember what we are */
- i_ptr->pval2 = m_ptr->r_idx;
-
- /* Give HP */
- i_ptr->pval3 = maxroll(r_ptr->hdice, r_ptr->hside);
-
- /* Drop it */
- drop_near(i_ptr, -1, y, x);
- }
-
- break;
- }
-
- /* Default */
- default:
- {
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_EXEC, "dddddddddss", "(s,d,d,d,d,d,d,M)", "monster", who, typ, dam, r, y, x, m_ptr))
- {
- obvious = process_hooks_return[0].num;
- dam = process_hooks_return[1].num;
- do_stun = process_hooks_return[2].num;
- do_fear = process_hooks_return[3].num;
- do_conf = process_hooks_return[4].num;
- do_dist = process_hooks_return[5].num;
- do_pois = process_hooks_return[6].num;
- do_cut = process_hooks_return[7].num;
- do_poly = process_hooks_return[8].num;
- if (process_hooks_return[9].str != NULL)
- note = process_hooks_return[9].str;
- if (process_hooks_return[10].str != NULL)
- note_dies = process_hooks_return[10].str;
- }
- else
- {
- /* Irrelevant */
- skipped = TRUE;
-
- /* No damage */
- dam = 0;
- }
- break;
- }
- }
-
-
- /* Absolutely no effect */
- if (skipped) return (FALSE);
-
-
- /* "Unique" monsters cannot be polymorphed */
- if (r_ptr->flags1 & (RF1_UNIQUE)) do_poly = FALSE;
-
- /*
- * "Quest" monsters cannot be polymorphed
- */
- if (m_ptr->mflag & MFLAG_QUEST)
- do_poly = FALSE;
-
- /* "Unique" monsters can only be "killed" by the player unless they are player's friends */
- if ((r_ptr->flags1 & RF1_UNIQUE) && (m_ptr->status <= MSTATUS_NEUTRAL_P))
- {
- /* Uniques may only be killed by the player */
- if (who && (who != -2) && (dam > m_ptr->hp)) dam = m_ptr->hp;
- }
-
- /*
- * "Quest" monsters can only be "killed" by the player
- */
- if (m_ptr->mflag & MFLAG_QUEST)
- {
- if ((who > 0) && (dam > m_ptr->hp)) dam = m_ptr->hp;
- }
-
- if (do_pois && (!(r_ptr->flags3 & RF3_IM_POIS)) && (!(r_ptr->flags3 & RF4_BR_POIS)) && hurt_monster(m_ptr))
- {
- if (m_ptr->poisoned) note = " is more poisoned.";
- else note = " is poisoned.";
- m_ptr->poisoned += do_pois;
- }
-
- if (do_cut && (!(r_ptr->flags4 & RF4_BR_WALL)) && hurt_monster(m_ptr))
- {
- if (m_ptr->bleeding) note = " bleeds more strongly.";
- else note = " starts bleeding.";
- m_ptr->bleeding += do_cut;
- }
-
- /* Check for death */
- if ((dam > m_ptr->hp) && hurt_monster(m_ptr))
- {
- /* Extract method of death */
- note = note_dies;
- }
-
- /* Mega-Hack -- Handle "polymorph" -- monsters get a saving throw */
- else if (do_poly && cave_floor_bold(y, x) && (randint(90) > m_ptr->level))
- {
- /* Default -- assume no polymorph */
- note = " is unaffected!";
-
- /* Handle polymorph */
- if (do_poly_monster(y, x))
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Monster polymorphs */
- note = " changes!";
-
- /* Turn off the damage */
- dam = 0;
-
- /* Hack -- Get new monster */
- m_ptr = &m_list[c_ptr->m_idx];
-
- /* Hack -- Get new race */
- r_ptr = race_inf(m_ptr);
- }
- }
-
- /* Handle moving the monster.
- *
- * Note: This is a effect of force, but only when used
- * by the player. (For the moment). The usual stun effect
- * is not applied.
- */
- else if (do_move && hurt_monster(m_ptr))
- {
- int back = 0;
-
- /* Obvious */
- if (seen) obvious = TRUE;
-
- back = 0; /* Default of no movement */
-
- /* How far can we push the monster? */
- for (do_move = 1; do_move < 3; do_move++)
- {
- /* Get monster coords */
- /* And offset position */
- y1 = m_ptr->fy + (b * do_move);
- x1 = m_ptr->fx + (a * do_move);
-
- if (!in_bounds(y1, x1)) continue;
-
- /* Require "empty" floor space */
- if (!in_bounds(y1, x1) || !cave_empty_bold(y1, x1)) continue;
-
- /* Hack -- no teleport onto glyph of warding */
- if (cave[y1][x1].feat == FEAT_GLYPH) continue;
-
- /* amount moved */
- back = do_move;
- }
-
- /* Move the monster */
- if (back)
- {
- y1 = m_ptr->fy + (b * back);
- x1 = m_ptr->fx + (a * back);
- monster_swap(m_ptr->fy, m_ptr->fx, y1, x1);
-
- if (back == 2)
- {
- note = " is knocked back!";
- }
- if (back == 1)
- {
- note = " is knocked back and crushed!";
-
- /* was kept from being pushed all the way, do extra dam */
- dam = dam * 13 / 10;
- }
-
- /* Get new position */
- y = y1;
- x = x1;
-
- /* Hack -- get new grid */
- c_ptr = &cave[y][x];
- }
- else /* could not move the monster */
- {
- note = " is severely crushed!";
-
- /* Do extra damage (1/3)*/
- dam = dam * 15 / 10;
- }
-
- }
-
- /* Handle "teleport" */
- else if (do_dist)
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Message */
- note = " disappears!";
-
- /* Teleport */
- teleport_away(c_ptr->m_idx, do_dist);
-
- /* Hack -- get new location */
- y = m_ptr->fy;
- x = m_ptr->fx;
-
- /* Hack -- get new grid */
- c_ptr = &cave[y][x];
- }
-
- /* Sound and Impact breathers never stun */
- else if (do_stun &&
- !(r_ptr->flags4 & (RF4_BR_SOUN)) &&
- !(r_ptr->flags4 & (RF4_BR_WALL)) && hurt_monster(m_ptr))
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Get confused */
- if (m_ptr->stunned)
- {
- note = " is more dazed.";
- tmp = m_ptr->stunned + (do_stun / 2);
- }
- else
- {
- note = " is dazed.";
- tmp = do_stun;
- }
-
- /* Apply stun */
- m_ptr->stunned = (tmp < 200) ? tmp : 200;
- }
-
- /* Confusion and Chaos breathers (and sleepers) never confuse */
- else if (do_conf &&
- !(r_ptr->flags3 & (RF3_NO_CONF)) &&
- !(r_ptr->flags4 & (RF4_BR_CONF)) &&
- !(r_ptr->flags4 & (RF4_BR_CHAO)) && hurt_monster(m_ptr))
- {
- /* Obvious */
- if (seen) obvious = TRUE;
-
- /* Already partially confused */
- if (m_ptr->confused)
- {
- note = " looks more confused.";
- tmp = m_ptr->confused + (do_conf / 2);
- }
-
- /* Was not confused */
- else
- {
- note = " looks confused.";
- tmp = do_conf;
- }
-
- /* Apply confusion */
- m_ptr->confused = (tmp < 200) ? tmp : 200;
- }
-
-
- /* Fear */
- if (do_fear && hurt_monster(m_ptr))
- {
- /* Increase fear */
- tmp = m_ptr->monfear + do_fear;
-
- /* Set fear */
- m_ptr->monfear = (tmp < 200) ? tmp : 200;
- }
-
-
- /* If another monster did the damage, hurt the monster by hand */
- if (who > 0)
- {
- bool_ fear = FALSE;
-
- /* Dead monster */
- if (mon_take_hit_mon(who, c_ptr->m_idx, dam, &fear, note_dies))
- {}
-
- /* Damaged monster */
- else
- {
- /* Give detailed messages if visible or destroyed */
- if (note && seen) msg_format("%^s%s", m_name, note);
-
- /* Hack -- Pain message */
- else if (dam > 0) message_pain(c_ptr->m_idx, dam);
-
- /* Hack -- handle sleep */
- if (do_sleep) m_ptr->csleep = do_sleep;
- }
- }
- /* If the player did it, give him experience, check fear */
- else if (hurt_monster(m_ptr))
- {
- bool_ fear = FALSE;
-
- /* Hurt the monster, check for fear and death */
- if (mon_take_hit(c_ptr->m_idx, dam, &fear, note_dies))
- {
- /* Dead monster */
- }
-
- /* Damaged monster */
- else
- {
- /* Give detailed messages if visible or destroyed */
- if (note && seen) msg_format("%^s%s", m_name, note);
-
- /* Hack -- Pain message */
- else if (dam > 0) message_pain(c_ptr->m_idx, dam);
-
- /* Take note */
- if ((fear || do_fear) && (m_ptr->ml))
- {
- /* Sound */
- sound(SOUND_FLEE);
-
- /* Message */
- msg_format("%^s flees in terror!", m_name);
- }
-
- /* Hack -- handle sleep */
- if (do_sleep) m_ptr->csleep = do_sleep;
- }
- }
-
-
- /* XXX XXX XXX Verify this code */
-
- /* Update the monster */
- update_mon(c_ptr->m_idx, FALSE);
-
- /* Redraw the monster grid */
- lite_spot(y, x);
-
-
- /* Update monster recall window */
- if (monster_race_idx == m_ptr->r_idx)
- {
- /* Window stuff */
- p_ptr->window |= (PW_MONSTER);
- }
-
-
- /* Track it */
- project_m_n++;
- project_m_x = x;
- project_m_y = y;
-
-
- /* Return "Anything seen?" */
- return (obvious);
-}
-
-
-/* Is the spell unsafe for the player ? */
-bool_ unsafe = FALSE;
-
-
-/*
- * Helper function for "project()" below.
- *
- * Handle a beam/bolt/ball causing damage to the player.
- *
- * This routine takes a "source monster" (by index), a "distance", a default
- * "damage", and a "damage type". See "project_m()" above.
- *
- * If "rad" is non-zero, then the blast was centered elsewhere, and the damage
- * is reduced (see "project_m()" above). This can happen if a monster breathes
- * at the player and hits a wall instead.
- *
- * NOTE (Zangband): 'Bolt' attacks can be reflected back, so we need to know
- * if this is actually a ball or a bolt spell
- *
- *
- * We return "TRUE" if any "obvious" effects were observed. XXX XXX Actually,
- * we just assume that the effects were obvious, for historical reasons.
- */
-static bool_ project_p(int who, int r, int y, int x, int dam, int typ, int a_rad)
-{
- int k = 0, do_move = 0, a = 0, b = 0, x1 = 0, y1 = 0;
-
- /* Hack -- assume obvious */
- bool_ obvious = TRUE;
-
- /* Player blind-ness */
- bool_ blind = (p_ptr->blind ? TRUE : FALSE);
-
- /* Player needs a "description" (he is blind) */
- bool_ fuzzy = FALSE;
-
- /* Source monster */
- monster_type *m_ptr = NULL;
-
- /* Monster name (for attacks) */
- char m_name[80];
-
- /* Monster name (for damage) */
- char killer[80];
-
- /* Hack -- messages */
- cptr act = NULL;
-
-
- /* Player is not here */
- if ((x != p_ptr->px) || (y != p_ptr->py)) return (FALSE);
-
- /* Player cannot hurt himself */
- if ((!who) && (!unsafe)) return (FALSE);
-
- /* Bolt attack from a monster */
- if ((!a_rad) && get_skill(SKILL_DODGE) && (who > 0))
- {
- int chance = (p_ptr->dodge_chance - ((r_info[who].level * 5) / 6)) / 3;
-
- if ((chance > 0) && magik(chance))
- {
- msg_print("You dodge a magical attack!");
- return (TRUE);
- }
- }
-
- /* Effects done by the plane cannot bounce */
- if (p_ptr->reflect && !a_rad && !(randint(10) == 1) && ((who != -101) && (who != -100)))
- {
- int t_y, t_x;
- int max_attempts = 10;
-
- if (blind) msg_print("Something bounces!");
- else msg_print("The attack bounces!");
-
- /* Choose 'new' target */
- do
- {
- t_y = m_list[who].fy - 1 + randint(3);
- t_x = m_list[who].fx - 1 + randint(3);
- max_attempts--;
- }
- while (max_attempts && in_bounds2(t_y, t_x) &&
- !(player_has_los_bold(t_y, t_x)));
-
- if (max_attempts < 1)
- {
- t_y = m_list[who].fy;
- t_x = m_list[who].fx;
- }
-
- project(0, 0, t_y, t_x, dam, typ, (PROJECT_STOP | PROJECT_KILL));
-
- disturb(1, 0);
- return TRUE;
- }
-
- /* XXX XXX XXX */
- /* Limit maximum damage */
- if (dam > 1600) dam = 1600;
-
- /* Reduce damage by distance */
- dam = (dam + r) / (r + 1);
-
-
- /* If the player is blind, be more descriptive */
- if (blind) fuzzy = TRUE;
-
- /* If the player is hit by a trap, be more descritive */
- if (who == -2) fuzzy = TRUE;
-
- /* Did ``God'' do it? */
- if (who == -99)
- {
- if (p_ptr->pgod)
- {
- /* Find out the name of player's god. */
- sprintf(killer, "%s",
- deity_info[p_ptr->pgod].name);
- }
- else strcpy(killer, "Divine Wrath");
- }
-
- /* Did the dungeon do it? */
- if (who == -100)
- {
- sprintf(killer, "%s",
- d_name + d_info[dungeon_type].name);
- }
- if (who == -101)
- {
- sprintf(killer, "%s",
- f_name + f_info[cave[p_ptr->py][p_ptr->px].feat].name);
- }
-
- if (who >= -1)
- {
- /* Get the source monster */
- m_ptr = &m_list[who];
-
- /* Get the monster name */
- monster_desc(m_name, m_ptr, 0);
-
- /* Get the monster's real name */
- monster_desc(killer, m_ptr, 0x88);
- }
-
- if (who == -2)
- {
- sprintf(killer, "%s",
- t_name + t_info[cave[p_ptr->py][p_ptr->px].t_idx].name);
- }
-
- /* Analyze the damage */
- switch (typ)
- {
- case GF_DEATH_RAY:
- {
- if (fuzzy) msg_print("You are hit by pure death!");
- take_hit(32000, killer);
- break;
- }
-
- /* Standard damage -- hurts inventory too */
- case GF_ACID:
- {
- if (fuzzy) msg_print("You are hit by acid!");
- acid_dam(dam, killer);
- break;
- }
-
- /* Standard damage -- hurts inventory too */
- case GF_FIRE:
- {
- if (fuzzy) msg_print("You are hit by fire!");
- fire_dam(dam, killer);
- break;
- }
-
- /* Standard damage -- hurts inventory too */
- case GF_COLD:
- {
- if (fuzzy) msg_print("You are hit by cold!");
- cold_dam(dam, killer);
- break;
- }
-
- /* Standard damage -- hurts inventory too */
- case GF_ELEC:
- {
- if (fuzzy) msg_print("You are hit by lightning!");
- elec_dam(dam, killer);
- break;
- }
-
- /* Standard damage -- also poisons player */
- case GF_POIS:
- {
- if (fuzzy) msg_print("You are hit by poison!");
- if (p_ptr->resist_pois) dam = (dam + 2) / 3;
- if (p_ptr->oppose_pois) dam = (dam + 2) / 3;
-
- if ((!(p_ptr->oppose_pois || p_ptr->resist_pois)) &&
- randint(HURT_CHANCE) == 1)
- {
- do_dec_stat(A_CON, STAT_DEC_NORMAL);
- }
-
- take_hit(dam, killer);
-
- if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
- {
- set_poisoned(p_ptr->poisoned + rand_int(dam) + 10);
- }
- break;
- }
-
- /* Standard damage -- also poisons / mutates player */
- case GF_NUKE:
- {
- if (fuzzy) msg_print("You are hit by radiation!");
- if (p_ptr->resist_pois) dam = (2 * dam + 2) / 5;
- if (p_ptr->oppose_pois) dam = (2 * dam + 2) / 5;
- take_hit(dam, killer);
- if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
- {
- set_poisoned(p_ptr->poisoned + rand_int(dam) + 10);
-
- if (randint(5) == 1) /* 6 */
- {
- msg_print("You undergo a freakish metamorphosis!");
- if (randint(4) == 1) /* 4 */
- do_poly_self();
- else
- corrupt_player();
- }
-
- if (randint(6) == 1)
- {
- inven_damage(set_acid_destroy, 2);
- }
- }
- break;
- }
-
- /* Standard damage */
- case GF_MISSILE:
- {
- if (fuzzy) msg_print("You are hit by something!");
- take_hit(dam, killer);
- break;
- }
-
- /* Holy Orb -- Player only takes partial damage */
- case GF_HOLY_FIRE:
- {
- if (fuzzy) msg_print("You are hit by something!");
- take_hit(dam, killer);
- break;
- }
-
- case GF_HELL_FIRE:
- {
- if (fuzzy) msg_print("You are hit by something!");
- take_hit(dam, killer);
- break;
- }
-
- /* Arrow -- XXX no dodging */
- case GF_ARROW:
- {
- if (fuzzy) msg_print("You are hit by something sharp!");
- take_hit(dam, killer);
- break;
- }
-
- /* Plasma -- XXX No resist */
- case GF_PLASMA:
- {
- if (fuzzy) msg_print("You are hit by something *HOT*!");
- take_hit(dam, killer);
-
- if (!p_ptr->resist_sound)
- {
- int k = (randint((dam > 40) ? 35 : (dam * 3 / 4 + 5)));
- (void)set_stun(p_ptr->stun + k);
- }
-
- if (!(p_ptr->resist_fire ||
- p_ptr->oppose_fire ||
- p_ptr->immune_fire))
- {
- inven_damage(set_acid_destroy, 3);
- }
-
- break;
- }
-
- /* Nether -- drain experience */
- case GF_NETHER:
- {
- if (fuzzy) msg_print("You are hit by nether forces!");
- {
- if (p_ptr->immune_neth)
- {
- dam = 0;
- }
- else if (p_ptr->resist_neth)
- {
- dam *= 6;
- dam /= (randint(6) + 6);
- }
- else
- {
- if (p_ptr->hold_life && (rand_int(100) < 75))
- {
- msg_print("You keep hold of your life force!");
- }
- else if (p_ptr->hold_life)
- {
- msg_print("You feel your life slipping away!");
- lose_exp(200 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
- }
- else
- {
- msg_print("You feel your life draining away!");
- lose_exp(200 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
- }
- }
-
- take_hit(dam, killer);
- }
-
- break;
- }
-
- /* Water -- stun/confuse */
- case GF_WAVE:
- case GF_WATER:
- {
- if (fuzzy) msg_print("You are hit by something wet!");
- if (!p_ptr->resist_sound)
- {
- set_stun(p_ptr->stun + randint(40));
- }
- if (!p_ptr->resist_conf)
- {
- set_confused(p_ptr->confused + randint(5) + 5);
- }
-
- if (randint(5) == 1)
- {
- inven_damage(set_cold_destroy, 3);
- }
-
- take_hit(dam, killer);
- break;
- }
-
- /* Chaos -- many effects */
- case GF_CHAOS:
- {
- if (fuzzy) msg_print("You are hit by a wave of anarchy!");
- if (p_ptr->resist_chaos)
- {
- dam *= 6;
- dam /= (randint(6) + 6);
- }
- if (!p_ptr->resist_conf)
- {
- (void)set_confused(p_ptr->confused + rand_int(20) + 10);
- }
- if (!p_ptr->resist_chaos)
- {
- (void)set_image(p_ptr->image + randint(10));
- }
- if (!p_ptr->resist_neth && !p_ptr->resist_chaos)
- {
- if (p_ptr->hold_life && (rand_int(100) < 75))
- {
- msg_print("You keep hold of your life force!");
- }
- else if (p_ptr->hold_life)
- {
- msg_print("You feel your life slipping away!");
- lose_exp(500 + (p_ptr->exp / 1000) * MON_DRAIN_LIFE);
- }
- else
- {
- msg_print("You feel your life draining away!");
- lose_exp(5000 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
- }
- }
- if ((!p_ptr->resist_chaos) || (randint(9) == 1))
- {
- inven_damage(set_elec_destroy, 2);
- inven_damage(set_fire_destroy, 2);
- }
- take_hit(dam, killer);
- break;
- }
-
- /* Shards -- mostly cutting */
- case GF_SHARDS:
- {
- if (fuzzy) msg_print("You are hit by something sharp!");
- if (p_ptr->resist_shard)
- {
- dam *= 6;
- dam /= (randint(6) + 6);
- }
- else
- {
- (void)set_cut(p_ptr->cut + dam);
- }
-
- if ((!p_ptr->resist_shard) || (randint(13) == 1))
- {
- inven_damage(set_cold_destroy, 2);
- }
-
- take_hit(dam, killer);
- break;
- }
-
- /* Sound -- mostly stunning */
- case GF_SOUND:
- {
- if (fuzzy) msg_print("You are hit by a loud noise!");
- if (p_ptr->resist_sound)
- {
- dam *= 5;
- dam /= (randint(6) + 6);
- }
- else
- {
- int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
- (void)set_stun(p_ptr->stun + k);
- }
-
- if ((!p_ptr->resist_sound) || (randint(13) == 1))
- {
- inven_damage(set_cold_destroy, 2);
- }
-
- take_hit(dam, killer);
- break;
- }
-
- /* Pure confusion */
- case GF_CONFUSION:
- {
- if (fuzzy) msg_print("You are hit by something puzzling!");
- if (p_ptr->resist_conf)
- {
- dam *= 5;
- dam /= (randint(6) + 6);
- }
- if (!p_ptr->resist_conf)
- {
- (void)set_confused(p_ptr->confused + randint(20) + 10);
- }
- take_hit(dam, killer);
- break;
- }
-
- /* Disenchantment -- see above */
- case GF_DISENCHANT:
- {
- if (fuzzy) msg_print("You are hit by something static!");
- if (p_ptr->resist_disen)
- {
- dam *= 6;
- dam /= (randint(6) + 6);
- }
- else
- {
- (void)apply_disenchant(0);
- }
- take_hit(dam, killer);
- break;
- }
-
- /* Nexus -- see above */
- case GF_NEXUS:
- {
- if (fuzzy) msg_print("You are hit by something strange!");
- if (p_ptr->resist_nexus)
- {
- dam *= 6;
- dam /= (randint(6) + 6);
- }
- else
- {
- apply_nexus(m_ptr);
- }
- take_hit(dam, killer);
- break;
- }
-
- /* Force -- mostly stun */
- case GF_FORCE:
- {
- if (fuzzy) msg_print("You are hit by kinetic force!");
- if (!p_ptr->resist_sound)
- {
- (void)set_stun(p_ptr->stun + randint(20));
- /*
- * If fired by player, try pushing monster.
- * First get vector from player to monster.
- * x10 so we can use pseudo-fixed point maths.
- *
- * Really should use get_angle_to_grid (util.c)
- */
- if (who > 0)
- {
- a = 0;
- b = 0;
-
- /* Get vector from firer to target */
- x1 = (p_ptr->px - m_ptr->fx) * 10;
- y1 = (p_ptr->py - m_ptr->fy) * 10;
-
- /* Make sure no zero divides */
- if (x1 == 0) x1 = 1;
- if (y1 == 0) y1 = 1;
-
- /* Select direction player is being pushed */
-
- /* Roughly horizontally */
- if ((2*y1) / x1 == 0)
- {
- if (x1 > 0)
- {
- a = 1, b = 0;
- }
- else
- {
- a = -1, b = 0;
- }
- }
-
- /* Roughly vertically */
- else if ((2*x1) / y1 == 0)
- {
- if (y1 > 0)
- {
- a = 0, b = 1;
- }
- else
- {
- a = 0, b = -1;
- }
- }
-
- /* Take diagonals */
- else
- {
- if (y1 > 0)
- {
- b = 1;
- }
- else
- {
- b = -1;
- }
- if (x1 > 0)
- {
- a = 1;
- }
- else
- {
- a = -1;
- }
- }
-
- /* Move monster 2 offsets back */
- do_move = 2;
-
- /* Old monster coords in x,y */
- y1 = p_ptr->py;
- x1 = p_ptr->px;
- }
- }
- else
- take_hit(dam, killer);
- break;
- }
-
-
- /* Rocket -- stun, cut */
- case GF_ROCKET:
- {
- if (fuzzy) msg_print("There is an explosion!");
- if (!p_ptr->resist_sound)
- {
- (void)set_stun(p_ptr->stun + randint(20));
- }
- if (p_ptr->resist_shard)
- {
- dam /= 2;
- }
- else
- {
- (void)set_cut(p_ptr-> cut + ( dam / 2) );
- }
-
- if ((!p_ptr->resist_shard) || (randint(12) == 1))
- {
- inven_damage(set_cold_destroy, 3);
- }
-
- take_hit(dam, killer);
- break;
- }
-
- /* Inertia -- slowness */
- case GF_INERTIA:
- {
- if (fuzzy) msg_print("You are hit by something slow!");
- (void)set_slow(p_ptr->slow + rand_int(4) + 4);
- take_hit(dam, killer);
- break;
- }
-
- /* Lite -- blinding */
- case GF_LITE:
- {
- if (fuzzy) msg_print("You are hit by something!");
- if (p_ptr->resist_lite)
- {
- dam *= 4;
- dam /= (randint(6) + 6);
- }
- else if (!blind && !p_ptr->resist_blind)
- {
- (void)set_blind(p_ptr->blind + randint(5) + 2);
- }
- if (p_ptr->sensible_lite)
- {
- msg_print("The light scorches your flesh!");
- dam *= 3;
- }
- take_hit(dam, killer);
-
- if (p_ptr->tim_wraith)
- {
- p_ptr->tim_wraith = 0;
- msg_print("The light forces you out of your incorporeal shadow form.");
-
- p_ptr->redraw |= PR_MAP;
- /* Update monsters */
- p_ptr->update |= (PU_MONSTERS);
- /* Window stuff */
- p_ptr->window |= (PW_OVERHEAD);
- }
-
- break;
- }
-
- /* Dark -- blinding */
- case GF_DARK:
- {
- if (fuzzy) msg_print("You are hit by something!");
- if (p_ptr->resist_dark)
- {
- dam *= 4;
- dam /= (randint(6) + 6);
- }
- else if (!blind && !p_ptr->resist_blind)
- {
- (void)set_blind(p_ptr->blind + randint(5) + 2);
- }
- if (p_ptr->wraith_form) hp_player(dam);
- else take_hit(dam, killer);
- break;
- }
-
- /* Time -- bolt fewer effects XXX */
- case GF_TIME:
- {
- if (fuzzy) msg_print("You are hit by a blast from the past!");
-
- if (p_ptr->resist_continuum)
- {
- dam *= 4;
- dam /= (randint(6) + 6);
- msg_print("You feel as if time is passing you by.");
- }
- else
- {
- switch (randint(10))
- {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- {
- msg_print("You feel life has clocked back.");
- lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
- break;
- }
-
- case 6:
- case 7:
- case 8:
- case 9:
- {
- switch (randint(6))
- {
- case 1:
- k = A_STR;
- act = "strong";
- break;
- case 2:
- k = A_INT;
- act = "bright";
- break;
- case 3:
- k = A_WIS;
- act = "wise";
- break;
- case 4:
- k = A_DEX;
- act = "agile";
- break;
- case 5:
- k = A_CON;
- act = "hardy";
- break;
- case 6:
- k = A_CHR;
- act = "beautiful";
- break;
- }
-
- msg_format("You're not as %s as you used to be...", act);
-
- p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
- if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
- p_ptr->update |= (PU_BONUS);
- break;
- }
-
- case 10:
- {
- msg_print("You're not as powerful as you used to be...");
-
- for (k = 0; k < 6; k++)
- {
- p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
- if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
- }
- p_ptr->update |= (PU_BONUS);
- break;
- }
- }
- }
- take_hit(dam, killer);
- break;
- }
-
- /* Gravity -- stun plus slowness plus teleport */
- case GF_GRAVITY:
- {
- if (dungeon_flags2 & DF2_NO_TELEPORT) break; /* No teleport on special levels */
- if (fuzzy) msg_print("You are hit by something heavy!");
- msg_print("Gravity warps around you.");
- if (!unsafe)
- {
- teleport_player(5);
- if (!p_ptr->ffall)
- (void)set_slow(p_ptr->slow + rand_int(4) + 4);
- if (!(p_ptr->resist_sound || p_ptr->ffall))
- {
- int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
- (void)set_stun(p_ptr->stun + k);
- }
- if (p_ptr->ffall)
- {
- dam = (dam * 2) / 3;
- }
-
- if ((!p_ptr->ffall) || (randint(13) == 1))
- {
- inven_damage(set_cold_destroy, 2);
- }
-
- take_hit(dam, killer);
- }
- else
- teleport_player(dam);
- break;
- }
-
- /* Standard damage */
- case GF_DISINTEGRATE:
- {
- if (fuzzy) msg_print("You are hit by pure energy!");
- take_hit(dam, killer);
- break;
- }
-
- case GF_OLD_HEAL:
- {
- if (fuzzy) msg_print("You are hit by something invigorating!");
- (void)hp_player(dam);
- dam = 0;
- break;
- }
-
- case GF_OLD_SPEED:
- {
- if (fuzzy) msg_print("You are hit by something!");
- (void)set_fast(p_ptr->fast + randint(5), 10);
- dam = 0;
- break;
- }
-
- case GF_OLD_SLOW:
- {
- if (fuzzy) msg_print("You are hit by something slow!");
- (void)set_slow(p_ptr->slow + rand_int(4) + 4);
- break;
- }
-
- case GF_OLD_SLEEP:
- {
- if (p_ptr->free_act) break;
- if (fuzzy) msg_print("You fall asleep!");
- set_paralyzed(p_ptr->paralyzed + dam);
- dam = 0;
- break;
- }
-
- /* Pure damage */
- case GF_MANA:
- {
- if (fuzzy) msg_print("You are hit by an aura of magic!");
- take_hit(dam, killer);
- break;
- }
-
- /* Pure damage */
- case GF_METEOR:
- {
- if (fuzzy) msg_print("Something falls from the sky on you!");
- take_hit(dam, killer);
- if ((!p_ptr->resist_shard) || (randint(13) == 1))
- {
- if (!p_ptr->immune_fire) inven_damage(set_fire_destroy, 2);
- inven_damage(set_cold_destroy, 2);
- }
-
- break;
- }
-
- /* Ice -- cold plus stun plus cuts */
- case GF_ICE:
- {
- if (fuzzy) msg_print("You are hit by something sharp and cold!");
- cold_dam(dam, killer);
- if (!p_ptr->resist_shard)
- {
- (void)set_cut(p_ptr->cut + damroll(5, 8));
- }
- if (!p_ptr->resist_sound)
- {
- (void)set_stun(p_ptr->stun + randint(15));
- }
-
- if ((!(p_ptr->resist_cold || p_ptr->oppose_cold)) || (randint(12) == 1))
- {
- if (!(p_ptr->immune_cold)) inven_damage(set_cold_destroy, 3);
- }
-
- break;
- }
-
- /* Knowledge */
- case GF_IDENTIFY:
- {
- if (fuzzy) msg_print("You are hit by pure knowledge!");
- self_knowledge(NULL);
- break;
- }
-
- /* Psi -- ESP */
- case GF_PSI:
- {
- if (fuzzy) msg_print("You are hit by pure psionic energy!");
- set_tim_esp(p_ptr->tim_esp + dam);
- break;
- }
-
- /* Statis -- paralyse */
- case GF_STASIS:
- {
- if (fuzzy) msg_print("You are hit by something paralyzing!");
- set_paralyzed(p_ptr->paralyzed + dam);
- break;
- }
-
- /* Raise Death -- restore life */
- case GF_RAISE:
- {
- if (fuzzy) msg_print("You are hit by pure anti-death energy!");
- restore_level();
- break;
- }
-
- /* Make Glyph -- Shield */
- case GF_MAKE_GLYPH:
- {
- if (fuzzy) msg_print("You are hit by pure protection!");
- set_shield(p_ptr->shield + dam, 50, 0, 0, 0);
- break;
- }
-
- /* Default */
- default:
- {
- /* Hooks! */
- if (process_hooks_ret(HOOK_GF_EXEC, "dd", "(s,d,d,d,d,d,d)", "player", who, typ, dam, r, y, x))
- {
- obvious = process_hooks_return[0].num;
- dam = process_hooks_return[1].num;
- }
- else
- {
- /* No damage */
- dam = 0;
- }
- break;
- }
- }
-
-
- /* Handle moving the player.
- *
- * Note: This is a effect of force
- */
- if (do_move)
- {
- int back = 0;
-
- back = 0; /* Default of no movement */
-
- /* How far can we push the monster? */
- for (do_move = 1; do_move < 3; do_move++)
- {
- /* Get monster coords */
- /* And offset position */
- y1 = p_ptr->py + (b * do_move);
- x1 = p_ptr->px + (a * do_move);
-
- if (!in_bounds(y1, x1)) continue;
-
- /* Require "empty" floor space */
- if (!in_bounds(y1, x1) || !cave_empty_bold(y1, x1)) continue;
-
- /* amount moved */
- back = do_move;
- }
-
- /* Move the monster */
- if (back)
- {
- y1 = p_ptr->py + (b * back);
- x1 = p_ptr->px + (a * back);
- swap_position(y1, x1);
-
- if (back == 2)
- {
- msg_print("You are knocked back!");
- }
- if (back == 1)
- {
- msg_print("You are knocked back and crushed!");
-
- /* was kept from being pushed all the way, do extra dam */
- dam = dam * 13 / 10;
- }
-
- /* Get new position */
- y = y1;
- x = x1;
- }
- else /* could not move the monster */
- {
- msg_print("You are severely crushed!");
-
- /* Do extra damage (1/3)*/
- dam = dam * 15 / 10;
- }
-
- take_hit(dam, killer);
-
- }
-
-
- /* Disturb */
- disturb(1, 0);
-
-
- /* Return "Anything seen?" */
- return (obvious);
-}
-
-
-
-/*
- * Generic "beam"/"bolt"/"ball" projection routine.
- *
- * Input:
- * who: Index of "source" monster (negative for "player")
- * jk -- -2 for traps, only used with project_jump
- * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
- * y,x: Target location (or location to travel "towards")
- * dam: Base damage roll to apply to affected monsters (or player)
- * typ: Type of damage to apply to monsters (and objects)
- * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
- *
- * Return:
- * TRUE if any "effects" of the projection were observed, else FALSE
- *
- * Allows a monster (or player) to project a beam/bolt/ball of a given kind
- * towards a given location (optionally passing over the heads of interposing
- * monsters), and have it do a given amount of damage to the monsters (and
- * optionally objects) within the given radius of the final location.
- *
- * A "bolt" travels from source to target and affects only the target grid.
- * A "beam" travels from source to target, affecting all grids passed through.
- * A "ball" travels from source to the target, exploding at the target, and
- * affecting everything within the given radius of the target location.
- *
- * Traditionally, a "bolt" does not affect anything on the ground, and does
- * not pass over the heads of interposing monsters, much like a traditional
- * missile, and will "stop" abruptly at the "target" even if no monster is
- * positioned there, while a "ball", on the other hand, passes over the heads
- * of monsters between the source and target, and affects everything except
- * the source monster which lies within the final radius, while a "beam"
- * affects every monster between the source and target, except for the casting
- * monster (or player), and rarely affects things on the ground.
- *
- * Two special flags allow us to use this function in special ways, the
- * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
- * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
- * actually projecting from the source monster (or player).
- *
- * The player will only get "experience" for monsters killed by himself
- * Unique monsters can only be destroyed by attacks from the player
- *
- * Only 256 grids can be affected per projection, limiting the effective
- * "radius" of standard ball attacks to nine units (diameter nineteen).
- *
- * One can project in a given "direction" by combining PROJECT_THRU with small
- * offsets to the initial location (see "line_spell()"), or by calculating
- * "virtual targets" far away from the player.
- *
- * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
- * continuing until it actually hits something (useful for "stone to mud").
- *
- * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
- *
- * Balls must explode BEFORE hitting walls, or they would affect monsters
- * on both sides of a wall. Some bug reports indicate that this is still
- * happening in 2.7.8 for Windows, though it appears to be impossible.
- *
- * We "pre-calculate" the blast area only in part for efficiency.
- * More importantly, this lets us do "explosions" from the "inside" out.
- * This results in a more logical distribution of "blast" treasure.
- * It also produces a better (in my opinion) animation of the explosion.
- * It could be (but is not) used to have the treasure dropped by monsters
- * in the middle of the explosion fall "outwards", and then be damaged by
- * the blast as it spreads outwards towards the treasure drop location.
- *
- * Walls and doors are included in the blast area, so that they can be
- * "burned" or "melted" in later versions.
- *
- * This algorithm is intended to maximize simplicity, not necessarily
- * efficiency, since this function is not a bottleneck in the code.
- *
- * We apply the blast effect from ground zero outwards, in several passes,
- * first affecting features, then objects, then monsters, then the player.
- * This allows walls to be removed before checking the object or monster
- * in the wall, and protects objects which are dropped by monsters killed
- * in the blast, and allows the player to see all affects before he is
- * killed or teleported away. The semantics of this method are open to
- * various interpretations, but they seem to work well in practice.
- *
- * We process the blast area from ground-zero outwards to allow for better
- * distribution of treasure dropped by monsters, and because it provides a
- * pleasing visual effect at low cost.
- *
- * Note that the damage done by "ball" explosions decreases with distance.
- * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
- *
- * Notice the "napalm" effect of "beam" weapons. First they "project" to
- * the target, and then the damage "flows" along this beam of destruction.
- * The damage at every grid is the same as at the "center" of a "ball"
- * explosion, since the "beam" grids are treated as if they ARE at the
- * center of a "ball" explosion.
- *
- * Currently, specifying "beam" plus "ball" means that locations which are
- * covered by the initial "beam", and also covered by the final "ball", except
- * for the final grid (the epicenter of the ball), will be "hit twice", once
- * by the initial beam, and once by the exploding ball. For the grid right
- * next to the epicenter, this results in 150% damage being done. The center
- * does not have this problem, for the same reason the final grid in a "beam"
- * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
- * grids which are covered by the "ball" will NOT work, as then they will
- * receive LESS damage than they should. Do not combine "beam" with "ball".
- *
- * The array "gy[],gx[]" with current size "grids" is used to hold the
- * collected locations of all grids in the "blast area" plus "beam path".
- *
- * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
- * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
- * first blast grid (see above) with radius "N" from the blast center. Note
- * that only the first gm[1] grids in the blast area thus take full damage.
- * Also, note that gm[rad+1] is always equal to "grids", which is the total
- * number of blast grids.
- *
- * Note that once the projection is complete, (y2,x2) holds the final location
- * of bolts/beams, and the "epicenter" of balls.
- *
- * Note also that "rad" specifies the "inclusive" radius of projection blast,
- * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
- * implementation of the "distance" function. Also, a bolt can be properly
- * viewed as a "ball" with a "rad" of "zero".
- *
- * Note that if no "target" is reached before the beam/bolt/ball travels the
- * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
- * may be relevant even for bolts, since they have a "1x1" mini-blast.
- *
- * Note that for consistency, we "pretend" that the bolt actually takes "time"
- * to move from point A to point B, even if the player cannot see part of the
- * projection path. Note that in general, the player will *always* see part
- * of the path, since it either starts at the player or ends on the player.
- *
- * Hack -- we assume that every "projection" is "self-illuminating".
- *
- * Hack -- when only a single monster is affected, we automatically track
- * (and recall) that monster, unless "PROJECT_JUMP" is used.
- *
- * Note that all projections now "explode" at their final destination, even
- * if they were being projected at a more distant destination. This means
- * that "ball" spells will *always* explode.
- *
- * Note that we must call "handle_stuff()" after affecting terrain features
- * in the blast radius, in case the "illumination" of the grid was changed,
- * and "update_view()" and "update_monsters()" need to be called.
- */
-bool_ project(int who, int rad, int y, int x, int dam, int typ, int flg)
-{
- int i, t, dist;
-
- int y1, x1;
- int y2, x2;
-
- int dist_hack = 0;
-
- int y_saver, x_saver; /* For reflecting monsters */
-
- int msec = delay_factor * delay_factor * delay_factor;
-
- /* Assume the player sees nothing */
- bool_ notice = FALSE;
-
- /* Assume the player has seen nothing */
- bool_ visual = FALSE;
-
- /* Assume the player has seen no blast grids */
- bool_ drawn = FALSE;
-
- /* Is the player blind? */
- bool_ blind = (p_ptr->blind ? TRUE : FALSE);
-
- /* Number of grids in the "path" */
- int path_n = 0;
-
- /* Actual grids in the "path" */
- u16b path_g[1024];
-
- /* Number of grids in the "blast area" (including the "beam" path) */
- int grids = 0;
-
- int effect = 0;
-
- /* Coordinates of the affected grids */
- byte gx[1024], gy[1024];
-
- /* Encoded "radius" info (see above) */
- byte gm[64];
-
-
- /* Hack -- Jump to target */
- if (flg & (PROJECT_JUMP))
- {
- x1 = x;
- y1 = y;
-
- /* Clear the flag */
- flg &= ~(PROJECT_JUMP);
- }
-
- /* Start at player */
- else if ((who <= 0) && ((who != -101) && (who != -100)))
- {
- x1 = p_ptr->px;
- y1 = p_ptr->py;
- }
-
- /* Start at monster */
- else if (who > 0)
- {
- x1 = m_list[who].fx;
- y1 = m_list[who].fy;
- }
-
- /* Oops */
- else
- {
- x1 = x;
- y1 = y;
- }
-
- y_saver = y1;
- x_saver = x1;
-
- /* Default "destination" */
- y2 = y;
- x2 = x;
-
-
- /* Hack -- verify stuff */
- if (flg & (PROJECT_THRU))
- {
- if ((x1 == x2) && (y1 == y2))
- {
- flg &= ~(PROJECT_THRU);
- }
- }
-
-
- /* Hack -- Assume there will be no blast (max radius 16) */
- for (dist = 0; dist < 64; dist++) gm[dist] = 0;
-
-
- /* Initial grid */
- y = y1;
- x = x1;
- dist = 0;
-
- /* Collect beam grids */
- if (flg & (PROJECT_BEAM))
- {
- gy[grids] = y;
- gx[grids] = x;
- grids++;
- }
-
-
- /* Calculate the projection path */
- if ((who == -101) || (who == -100))
- path_n = 0;
- else
- path_n = project_path(path_g, MAX_RANGE, y1, x1, y2, x2, flg);
-
-
- /* Hack -- Handle stuff */
- handle_stuff();
-
- /* Project along the path */
- for (i = 0; i < path_n; ++i)
- {
- int oy = y;
- int ox = x;
-
- int ny = GRID_Y(path_g[i]);
- int nx = GRID_X(path_g[i]);
-
- /* Hack -- Balls explode before reaching walls */
- if (!cave_floor_bold(ny, nx) && (rad > 0)) break;
-
- /* Advance */
- y = ny;
- x = nx;
-
- /* Collect beam grids */
- if (flg & (PROJECT_BEAM))
- {
- gy[grids] = y;
- gx[grids] = x;
- grids++;
- }
-
- /* Only do visuals if requested */
- if (!blind && !(flg & (PROJECT_HIDE)))
- {
- /* Only do visuals if the player can "see" the bolt */
- if (panel_contains(y, x) && player_has_los_bold(y, x))
- {
- u16b p;
-
- byte a;
- char c;
-
- /* Obtain the bolt pict */
- p = bolt_pict(oy, ox, y, x, typ);
-
- /* Extract attr/char */
- a = PICT_A(p);
- c = PICT_C(p);
-
- /* Visual effects */
- print_rel(c, a, y, x);
- move_cursor_relative(y, x);
- if (fresh_before) Term_fresh();
- Term_xtra(TERM_XTRA_DELAY, msec);
- lite_spot(y, x);
- if (fresh_before) Term_fresh();
-
- /* Display "beam" grids */
- if (flg & (PROJECT_BEAM))
- {
- /* Obtain the explosion pict */
- p = bolt_pict(y, x, y, x, typ);
-
- /* Extract attr/char */
- a = PICT_A(p);
- c = PICT_C(p);
-
- /* Visual effects */
- print_rel(c, a, y, x);
- }
-
- /* Hack -- Activate delay */
- visual = TRUE;
- }
-
- /* Hack -- delay anyway for consistency */
- else if (visual)
- {
- /* Delay for consistency */
- Term_xtra(TERM_XTRA_DELAY, msec);
- }
- }
- }
-
-
- /* Save the "blast epicenter" */
- y2 = y;
- x2 = x;
-
- /* Start the "explosion" */
- gm[0] = 0;
-
- /* Hack -- make sure beams get to "explode" */
- gm[1] = grids;
-
- dist_hack = dist;
-
- /* Explode */
- if (TRUE)
- {
- /* Hack -- remove final beam grid */
- if (flg & (PROJECT_BEAM))
- {
- grids--;
- }
-
- /* Determine the blast area, work from the inside out */
- for (dist = 0; dist <= rad; dist++)
- {
- /* Scan the maximal blast area of radius "dist" */
- for (y = y2 - dist; y <= y2 + dist; y++)
- {
- for (x = x2 - dist; x <= x2 + dist; x++)
- {
- /* Ignore "illegal" locations */
- if (!in_bounds(y, x)) continue;
-
- /* Enforce a "circular" explosion */
- if (distance(y2, x2, y, x) != dist) continue;
-
- /* Ball explosions are stopped by walls */
- if (typ == GF_DISINTEGRATE)
- {
- if (cave_valid_bold(y, x) &&
- (cave[y][x].feat < FEAT_PATTERN_START
- || cave[y][x].feat > FEAT_PATTERN_XTRA2))
- cave_set_feat(y, x, FEAT_FLOOR);
-
- /* Update some things -- similar to GF_KILL_WALL */
- p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MONSTERS | PU_MON_LITE);
- }
- else
- {
- if (!los(y2, x2, y, x)) continue;
- }
-
- /* Save this grid */
- gy[grids] = y;
- gx[grids] = x;
- grids++;
- }
- }
-
- /* Encode some more "radius" info */
- gm[dist + 1] = grids;
- }
- }
-
-
- /* Speed -- ignore "non-explosions" */
- if (!grids) return (FALSE);
-
-
- /* Display the "blast area" if requested */
- if (!blind && !(flg & (PROJECT_HIDE)))
- {
- /* Then do the "blast", from inside out */
- for (t = 0; t <= rad; t++)
- {
- /* Dump everything with this radius */
- for (i = gm[t]; i < gm[t + 1]; i++)
- {
- /* Extract the location */
- y = gy[i];
- x = gx[i];
-
- /* Only do visuals if the player can "see" the blast */
- if (panel_contains(y, x) && player_has_los_bold(y, x))
- {
- u16b p;
-
- byte a;
- char c;
-
- drawn = TRUE;
-
- /* Obtain the explosion pict */
- p = bolt_pict(y, x, y, x, typ);
-
- /* Extract attr/char */
- a = PICT_A(p);
- c = PICT_C(p);
-
- /* Visual effects -- Display */
- print_rel(c, a, y, x);
- }
- }
-
- /* Hack -- center the cursor */
- move_cursor_relative(y2, x2);
-
- /* Flush each "radius" seperately */
- if (fresh_before) Term_fresh();
-
- /* Delay (efficiently) */
- if (visual || drawn)
- {
- Term_xtra(TERM_XTRA_DELAY, msec);
- }
- }
-
- /* Flush the erasing */
- if (drawn)
- {
- /* Erase the explosion drawn above */
- for (i = 0; i < grids; i++)
- {
- /* Extract the location */
- y = gy[i];
- x = gx[i];
-
- /* Hack -- Erase if needed */
- if (panel_contains(y, x) && player_has_los_bold(y, x))
- {
- lite_spot(y, x);
- }
- }
-
- /* Hack -- center the cursor */
- move_cursor_relative(y2, x2);
-
- /* Flush the explosion */
- if (fresh_before) Term_fresh();
- }
- }
-
-
- /* Check features */
- if (flg & (PROJECT_GRID))
- {
- /* Start with "dist" of zero */
- dist = 0;
-
- /* Effect ? */
- if (flg & PROJECT_STAY)
- {
- effect = new_effect(typ, dam, project_time, p_ptr->py, p_ptr->px, rad, project_time_effect);
- project_time = 0;
- project_time_effect = 0;
- }
-
- /* Scan for features */
- for (i = 0; i < grids; i++)
- {
- /* Hack -- Notice new "dist" values */
- if (gm[dist + 1] == i) dist++;
-
- /* Get the grid location */
- y = gy[i];
- x = gx[i];
-
- /* Affect the feature in that grid */
- if (project_f(who, dist, y, x, dam, typ)) notice = TRUE;
-
- /* Effect ? */
- if (flg & PROJECT_STAY)
- {
- cave[y][x].effect = effect;
- lite_spot(y, x);
- }
- }
- }
-
-
- /* Update stuff if needed */
- if (p_ptr->update) update_stuff();
-
-
- /* Check objects */
- if (flg & (PROJECT_ITEM))
- {
- /* Start with "dist" of zero */
- dist = 0;
-
- /* Scan for objects */
- for (i = 0; i < grids; i++)
- {
- /* Hack -- Notice new "dist" values */
- if (gm[dist + 1] == i) dist++;
-
- /* Get the grid location */
- y = gy[i];
- x = gx[i];
-
- /* Affect the object in the grid */
- if (project_o(who, dist, y, x, dam, typ)) notice = TRUE;
- }
- }
-
-
- /* Check monsters */
- if (flg & (PROJECT_KILL))
- {
- /* Mega-Hack */
- project_m_n = 0;
- project_m_x = 0;
- project_m_y = 0;
-
- /* Start with "dist" of zero */
- dist = 0;
-
- /* Scan for monsters */
- for (i = 0; i < grids; i++)
- {
- /* Hack -- Notice new "dist" values */
- if (gm[dist + 1] == i) dist++;
-
- /* Get the grid location */
- y = gy[i];
- x = gx[i];
-
- if (grids > 1)
- {
- /* Affect the monster in the grid */
- if (project_m(who, dist, y, x, dam, typ)) notice = TRUE;
- }
- else
- {
- monster_race *ref_ptr = race_inf(&m_list[cave[y][x].m_idx]);
-
- if ((ref_ptr->flags2 & (RF2_REFLECTING)) && (randint(10) != 1)
- && (dist_hack > 1))
- {
- int t_y, t_x;
- int max_attempts = 10;
-
- /* Choose 'new' target */
- do
- {
- t_y = y_saver - 1 + randint(3);
- t_x = x_saver - 1 + randint(3);
- max_attempts--;
- }
-
- while (max_attempts && in_bounds2(t_y, t_x) &&
- !(los(y, x, t_y, t_x)));
-
- if (max_attempts < 1)
- {
- t_y = y_saver;
- t_x = x_saver;
- }
-
- if (m_list[cave[y][x].m_idx].ml)
- {
- msg_print("The attack bounces!");
- ref_ptr->r_flags2 |= RF2_REFLECTING;
- }
-
- project(cave[y][x].m_idx, 0, t_y, t_x, dam, typ, flg);
- }
- else
- {
- if (project_m(who, dist, y, x, dam, typ)) notice = TRUE;
- }
- }
- }
-
- /* Player affected one monster (without "jumping") */
- if ((who < 0) && (project_m_n == 1) && !(flg & (PROJECT_JUMP)))
- {
- /* Location */
- x = project_m_x;
- y = project_m_y;
-
- /* Track if possible */
- if (cave[y][x].m_idx > 0)
- {
- monster_type *m_ptr = &m_list[cave[y][x].m_idx];
-
- /* Hack -- auto-recall */
- if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego);
-
- /* Hack - auto-track */
- if (m_ptr->ml) health_track(cave[y][x].m_idx);
- }
- }
- }
-
-
- /* Check player */
- if (flg & (PROJECT_KILL))
- {
- /* Start with "dist" of zero */
- dist = 0;
-
- /* Scan for player */
- for (i = 0; i < grids; i++)
- {
- /* Hack -- Notice new "dist" values */
- if (gm[dist + 1] == i) dist++;
-
- /* Get the grid location */
- y = gy[i];
- x = gx[i];
-
- /* Affect the player */
- if (project_p(who, dist, y, x, dam, typ, rad)) notice = TRUE;
- }
- }
-
- /* Return "something was noticed" */
- return (notice);
-}
-
-
-
-/*
- * Potions "smash open" and cause an area effect when
- * (1) they are shattered while in the player's inventory,
- * due to cold (etc) attacks;
- * (2) they are thrown at a monster, or obstacle;
- * (3) they are shattered by a "cold ball" or other such spell
- * while lying on the floor.
- *
- * Arguments:
- * who --- who caused the potion to shatter (0=player)
- * potions that smash on the floor are assumed to
- * be caused by no-one (who = 1), as are those that
- * shatter inside the player inventory.
- * (Not anymore -- I changed this; TY)
- * y, x --- coordinates of the potion (or player if
- * the potion was in her inventory);
- * o_ptr --- pointer to the potion object.
- */
-bool_ potion_smash_effect(int who, int y, int x, int o_sval)
-{
- int radius = 2;
- int dt = 0;
- int dam = 0;
- bool_ ident = FALSE;
- bool_ angry = FALSE;
-
- switch (o_sval)
- {
- case SV_POTION_SALT_WATER:
- case SV_POTION_SLIME_MOLD:
- case SV_POTION_LOSE_MEMORIES:
- case SV_POTION_DEC_STR:
- case SV_POTION_DEC_INT:
- case SV_POTION_DEC_WIS:
- case SV_POTION_DEC_DEX:
- case SV_POTION_DEC_CON:
- case SV_POTION_DEC_CHR:
- case SV_POTION_WATER: /* perhaps a 'water' attack? */
- case SV_POTION_APPLE_JUICE:
- return TRUE;
-
- case SV_POTION_INFRAVISION:
- case SV_POTION_DETECT_INVIS:
- case SV_POTION_SLOW_POISON:
- case SV_POTION_CURE_POISON:
- case SV_POTION_BOLDNESS:
- case SV_POTION_RESIST_HEAT:
- case SV_POTION_RESIST_COLD:
- case SV_POTION_HEROISM:
- case SV_POTION_BESERK_STRENGTH:
- case SV_POTION_RESTORE_EXP:
- case SV_POTION_RES_STR:
- case SV_POTION_RES_INT:
- case SV_POTION_RES_WIS:
- case SV_POTION_RES_DEX:
- case SV_POTION_RES_CON:
- case SV_POTION_RES_CHR:
- case SV_POTION_INC_STR:
- case SV_POTION_INC_INT:
- case SV_POTION_INC_WIS:
- case SV_POTION_INC_DEX:
- case SV_POTION_INC_CON:
- case SV_POTION_INC_CHR:
- case SV_POTION_AUGMENTATION:
- case SV_POTION_ENLIGHTENMENT:
- case SV_POTION_STAR_ENLIGHTENMENT:
- case SV_POTION_SELF_KNOWLEDGE:
- case SV_POTION_EXPERIENCE:
- case SV_POTION_RESISTANCE:
- case SV_POTION_INVULNERABILITY:
- case SV_POTION_NEW_LIFE:
- /* All of the above potions have no effect when shattered */
- return FALSE;
- case SV_POTION_SLOWNESS:
- dt = GF_OLD_SLOW;
- dam = 5;
- ident = TRUE;
- angry = TRUE;
- break;
- case SV_POTION_POISON:
- dt = GF_POIS;
- dam = 3;
- ident = TRUE;
- angry = TRUE;
- break;
- case SV_POTION_BLINDNESS:
- dt = GF_DARK;
- ident = TRUE;
- angry = TRUE;
- break;
- case SV_POTION_CONFUSION: /* Booze */
- dt = GF_OLD_CONF;
- ident = TRUE;
- angry = TRUE;
- break;
- case SV_POTION_SLEEP:
- dt = GF_OLD_SLEEP;
- angry = TRUE;
- ident = TRUE;
- break;
- case SV_POTION_RUINATION:
- case SV_POTION_DETONATIONS:
- dt = GF_SHARDS;
- dam = damroll(25, 25);
- angry = TRUE;
- ident = TRUE;
- break;
- case SV_POTION_DEATH:
- dt = GF_MANA; /* !! */
- dam = damroll(10, 10);
- angry = TRUE;
- radius = 1;
- ident = TRUE;
- break;
- case SV_POTION_SPEED:
- dt = GF_OLD_SPEED;
- ident = TRUE;
- break;
- case SV_POTION_CURE_LIGHT:
- dt = GF_OLD_HEAL;
- dam = damroll(2, 3);
- ident = TRUE;
- break;
- case SV_POTION_CURE_SERIOUS:
- dt = GF_OLD_HEAL;
- dam = damroll(4, 3);
- ident = TRUE;
- break;
- case SV_POTION_CURE_CRITICAL:
- case SV_POTION_CURING:
- dt = GF_OLD_HEAL;
- dam = damroll(6, 3);
- ident = TRUE;
- break;
- case SV_POTION_HEALING:
- dt = GF_OLD_HEAL;
- dam = damroll(10, 10);
- ident = TRUE;
- break;
- case SV_POTION_STAR_HEALING:
- case SV_POTION_LIFE:
- dt = GF_OLD_HEAL;
- dam = damroll(50, 50);
- radius = 1;
- ident = TRUE;
- break;
- case SV_POTION_RESTORE_MANA: /* MANA */
- dt = GF_MANA;
- dam = damroll(10, 10);
- radius = 1;
- ident = TRUE;
- break;
- default:
- /* Do nothing */
- ;
- }
-
- (void) project(who, radius, y, x, dam, dt,
- (PROJECT_JUMP | PROJECT_ITEM | PROJECT_KILL));
-
- /* XXX those potions that explode need to become "known" */
- return angry;
-}
-
-/* This is for Thaumaturgy */
-static const int destructive_attack_types[10] =
-{
- GF_KILL_WALL,
- GF_KILL_WALL,
- GF_KILL_WALL,
- GF_STONE_WALL,
- GF_STONE_WALL,
- GF_STONE_WALL,
- GF_DESTRUCTION,
- GF_DESTRUCTION,
- GF_DESTRUCTION,
- GF_DESTRUCTION,
-};
-
-/* Also for Power-mages */
-static const int attack_types[25] =
-{
- GF_ARROW,
- GF_MISSILE,
- GF_MANA,
- GF_WATER,
- GF_PLASMA,
- GF_METEOR,
- GF_ICE,
- GF_GRAVITY,
- GF_INERTIA,
- GF_FORCE,
- GF_TIME,
- GF_ACID,
- GF_ELEC,
- GF_FIRE,
- GF_COLD,
- GF_POIS,
- GF_LITE,
- GF_DARK,
- GF_CONFUSION,
- GF_SOUND,
- GF_SHARDS,
- GF_NEXUS,
- GF_NETHER,
- GF_CHAOS,
- GF_DISENCHANT,
-};
-
-/*
- * Describe the attack using normal names.
- */
-
-void describe_attack_fully(int type, char* r)
-{
- switch (type)
- {
- case GF_ARROW:
- strcpy(r, "arrows");
- break;
- case GF_MISSILE:
- strcpy(r, "magic missiles");
- break;
- case GF_MANA:
- strcpy(r, "mana");
- break;
- case GF_LITE_WEAK:
- strcpy(r, "light");
- break;
- case GF_DARK_WEAK:
- strcpy(r, "dark");
- break;
- case GF_WATER:
- strcpy(r, "water");
- break;
- case GF_PLASMA:
- strcpy(r, "plasma");
- break;
- case GF_METEOR:
- strcpy(r, "meteors");
- break;
- case GF_ICE:
- strcpy(r, "ice");
- break;
- case GF_GRAVITY:
- strcpy(r, "gravity");
- break;
- case GF_INERTIA:
- strcpy(r, "inertia");
- break;
- case GF_FORCE:
- strcpy(r, "force");
- break;
- case GF_TIME:
- strcpy(r, "pure time");
- break;
- case GF_ACID:
- strcpy(r, "acid");
- break;
- case GF_ELEC:
- strcpy(r, "lightning");
- break;
- case GF_FIRE:
- strcpy(r, "flames");
- break;
- case GF_COLD:
- strcpy(r, "cold");
- break;
- case GF_POIS:
- strcpy(r, "poison");
- break;
- case GF_LITE:
- strcpy(r, "pure light");
- break;
- case GF_DARK:
- strcpy(r, "pure dark");
- break;
- case GF_CONFUSION:
- strcpy(r, "confusion");
- break;
- case GF_SOUND:
- strcpy(r, "sound");
- break;
- case GF_SHARDS:
- strcpy(r, "shards");
- break;
- case GF_NEXUS:
- strcpy(r, "nexus");
- break;
- case GF_NETHER:
- strcpy(r, "nether");
- break;
- case GF_CHAOS:
- strcpy(r, "chaos");
- break;
- case GF_DISENCHANT:
- strcpy(r, "disenchantment");
- break;
- case GF_KILL_WALL:
- strcpy(r, "wall destruction");
- break;
- case GF_KILL_DOOR:
- strcpy(r, "door destruction");
- break;
- case GF_KILL_TRAP:
- strcpy(r, "trap destruction");
- break;
- case GF_STONE_WALL:
- strcpy(r, "wall creation");
- break;
- case GF_MAKE_DOOR:
- strcpy(r, "door creation");
- break;
- case GF_MAKE_TRAP:
- strcpy(r, "trap creation");
- break;
- case GF_DESTRUCTION:
- strcpy(r, "destruction");
- break;
-
- default:
- strcpy(r, "something unknown");
- break;
- }
-}
-
-/*
- * Give a randomly-generated spell a name.
- * Note that it only describes the first effect!
- */
-
-static void name_spell(random_spell* s_ptr)
-{
- char buff[30];
- cptr buff2 = "???";
-
- if (s_ptr->proj_flags & PROJECT_STOP && s_ptr->radius == 0)
- {
- buff2 = "Bolt";
- }
- else if (s_ptr->proj_flags & PROJECT_BEAM)
- {
- buff2 = "Beam";
- }
- else if (s_ptr->proj_flags & PROJECT_STOP && s_ptr->radius > 0)
- {
- buff2 = "Ball";
- }
- else if (s_ptr->proj_flags & PROJECT_BLAST)
- {
- buff2 = "Blast";
- }
- else if (s_ptr->proj_flags & PROJECT_METEOR_SHOWER)
- {
- buff2 = "Area";
- }
- else if (s_ptr->proj_flags & PROJECT_VIEWABLE)
- {
- buff2 = "View";
- }
-
- describe_attack_fully(s_ptr->GF, buff);
- strnfmt(s_ptr->name, 30, "%s - %s", buff2, buff);
-}
-
-void generate_spell(int plev)
-{
- random_spell* rspell;
- int dice, sides, chance, mana, power;
- bool_ destruc_gen = FALSE;
- bool_ simple_gen = TRUE;
- bool_ ball_desc = FALSE;
-
- if (spell_num == MAX_SPELLS) return;
-
- rspell = &random_spells[spell_num];
-
- power = rand_int(5);
-
- dice = plev / 2;
- sides = plev;
- mana = plev;
-
- /* Make the spell more or less powerful. */
- dice += power;
- sides += power;
- mana += (plev * power) / 15;
-
- /* Stay within reasonable bounds. */
- if (dice < 1) dice = 1;
-
- if (sides < 5) sides = 5;
-
- if (mana < 1) mana = 1;
-
- rspell->level = plev;
- rspell->mana = mana;
- rspell->untried = TRUE;
-
- /* Spells are always maximally destructive. */
- rspell->proj_flags = PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID;
-
- chance = randint(100);
-
- /* Hack -- Always start with Magic Missile or derivative at lev. 1 */
- if (plev == 1 || chance < 25)
- {
- rspell->proj_flags |= PROJECT_STOP;
- /* Swap dice and sides for better damage */
- rspell->dam_dice = sides;
- rspell->dam_sides = dice;
- rspell->radius = 0;
- }
- else if (chance < 50)
- {
- rspell->proj_flags |= PROJECT_BEAM;
- rspell->dam_dice = dice;
- rspell->dam_sides = sides;
- rspell->radius = 0;
- }
- else if (chance < 76)
- {
- rspell->proj_flags |= PROJECT_STOP;
- rspell->radius = dice / 3;
- rspell->dam_dice = dice;
- rspell->dam_sides = sides;
- ball_desc = TRUE;
- }
- else if (chance < 83)
- {
- rspell->proj_flags |= PROJECT_BLAST;
- rspell->radius = sides / 3;
- rspell->dam_dice = dice;
- rspell->dam_sides = sides;
-
- destruc_gen = TRUE;
- simple_gen = FALSE;
- }
- else if (chance < 90)
- {
- rspell->proj_flags |= PROJECT_METEOR_SHOWER;
- /* Area effect spells do way less damage "per shot" */
- rspell->dam_dice = dice / 5;
- rspell->dam_sides = sides / 5;
- rspell->radius = sides / 3;
- if (rspell->radius < 4) rspell->radius = 4;
-
- destruc_gen = TRUE;
- }
- else
- {
- rspell->proj_flags |= PROJECT_VIEWABLE;
- /* View spells do less damage */
- rspell->dam_dice = dice;
- rspell->dam_sides = sides / 2;
- }
-
- /* Both a destructive and a simple spell requested --
- * pick one or the other. */
- if (destruc_gen && simple_gen)
- {
- if (magik(25))
- {
- simple_gen = FALSE;
- }
- else
- {
- destruc_gen = FALSE;
- }
- }
-
- /* Pick a simple spell */
- if (simple_gen)
- {
- rspell->GF = attack_types[rand_int(25)];
- }
- /* Pick a destructive spell */
- else
- {
- rspell->GF = destructive_attack_types[rand_int(10)];
- }
-
- /* Give the spell a name. */
- name_spell(rspell);
- if (ball_desc)
- {
- /* 30 character limit on the string! */
- sprintf(rspell->desc, "Dam: %d, Rad: %d, Pow: %d",
- sides, dice, power);
- }
- else
- {
- sprintf(rspell->desc, "Damage: %dd%d, Power: %d",
- dice, sides, power);
- }
-
- spell_num++;
-}
-
-/*
- * Polymorph a monster at given location.
- */
-s16b do_poly_monster(int y, int x)
-{
- cave_type *c_ptr = &cave[y][x];
-
- monster_type *m_ptr;
-
- s16b hack_m_idx;
- s16b old_m_idx;
- s16b new_m_idx = 0;
-
- s16b new_r_idx;
-
- /* Get a "old" monster */
- old_m_idx = c_ptr->m_idx;
-
- /* Giga-Hack -- Remember monster */
- hack_m_idx = old_m_idx;
-
- /* Get a monster */
- m_ptr = &m_list[c_ptr->m_idx];
-
- /* Pick a "new" monster race */
- new_r_idx = poly_r_idx(m_ptr->r_idx);
-
- /* No polymorph happend */
- if (new_r_idx == m_ptr->r_idx) return 0;
-
- /* Giga-Hack -- Removes the moster XXX XXX XXX XXX */
- c_ptr->m_idx = 0;
-
- /*
- * Handle polymorph --
- * Create a new monster (no groups)
- */
- if (place_monster_aux(y, x, new_r_idx, FALSE, FALSE, m_ptr->status))
- {
- /* Get a "new" monster */
- new_m_idx = c_ptr->m_idx;
-
- /* Giga-Hack -- Remember "new" monster */
- hack_m_idx = new_m_idx;
-
- /* "Kill" the "old" monster */
- delete_monster_idx(old_m_idx);
-
- p_ptr->redraw |= (PR_MAP);
- }
-
- /* Giga-Hack -- restore saved monster XXX XXX XXX */
- c_ptr->m_idx = hack_m_idx;
-
- return new_m_idx;
-}