summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mon-util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/mon-util.cc')
-rw-r--r--crawl-ref/source/mon-util.cc498
1 files changed, 84 insertions, 414 deletions
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index e06b511c72..fc30799dc5 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -294,8 +294,7 @@ bool mons_class_flag(int mc, int bf)
return ((me->bitfields & bf) != 0);
} // end mons_class_flag()
-static int scan_mon_inv_randarts( const monsters *mon,
- randart_prop_type ra_prop)
+static int scan_mon_inv_randarts( const monsters *mon, int ra_prop )
{
int ret = 0;
@@ -370,17 +369,6 @@ bool mons_is_stationary(const monsters *mons)
return (mons_class_is_stationary(mons->type));
}
-bool mons_class_is_confusable(int mc)
-{
- return (smc->resist_magic < MAG_IMMUNE
- && mons_intel(mc) > I_PLANT);
-}
-
-bool mons_class_is_slowable(int mc)
-{
- return (smc->resist_magic < MAG_IMMUNE);
-}
-
// returns whether a monster is non-solid
// and thus can't be affected by some traps
bool mons_is_insubstantial(int type)
@@ -489,11 +477,6 @@ bool mons_is_humanoid( int mc )
case 'T': // trolls
return (true);
- case 'm': // merfolk
- if (mc == MONS_MERFOLK || mc == MONS_MERMAID)
- return (true);
- return (false);
-
case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
if (mc != MONS_GARGOYLE
&& mc != MONS_METAL_GARGOYLE
@@ -1496,7 +1479,6 @@ void define_monster(monsters &mons)
// reset monster enchantments
mons.enchantments.clear();
- mons.ench_countdown = 0;
} // end define_monster()
static std::string str_monam(const monsters& mon, description_level_type desc,
@@ -1980,7 +1962,6 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
bool ret = false;
int intel, est_magic_resist, power, diff;
- const actor *foe = mon->get_foe();
// Eventually, we'll probably want to be able to have monsters
// learn which of their elemental bolts were resisted and have those
// handled here as well. -- bwr
@@ -1988,10 +1969,11 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
{
case SPELL_BACKLIGHT:
{
- ret = !foe || foe->backlit();
+ const actor *foe = mon->get_foe();
+ ret = !foe || foe->backlit() || foe->invisible();
break;
}
-
+
case SPELL_BERSERKER_RAGE:
if (!mon->needs_berserk(false))
ret = true;
@@ -2039,10 +2021,6 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
case SPELL_BANISHMENT:
case SPELL_DISINTEGRATE:
case SPELL_PARALYSE:
- case SPELL_SLEEP:
- if (monspell == SPELL_SLEEP && (!foe || foe->asleep()))
- return (true);
-
// occasionally we don't estimate... just fire and see:
if (one_chance_in(5))
return (false);
@@ -2061,7 +2039,9 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
if (mon->foe == MHITYOU)
est_magic_resist = player_res_magic();
else
+ {
est_magic_resist = mons_resist_magic(&menv[mon->foe]);
+ }
// now randomize (normal intels less accurate than high):
if (intel == I_NORMAL)
@@ -2186,7 +2166,6 @@ const char *mons_pronoun(monster_type mon_type, pronoun_type variant)
case MONS_EROLCHA:
case MONS_ERICA:
case MONS_TIAMAT:
- case MONS_MERMAID:
gender = GENDER_FEMALE;
break;
default:
@@ -2328,7 +2307,7 @@ monsters::monsters()
target_x(0), target_y(0), inv(), spells(), attitude(ATT_HOSTILE),
behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L),
experience(0), number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD),
- ghost(), seen_context("")
+ ghost()
{
}
@@ -2404,36 +2383,6 @@ bool monsters::floundering() const
&& !mons_flies(this));
}
-bool mons_class_can_pass(const int mclass, const dungeon_feature_type grid)
-{
- // Permanent walls can't be passed through.
- if (grid == DNGN_CLEAR_PERMAROCK_WALL || grid == DNGN_PERMAROCK_WALL)
- return false;
-
- switch (mclass)
- {
- case MONS_ROCK_WORM:
- return (!grid_is_solid(grid) || grid_is_rock(grid));
- }
-
- return !grid_is_solid(grid);
-}
-
-bool monsters::can_pass_through(const dungeon_feature_type grid) const
-{
- return mons_class_can_pass(type, grid);
-}
-
-bool monsters::can_pass_through(const int _x, const int _y) const
-{
- return can_pass_through(grd[_x][_y]);
-}
-
-bool monsters::can_pass_through(const coord_def &c) const
-{
- return can_pass_through(grd(c));
-}
-
bool monsters::can_drown() const
{
// Mummies can fall apart in water; ghouls and demons can drown in
@@ -2450,145 +2399,6 @@ size_type monsters::body_size(int /* psize */, bool /* base */) const
return (e? e->size : SIZE_MEDIUM);
}
-int monsters::body_weight() const
-{
- int mclass = type;
-
- switch(mclass)
- {
- case MONS_SPECTRAL_THING:
- case MONS_SPECTRAL_WARRIOR:
- case MONS_ELECTRIC_GOLEM:
- case MONS_RAKSHASA_FAKE:
- return 0;
-
- case MONS_ZOMBIE_SMALL:
- case MONS_ZOMBIE_LARGE:
- case MONS_SKELETON_SMALL:
- case MONS_SKELETON_LARGE:
- case MONS_SIMULACRUM_SMALL:
- case MONS_SIMULACRUM_LARGE:
- mclass = number;
- break;
- default:
- break;
- }
-
- int weight = mons_weight(mclass);
-
- // Water elementals are "insubstantial", but still have weight.
- if (weight == 0 && type == MONS_WATER_ELEMENTAL)
- weight = 1500;
-
- // weight == 0 in the monster entry indicates "no corpse". Can't
- // use CE_NOCORPSE, because the corpse-effect field is used for
- // corpseless monsters to indicate what happens if their blood
- // is sucked. Grrrr.
- if (weight == 0 && !mons_is_insubstantial(type))
- {
- const monsterentry *entry = get_monster_data(mclass);
- switch(entry->size)
- {
- case SIZE_TINY:
- weight = 150;
- break;
- case SIZE_LITTLE:
- weight = 300;
- break;
- case SIZE_SMALL:
- weight = 425;
- break;
- case SIZE_MEDIUM:
- weight = 550;
- break;
- case SIZE_LARGE:
- weight = 1300;
- break;
- case SIZE_BIG:
- weight = 1500;
- break;
- case SIZE_GIANT:
- weight = 1800;
- break;
- case SIZE_HUGE:
- weight = 2200;
- break;
- default:
- mpr("ERROR: invalid monster body weight");
- perror("monsters::body_weight(): invalid monster body weight");
- end(0);
- }
-
- switch(mclass)
- {
- case MONS_IRON_DEVIL:
- weight += 550;
- break;
-
- case MONS_STONE_GOLEM:
- case MONS_EARTH_ELEMENTAL:
- case MONS_CRYSTAL_GOLEM:
- weight *= 2;
- break;
-
- case MONS_IRON_DRAGON:
- case MONS_IRON_GOLEM:
- weight *= 3;
- break;
-
- case MONS_QUICKSILVER_DRAGON:
- case MONS_SILVER_STATUE:
- weight *= 4;
- break;
-
- case MONS_WOOD_GOLEM:
- weight *= 2;
- weight /= 3;
- break;
-
- case MONS_FLYING_SKULL:
- case MONS_CURSE_SKULL:
- case MONS_SKELETAL_DRAGON:
- case MONS_SKELETAL_WARRIOR:
- weight /= 2;
- break;
-
- case MONS_SHADOW_FIEND:
- case MONS_SHADOW_IMP:
- case MONS_SHADOW_DEMON:
- weight /= 3;
- break;
- }
-
- switch(monster_symbols[mclass].glyph)
- {
- case 'L':
- weight /= 2;
- break;
-
- case 'p':
- weight = 0;
- break;
- }
- }
-
- if (type == MONS_SKELETON_SMALL || type == MONS_SKELETON_LARGE)
- weight /= 2;
-
- return (weight);
-}
-
-int monsters::total_weight() const
-{
- int burden = 0;
-
- for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
- if (inv[i] != NON_ITEM)
- burden += item_mass(mitm[inv[i]]) * mitm[inv[i]].quantity;
-
- return (body_weight() + burden);
-}
-
int monsters::damage_type(int which_attack)
{
const item_def *mweap = weapon(which_attack);
@@ -2713,8 +2523,7 @@ void monsters::equip_weapon(item_def &item, int near)
{
if (need_message(near))
mprf("%s wields %s.", name(DESC_CAP_THE).c_str(),
- item.name(DESC_NOCAP_A, false, false, true,
- false, ISFLAG_CURSED).c_str());
+ item.name(DESC_NOCAP_A).c_str());
const int brand = get_weapon_brand(item);
if (brand == SPWPN_PROTECTION)
@@ -2772,19 +2581,14 @@ void monsters::equip_armour(item_def &item, int near)
mprf("%s wears %s.", name(DESC_CAP_THE).c_str(),
item.name(DESC_NOCAP_A).c_str());
- const equipment_type eq = get_armour_slot(item);
- if (eq != EQ_SHIELD)
- {
- ac += property( item, PARM_AC );
-
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac += armour_plus;
- }
+ ac += property( item, PARM_AC );
- // Shields can affect evasion.
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac += armour_plus;
ev += property( item, PARM_EVASION ) / 2;
+
if (ev < 1)
ev = 1; // This *shouldn't* happen.
}
@@ -2808,8 +2612,7 @@ void monsters::unequip_weapon(item_def &item, int near)
{
if (need_message(near))
mprf("%s unwields %s.", name(DESC_CAP_THE).c_str(),
- item.name(DESC_NOCAP_A, false, false, true,
- false, ISFLAG_CURSED).c_str());
+ item.name(DESC_NOCAP_A).c_str());
const int brand = get_weapon_brand(item);
if (brand == SPWPN_PROTECTION)
@@ -2854,18 +2657,14 @@ void monsters::unequip_armour(item_def &item, int near)
mprf("%s takes off %s.", name(DESC_CAP_THE).c_str(),
item.name(DESC_NOCAP_A).c_str());
- const equipment_type eq = get_armour_slot(item);
- if (eq != EQ_SHIELD)
- {
- ac -= property( item, PARM_AC );
+ ac -= property( item, PARM_AC );
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac -= armour_plus;
- }
-
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac -= armour_plus;
ev -= property( item, PARM_EVASION ) / 2;
+
if (ev < 1)
ev = 1; // This *shouldn't* happen.
}
@@ -2900,11 +2699,8 @@ bool monsters::unequip(item_def &item, int slot, int near, bool force)
void monsters::lose_pickup_energy()
{
- monsterentry* entry = get_monster_data(type);
- int delta = speed * entry->energy_usage.pickup_percent / 100;
-
- if (speed_increment > 25 && delta < speed_increment)
- speed_increment -= delta;
+ if (speed_increment > 25 && speed < speed_increment)
+ speed_increment -= speed;
}
void monsters::pickup_message(const item_def &item, int near)
@@ -2922,11 +2718,6 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
{
if (items_stack(item, mitm[inv[slot]], force_merge))
{
- dungeon_events.fire_position_event(
- dgn_event(DET_ITEM_PICKUP, pos(), 0, item.index(),
- monster_index(this)),
- pos());
-
pickup_message(item, near);
inc_mitm_item_quantity( inv[slot], item.quantity );
destroy_item(item.index());
@@ -2936,11 +2727,6 @@ bool monsters::pickup(item_def &item, int slot, int near, bool force_merge)
}
return (false);
}
-
- dungeon_events.fire_position_event(
- dgn_event(DET_ITEM_PICKUP, pos(), 0, item.index(),
- monster_index(this)),
- pos());
const int index = item.index();
unlink_item(index);
@@ -3123,17 +2909,6 @@ bool monsters::wants_armour(const item_def &item) const
return (!mslot_item(MSLOT_ARMOUR));
}
-static mon_inv_type equip_slot_to_mslot(equipment_type eq)
-{
- switch (eq)
- {
- case EQ_WEAPON: return MSLOT_WEAPON;
- case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
- case EQ_SHIELD: return MSLOT_SHIELD;
- default: return (NUM_MONSTER_SLOTS);
- }
-}
-
bool monsters::pickup_armour(item_def &item, int near, bool force)
{
ASSERT(item.base_type == OBJ_ARMOUR);
@@ -3141,27 +2916,21 @@ bool monsters::pickup_armour(item_def &item, int near, bool force)
if (!force && !wants_armour(item))
return (false);
- const equipment_type eq = get_armour_slot(item);
- // XXX: Monsters can only equip body armour and shields (as of 0.4).
- // They can still be forced to wear stuff - this is needed for bardings.
- if (!force && eq != EQ_BODY_ARMOUR && eq != EQ_SHIELD)
+ // XXX: Monsters can only equip body armour (as of 0.3).
+ if (get_armour_slot(item) != EQ_BODY_ARMOUR)
return (false);
- const mon_inv_type mslot = equip_slot_to_mslot(eq);
- if (mslot == NUM_MONSTER_SLOTS)
- return false;
-
// XXX: Very simplistic armour evaluation for the moment.
- if (const item_def *existing_armour = slot_item(eq))
+ if (const item_def *existing_armour = slot_item(EQ_BODY_ARMOUR))
{
if (!force && existing_armour->armour_rating() >= item.armour_rating())
return (false);
- if (!drop_item(mslot, near))
+ if (!drop_item(MSLOT_ARMOUR, near))
return (false);
}
- return pickup(item, mslot, near);
+ return pickup(item, MSLOT_ARMOUR, near);
}
bool monsters::pickup_weapon(item_def &item, int near, bool force)
@@ -3318,10 +3087,7 @@ void monsters::swap_weapons(int near)
// Monsters can swap weapons really fast. :-)
if ((weap || alt) && speed_increment >= 2)
- {
- monsterentry *entry = get_monster_data(type);
- speed_increment -= div_rand_round(entry->energy_usage.attack, 5);
- }
+ speed_increment -= 2;
}
void monsters::wield_melee_weapon(int near)
@@ -3335,6 +3101,16 @@ void monsters::wield_melee_weapon(int near)
}
}
+static mon_inv_type equip_slot_to_mslot(equipment_type eq)
+{
+ switch (eq)
+ {
+ case EQ_WEAPON: return MSLOT_WEAPON;
+ case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
+ default: return (NUM_MONSTER_SLOTS);
+ }
+}
+
item_def *monsters::slot_item(equipment_type eq)
{
return mslot_item(equip_slot_to_mslot(eq));
@@ -3348,7 +3124,7 @@ item_def *monsters::mslot_item(mon_inv_type mslot) const
item_def *monsters::shield()
{
- return (mslot_item(MSLOT_SHIELD));
+ return (NULL);
}
std::string monsters::name(description_level_type desc) const
@@ -3395,7 +3171,9 @@ bool monsters::fumbles_attack(bool verbose)
{
if (verbose)
{
- if (you.can_see(this))
+ const bool player_can_see =
+ mons_near(this) && player_monster_visible(this);
+ if (player_can_see)
mprf("%s splashes around in the water.",
this->name(DESC_CAP_THE).c_str());
else if (!silenced(you.x_pos, you.y_pos) && !silenced(x, y))
@@ -3488,11 +3266,12 @@ bool monsters::caught() const
int monsters::shield_bonus() const
{
+ // XXX: Monsters don't actually get shields yet.
const item_def *shld = const_cast<monsters*>(this)->shield();
if (shld)
{
const int shld_c = property(*shld, PARM_AC);
- return (random2(1 + shld_c) + random2(hit_dice / 2));
+ return (random2(shld_c + random2(hit_dice / 2)) / 2);
}
return (-100);
}
@@ -3570,7 +3349,6 @@ flight_type monsters::flight_mode() const
bool monsters::is_levitating() const
{
- // Checking class flags is not enough - see mons_flies.
return (flight_mode() == FL_LEVITATE);
}
@@ -3729,7 +3507,6 @@ void monsters::ghost_init()
inv.init(NON_ITEM);
enchantments.clear();
- ench_countdown = 0;
find_place_to_live();
}
@@ -3834,7 +3611,6 @@ void monsters::reset()
destroy_inventory();
enchantments.clear();
- ench_countdown = 0;
inv.init(NON_ITEM);
flags = 0;
@@ -3983,7 +3759,7 @@ bool monsters::add_ench(const mon_enchant &ench)
return (true);
}
-void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
+void monsters::add_enchantment_effect(const mon_enchant &ench, bool)
{
// check for slow/haste
switch (ench.ench)
@@ -3998,7 +3774,6 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
speed = 100 + ((speed - 100) * 2);
else
speed *= 2;
-
break;
case ENCH_SLOW:
@@ -4006,15 +3781,8 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
speed = 100 + ((speed - 100) / 2);
else
speed /= 2;
-
break;
- case ENCH_SUBMERGED:
- if (type == MONS_AIR_ELEMENTAL && mons_near(this) && !quiet)
- mprf("%s merges itself into the air.",
- name(DESC_CAP_A, true).c_str() );
- break;
-
case ENCH_CHARM:
behaviour = BEH_SEEK;
target_x = you.x_pos;
@@ -4053,7 +3821,6 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
speed = 100 + ((speed - 100) / 2);
else
speed /= 2;
-
break;
case ENCH_SLOW:
@@ -4061,7 +3828,6 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
speed = 100 + ((speed - 100) * 2);
else
speed *= 2;
-
break;
case ENCH_PARALYSIS:
@@ -4163,36 +3929,6 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
monster_die( this, quiet? KILL_DISMISSED : KILL_RESET, 0 );
break;
- case ENCH_SUBMERGED:
- if (you.can_see(this))
- {
- if (!mons_is_safe( static_cast<const monsters*>(this))
- && is_run_delay(current_delay_action()))
- {
- // Already set somewhere else.
- if (seen_context != "")
- return;
-
- if (type == MONS_AIR_ELEMENTAL)
- seen_context = "thin air";
- else if (monster_habitable_grid(this, DNGN_FLOOR))
- seen_context = "bursts forth";
- else
- seen_context = "surfaces";
- }
- else if (!quiet)
- if (type == MONS_AIR_ELEMENTAL)
- mprf("%s forms itself from the air!",
- name(DESC_CAP_A, true).c_str() );
- }
- else if (mons_near(this) && monster_habitable_grid(this, DNGN_FLOOR))
- {
- mpr("Something invisble bursts forth from the water.");
- interrupt_activity( AI_FORCE_INTERRUPT );
- }
-
- break;
-
default:
break;
}
@@ -4331,20 +4067,18 @@ std::string monsters::describe_enchantments() const
return (oss.str());
}
-// used to adjust time durations in calc_duration() for monster speed
+// used to adjust time durations in handle_enchantment() for monster speed
static inline int mod_speed( int val, int speed )
{
if (!speed)
- speed = 10;
+ speed = you.time_taken;
const int modded = (speed ? (val * 10) / speed : val);
return (modded? modded : 1);
}
bool monsters::decay_enchantment(const mon_enchant &me, bool decay_degree)
{
- // Faster monsters can wiggle out of the net more quickly.
- const int spd = (me.ench == ENCH_HELD) ? speed :
- 10;
+ const int spd = speed == 0? you.time_taken : speed;
const int actdur = speed_to_duration(spd);
if (lose_ench_duration(me, actdur))
return (true);
@@ -4379,7 +4113,7 @@ bool monsters::decay_enchantment(const mon_enchant &me, bool decay_degree)
void monsters::apply_enchantment(const mon_enchant &me)
{
- const int spd = 10;
+ const int spd = speed == 0? you.time_taken : speed;
switch (me.ench)
{
case ENCH_BERSERK:
@@ -4439,8 +4173,8 @@ void monsters::apply_enchantment(const mon_enchant &me)
// the enchantment doubles as the durability of a net
// the more corroded it gets, the more easily it will break
- const int hold = mitm[net].plus; // this will usually be negative
- const int mon_size = body_size(PSIZE_BODY);
+ int hold = mitm[net].plus; // this will usually be negative
+ int mon_size = body_size(PSIZE_BODY);
// smaller monsters can escape more quickly
if (mon_size < random2(SIZE_BIG) // BIG = 5
@@ -4510,12 +4244,7 @@ void monsters::apply_enchantment(const mon_enchant &me)
// berserking doubles damage dealt
if (has_ench(ENCH_BERSERK))
damage *= 2;
-
- // Faster monsters can damage the net more often per
- // time period.
- if (speed != 0)
- damage = div_rand_round(damage * speed, spd);
-
+
mitm[net].plus -= damage;
if (mitm[net].plus < -7)
@@ -4578,11 +4307,13 @@ void monsters::apply_enchantment(const mon_enchant &me)
del_ench(ENCH_SUBMERGED); // forced to surface
else if (hit_points <= max_hit_points / 2)
break;
- else if (((type == MONS_ELECTRICAL_EEL || type == MONS_LAVA_SNAKE)
- && (one_chance_in(50) || (mons_near(this)
- && hit_points == max_hit_points
- && !one_chance_in(10))))
- || one_chance_in(200)
+ else if (((type == MONS_ELECTRICAL_EEL
+ || type == MONS_LAVA_SNAKE)
+ && (random2(1000) < mod_speed( 20, spd )
+ || (mons_near(this)
+ && hit_points == max_hit_points
+ && !one_chance_in(10))))
+ || random2(2000) < mod_speed(10, spd)
|| (mons_near(this)
&& hit_points == max_hit_points
&& !one_chance_in(5)))
@@ -4593,7 +4324,7 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
case ENCH_POISON:
{
- const int poisonval = me.degree;
+ int poisonval = me.degree;
int dam = (poisonval >= 4) ? 1 : 0;
if (coinflip())
@@ -4602,6 +4333,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
if (mons_res_poison(this) < 0)
dam += roll_dice( 2, poisonval ) - 1;
+ // We adjust damage for monster speed (since this is applied
+ // only when the monster moves), and we handle the factional
+ // part as well (so that speed 30 creatures will take damage).
+ dam *= 10;
+ dam = (dam / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0);
+
if (dam > 0)
{
hurt_monster( this, dam );
@@ -4625,7 +4362,8 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
case ENCH_ROT:
{
- if (hit_points > 1 && one_chance_in(3))
+ if (hit_points > 1
+ && random2(1000) < mod_speed( 333, spd ))
{
hurt_monster(this, 1);
if (hit_points < max_hit_points && coinflip())
@@ -4644,6 +4382,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
if (mons_res_fire( this ) < 0)
dam += roll_dice( 2, 5 ) - 1;
+ // We adjust damage for monster speed (since this is applied
+ // only when the monster moves), and we handle the factional
+ // part as well (so that speed 30 creatures will take damage).
+ dam *= 10;
+ dam = (dam / spd) + ((random2(spd) < (dam % spd)) ? 1 : 0);
+
if (dam > 0)
{
hurt_monster( this, dam );
@@ -4672,13 +4416,16 @@ void monsters::apply_enchantment(const mon_enchant &me)
case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
// number of actions is fine for shapeshifters
- if (type == MONS_GLOWING_SHAPESHIFTER || one_chance_in(4))
+ if (type == MONS_GLOWING_SHAPESHIFTER
+ || random2(1000) < mod_speed( 250, spd ))
+ {
monster_polymorph(this, RANDOM_MONSTER, PPT_SAME);
+ }
break;
case ENCH_SHAPESHIFTER: // this ench never runs out
if (type == MONS_SHAPESHIFTER
- || random2(1000) < ( 1000 / ((15 * hit_dice) / 5)))
+ || random2(1000) < mod_speed( 1000 / ((15 * hit_dice) / 5), spd ))
{
monster_polymorph(this, RANDOM_MONSTER, PPT_SAME);
}
@@ -4919,11 +4666,10 @@ bool monsters::can_see(const actor *target) const
int tx = mon->x;
int ty = mon->y;
- if (distance(x, y, tx, ty) > LOS_RADIUS * LOS_RADIUS)
- return false;
-
- // Ignoring clouds for now.
- return (num_feats_between(x, y, tx, ty, DNGN_UNSEEN, DNGN_MAXOPAQUE) == 0);
+ // Assume we can see any monster within LOS radius. This is inaccurate,
+ // but can be followed up with a tracer if essential. Trunk does full
+ // (expensive) ray tracing up front to figure this out.
+ return (distance(x, y, tx, ty) <= LOS_RADIUS * LOS_RADIUS);
}
void monsters::mutate()
@@ -4967,82 +4713,6 @@ void monsters::apply_location_effects()
if (alive())
mons_check_pool(this);
-
- if (alive() && has_ench(ENCH_SUBMERGED)
- && !monster_can_submerge(type, grd[x][y]))
- {
- del_ench(ENCH_SUBMERGED);
- }
-}
-
-// returns true if the trap should be revealed to the player
-bool monsters::do_shaft()
-{
- if (!is_valid_shaft_level())
- return (false);
-
- // Handle instances of do_shaft() being invoked magically when
- // the monster isn't standing over a shaft.
- if (trap_type_at_xy(x, y) != TRAP_SHAFT)
- {
- switch(grd[x][y])
- {
- case DNGN_FLOOR:
- case DNGN_OPEN_DOOR:
- case DNGN_TRAP_MECHANICAL:
- case DNGN_TRAP_MAGICAL:
- case DNGN_TRAP_NATURAL:
- case DNGN_UNDISCOVERED_TRAP:
- case DNGN_ENTER_SHOP:
- break;
-
- default:
- return (false);
- }
-
- if (airborne() || total_weight() == 0)
- {
- if (mons_near(this))
- {
- if (player_monster_visible(this))
- mprf("A shaft briefly opens up underneath %s!",
- name(DESC_NOCAP_THE).c_str());
- else
- mpr("A shaft briefly opens up in the floor!");
- }
- return (false);
- }
- }
-
- level_id lev = shaft_dest();
-
- if (lev == level_id::current())
- return (false);
-
- set_transit(lev);
- bool reveal = false;
- if (simple_monster_message(this, " falls through a shaft!"))
- reveal = true;;
-
- // Monster is no longer on this level
- destroy_inventory();
- monster_cleanup(this);
-
- return (reveal);
-}
-
-void monsters::put_to_sleep(int)
-{
- if (has_ench(ENCH_BERSERK))
- return;
- behaviour = BEH_SLEEP;
- add_ench(ENCH_SLEEPY);
- add_ench(ENCH_SLEEP_WARY);
-}
-
-void monsters::check_awaken(int)
-{
- // XXX
}
/////////////////////////////////////////////////////////////////////////