summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/mon-util.cc
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-01-09 14:24:11 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-01-09 14:24:11 +0000
commitf2a95ba0d453ba6685ed29201beda8a2f703ab79 (patch)
treee7201beb995472236921334a363644e5782d648b /crawl-ref/source/mon-util.cc
parent447bc8ac9d8557be01da02c40349e4301f42c089 (diff)
downloadcrawl-ref-f2a95ba0d453ba6685ed29201beda8a2f703ab79.tar.gz
crawl-ref-f2a95ba0d453ba6685ed29201beda8a2f703ab79.zip
Monsters get multilevel resists (incomplete). Monster data needs to be
adjusted per monster to hand out the right resists. The current MR_RES_FIRE gives one level of resistance only. Added a real ghost structure, discarded the old ghost values array. Adjusted bones file format so bones will work out-of-the-box with Hearse. Breaks bones format, older bones will be rejected. Fixed some maps with bad DEPTHs. Added more safe answers in Y/N prompts, added a check to make it less likely that Crawl will spin in a tight loop reading input from a closed tty. (Experimental) !a will override existing foe of friendlies in LOS. Blademasters no longer pick up stuff to throw (Erik). Zombies of swimming things are also swimming things. Currently applies only to zombies explicitly placed in .des files, since fish zombies cannot be generated otherwise (can of worms). Morgue is now saved before showing the inventory and other boring end-of-game stuff. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3231 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/mon-util.cc')
-rw-r--r--crawl-ref/source/mon-util.cc270
1 files changed, 174 insertions, 96 deletions
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 8fad0cfef9..8a9eef2355 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -34,6 +34,8 @@
#include "debug.h"
#include "delay.h"
#include "dgnevent.h"
+#include "fight.h"
+#include "ghost.h"
#include "insult.h"
#include "itemname.h"
#include "itemprop.h"
@@ -256,14 +258,18 @@ void init_monster_symbols()
}
}
-unsigned long get_mons_class_resists(int mc)
+const mon_resist_def &get_mons_class_resists(int mc)
{
- return (smc->resists);
+ const monsterentry *me = get_monster_data(mc);
+ return (me? me->resists : get_monster_data(MONS_PROGRAM_BUG)->resists);
}
-unsigned long get_mons_resists(const monsters *mon)
+mon_resist_def get_mons_resists(const monsters *mon)
{
- unsigned long resists = get_mons_class_resists(mon->type);
+ if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
+ return (mon->ghost->resists);
+
+ mon_resist_def resists = get_mons_class_resists(mon->type);
if ((mons_genus(mon->type) == MONS_DRACONIAN &&
mon->type != MONS_DRACONIAN) ||
mon->type == MONS_TIAMAT)
@@ -290,11 +296,6 @@ int mons_piety(const monsters *mon)
return (mon->hit_dice * 14);
}
-unsigned long mons_resist(const monsters *mon, unsigned long flags)
-{
- return (get_mons_resists(mon) & flags);
-}
-
bool mons_class_flag(int mc, int bf)
{
const monsterentry *me = smc;
@@ -394,7 +395,7 @@ bool mons_class_is_slowable(int mc)
bool mons_is_wall_shielded(int mc)
{
- return (mons_habitat(mc) == HT_ROCK);
+ return (mons_habitat_by_type(mc) == HT_ROCK);
}
// returns whether a monster is non-solid
@@ -605,7 +606,7 @@ bool mons_sense_invis(const monsters *mon)
bool mons_see_invis(const monsters *mon)
{
if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_SEE_INVIS ]);
+ return (mon->ghost->see_invis);
else if (mons_class_flag(mon->type, M_SEE_INVIS))
return (true);
else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
@@ -739,7 +740,7 @@ mon_attack_def mons_attack_spec(const monsters *mons, int attk_number)
if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
{
if (attk_number == 0)
- return mon_attack_def::attk(mons->ghost->values[GVAL_DAMAGE]);
+ return mon_attack_def::attk(mons->ghost->damage);
else
return mon_attack_def::attk(0, AT_NONE);
}
@@ -852,14 +853,10 @@ int mons_res_elec( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_ELEC ]);
-
/* this is a variable, not a player_xx() function, so can be above 1 */
int u = 0;
- if (mons_resist(mon, MR_RES_ELEC))
- u++;
+ u += get_mons_resists(mon).elec;
// don't bother checking equipment if the monster can't use it
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
@@ -885,26 +882,19 @@ bool mons_res_asphyx( const monsters *mon )
|| holiness == MH_DEMONIC
|| holiness == MH_NONLIVING
|| holiness == MH_PLANT
- || mons_resist(mon, MR_RES_ASPHYX));
+ || get_mons_resists(mon).asphyx > 0);
}
int mons_res_acid( const monsters *mon )
{
- const unsigned long f = get_mons_resists(mon);
- return ((f & MR_RES_ACID) != 0);
+ return get_mons_resists(mon).acid;
}
int mons_res_poison( const monsters *mon )
{
int mc = mon->type;
- unsigned long u = 0, f = get_mons_resists(mon);
-
- if (f & MR_RES_POISON)
- u++;
-
- if (f & MR_VUL_POISON)
- u--;
+ int u = get_mons_resists(mon).poison;
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -930,26 +920,27 @@ int mons_res_poison( const monsters *mon )
return (u);
} // end mons_res_poison()
+bool mons_res_sticky_flame( const monsters *mon )
+{
+ return (get_mons_resists(mon).sticky_flame
+ || mon->has_equipped(EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR));
+}
+
+int mons_res_steam( const monsters *mon )
+{
+ int res = get_mons_resists(mon).steam;
+ if (mon->has_equipped(EQ_BODY_ARMOUR, ARM_STEAM_DRAGON_ARMOUR))
+ res += 3;
+ return (res + mons_res_fire(mon) / 2);
+}
+
int mons_res_fire( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_FIRE ]);
-
- int u = 0, f = get_mons_resists(mon);
-
- // no Big Prize (tm) here either if you set all three flags. It's a pity uh?
- //
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_HELLFIRE)
- u += 3;
- else if (f & MR_RES_FIRE)
- u += 2;
- else if (f & MR_VUL_FIRE)
- u--;
+ const mon_resist_def res = get_mons_resists(mon);
+
+ int u = std::min(res.fire + res.hellfire * 3, 3);
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -982,18 +973,7 @@ int mons_res_cold( const monsters *mon )
{
int mc = mon->type;
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (mon->ghost->values[ GVAL_RES_COLD ]);
-
- int u = 0, f = get_mons_resists(mon);
-
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_COLD)
- u += 2;
- else if (f & MR_VUL_COLD)
- u--;
+ int u = get_mons_resists(mon).cold;
if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
{
@@ -1104,9 +1084,9 @@ flight_type mons_class_flies(int mc)
flight_type mons_flies(const monsters *mon)
{
if (mon->type == MONS_PANDEMONIUM_DEMON
- && mon->ghost->values[ GVAL_DEMONLORD_FLY ])
+ && mon->ghost->fly)
{
- return (FL_FLY);
+ return (mon->ghost->fly);
}
const flight_type ret = mons_class_flies( mon->type );
@@ -1686,9 +1666,16 @@ mon_intel_type mons_intel(int mc)
return (smc->intel);
}
-habitat_type mons_habitat(int mc)
+habitat_type mons_habitat_by_type(int mc)
+{
+ const monsterentry *me = get_monster_data(mc);
+ return (me? me->habitat : HT_LAND);
+}
+
+habitat_type mons_habitat(const monsters *m)
{
- return (smc->habitat);
+ return mons_habitat_by_type(
+ mons_is_zombified(m)? mons_zombie_base(m) : m->type );
}
bool intelligent_ally(const monsters *monster)
@@ -1761,7 +1748,7 @@ int mons_offhand_weapon_index(const monsters *m)
int mons_base_damage_brand(const monsters *m)
{
if (m->type == MONS_PLAYER_GHOST || m->type == MONS_PANDEMONIUM_DEMON)
- return m->ghost->values[ GVAL_BRAND ];
+ return m->ghost->brand;
return (SPWPN_NORMAL);
}
@@ -1986,6 +1973,15 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
int intel, est_magic_resist, power, diff;
const actor *foe = mon->get_foe();
+
+ // Keep friendly summoners from spamming summons constantly.
+ if (mons_friendly(mon)
+ && (!foe || foe == &you)
+ && spell_typematch(monspell, SPTYP_SUMMONING))
+ {
+ return (true);
+ }
+
// 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
@@ -2337,6 +2333,11 @@ monsters::monsters()
{
}
+// Empty destructor to keep auto_ptr happy with incomplete ghost_demon type.
+monsters::~monsters()
+{
+}
+
monsters::monsters(const monsters &mon)
{
init_with(mon);
@@ -2395,7 +2396,7 @@ coord_def monsters::target_pos() const
bool monsters::swimming() const
{
const dungeon_feature_type grid = grd[x][y];
- return (grid_is_watery(grid) && mons_habitat(type) == HT_WATER);
+ return (grid_is_watery(grid) && mons_habitat(this) == HT_WATER);
}
bool monsters::submerged() const
@@ -2409,7 +2410,7 @@ bool monsters::floundering() const
return (grid_is_water(grid)
// Can't use monster_habitable_grid because that'll return true
// for non-water monsters in shallow water.
- && mons_habitat(type) != HT_WATER
+ && mons_habitat(this) != HT_WATER
&& !mons_amphibious(type)
&& !mons_flies(this));
}
@@ -2693,6 +2694,10 @@ bool monsters::can_use_missile(const item_def &item) const
// grabbing missiles.
if (has_spell_of_type(SPTYP_CONJURATION | SPTYP_SUMMONING))
return (false);
+
+ // Blademasters don't want to throw stuff.
+ if (type == MONS_DEEP_ELF_BLADEMASTER)
+ return (false);
if (item.base_type == OBJ_WEAPONS)
return (is_throwable(item));
@@ -3392,6 +3397,11 @@ int monsters::id() const
return (type);
}
+int monsters::get_experience_level() const
+{
+ return (hit_dice);
+}
+
bool monsters::fumbles_attack(bool verbose)
{
if (floundering() && one_chance_in(4))
@@ -3434,7 +3444,7 @@ void monsters::go_berserk(bool /* intentional */)
simple_monster_message(
this,
make_stringf(" shakes off %s lethargy.",
- name(DESC_NOCAP_YOUR).c_str()).c_str());
+ pronoun(PRONOUN_NOCAP_POSSESSIVE).c_str()).c_str());
}
del_ench(ENCH_HASTE);
del_ench(ENCH_FATIGUE, true); // give no additional message
@@ -3556,6 +3566,11 @@ int monsters::res_fire() const
return (mons_res_fire(this));
}
+int monsters::res_steam() const
+{
+ return (mons_res_steam(this));
+}
+
int monsters::res_cold() const
{
return (mons_res_cold(this));
@@ -3707,12 +3722,12 @@ void monsters::set_ghost(const ghost_demon &g)
void monsters::pandemon_init()
{
- hit_dice = ghost->values[ GVAL_DEMONLORD_HIT_DICE ];
- hit_points = ghost->values[ GVAL_MAX_HP ];
- max_hit_points = ghost->values[ GVAL_MAX_HP ];
- ac = ghost->values[ GVAL_AC ];
- ev = ghost->values[ GVAL_EV ];
- speed = (one_chance_in(3) ? 10 : 6 + roll_dice(2, 9));
+ hit_dice = ghost->xl;
+ hit_points = ghost->max_hp;
+ max_hit_points = ghost->max_hp;
+ ac = ghost->ac;
+ ev = ghost->ev;
+ speed = (one_chance_in(3) ? 10 : 8 + roll_dice(2, 9));
speed_increment = 70;
if (you.char_direction == GDT_ASCENDING && you.level_type == LEVEL_DUNGEON)
colour = LIGHTRED;
@@ -3724,12 +3739,12 @@ void monsters::pandemon_init()
void monsters::ghost_init()
{
type = MONS_PLAYER_GHOST;
- hit_dice = ghost->values[ GVAL_EXP_LEVEL ];
- hit_points = ghost->values[ GVAL_MAX_HP ];
- max_hit_points = ghost->values[ GVAL_MAX_HP ];
- ac = ghost->values[ GVAL_AC];
- ev = ghost->values[ GVAL_EV ];
- speed = ghost->values[ GVAL_SPEED ];
+ hit_dice = ghost->xl;
+ hit_points = ghost->max_hp;
+ max_hit_points = ghost->max_hp;
+ ac = ghost->ac;
+ ev = ghost->ev;
+ speed = ghost->speed;
speed_increment = 70;
attitude = ATT_HOSTILE;
behaviour = BEH_WANDER;
@@ -3896,16 +3911,7 @@ void monsters::load_spells(mon_spellbook_type book)
#endif
if (book == MST_GHOST)
- {
- for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
- {
- spells[i] =
- static_cast<spell_type>( ghost->values[ GVAL_SPELL_1 + i ] );
-#if DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "spell #%d: %d", i, spells[i] );
-#endif
- }
- }
+ spells = ghost->spells;
else
{
for (unsigned int i = 0; i < ARRAYSIZE(mspell_list); ++i)
@@ -3918,6 +3924,11 @@ void monsters::load_spells(mon_spellbook_type book)
}
}
}
+#if DEBUG_DIAGNOSTICS
+ for (int i = 0; i < NUM_MONSTER_SPELL_SLOTS; i++)
+ mprf( MSGCH_DIAGNOSTICS, "Spell #%d: %d (%s)",
+ i, spells[i], spell_title(spells[i]) );
+#endif
}
bool monsters::has_ench(enchant_type ench) const
@@ -4588,12 +4599,12 @@ void monsters::apply_enchantment(const mon_enchant &me)
}
// Now we handle the others:
- int grid = grd[x][y];
+ const dungeon_feature_type grid = grd[x][y];
// Badly injured monsters prefer to stay submerged...
// electrical eels and lava snakes have ranged attacks
// and are more likely to surface. -- bwr
- if (!monster_can_submerge(type, grid))
+ if (!monster_can_submerge(this, grid))
del_ench(ENCH_SUBMERGED); // forced to surface
else if (hit_points <= max_hit_points / 2)
break;
@@ -4658,10 +4669,8 @@ void monsters::apply_enchantment(const mon_enchant &me)
// assumption: mons_res_fire has already been checked
case ENCH_STICKY_FLAME:
{
- int dam = roll_dice( 2, 4 ) - 1;
-
- if (mons_res_fire( this ) < 0)
- dam += roll_dice( 2, 5 ) - 1;
+ int dam =
+ resist_adjust_damage(this, res_fire(), roll_dice( 2, 4 ) - 1);
if (dam > 0)
{
@@ -5002,7 +5011,7 @@ void monsters::apply_location_effects()
mons_check_pool(this);
if (alive() && has_ench(ENCH_SUBMERGED)
- && !monster_can_submerge(type, grd[x][y]))
+ && !monster_can_submerge(this, grd[x][y]))
{
del_ench(ENCH_SUBMERGED);
}
@@ -5430,7 +5439,7 @@ std::string do_mon_str_replacements(const std::string &in_msg,
if (mons_shouts(monster->type) >= NUM_SHOUTS)
{
mpr("Invalid @says@ type.", MSGCH_DIAGNOSTICS);
- msg = replace_all(msg, "@says@", "bugilly says");
+ msg = replace_all(msg, "@says@", "buggily says");
}
else
msg = replace_all(msg, "@says@",
@@ -5448,7 +5457,7 @@ static mon_body_shape get_ghost_shape(const monsters *mon)
{
const ghost_demon &ghost = *(mon->ghost);
- switch(ghost.values[GVAL_SPECIES])
+ switch (ghost.species)
{
case SP_NAGA:
return (MON_SHAPE_NAGA);
@@ -5472,9 +5481,10 @@ static mon_body_shape get_ghost_shape(const monsters *mon)
case SP_UNK1_DRACONIAN:
case SP_BASE_DRACONIAN:
return (MON_SHAPE_HUMANOID_TAILED);
- }
- return (MON_SHAPE_HUMANOID);
+ default:
+ return (MON_SHAPE_HUMANOID);
+ }
}
mon_body_shape get_mon_shape(const monsters *mon)
@@ -5706,3 +5716,71 @@ std::string get_mon_shape_str(const mon_body_shape shape)
return (shape_names[shape]);
}
+
+/////////////////////////////////////////////////////////////////////////
+// mon_resist_def
+
+mon_resist_def::mon_resist_def()
+ : elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
+ asphyx(0), acid(0), sticky_flame(false), pierce(0),
+ slice(0), bludgeon(0)
+{
+}
+
+mon_resist_def::mon_resist_def(int flags, short level)
+ : elec(0), poison(0), fire(0), steam(0), cold(0), hellfire(0),
+ asphyx(0), acid(0), sticky_flame(false), pierce(0),
+ slice(0), bludgeon(0)
+{
+ for (int i = 0; i < 32; ++i)
+ {
+ switch (flags & (1 << i))
+ {
+ case MR_RES_STEAM: steam = 3; break;
+ case MR_RES_ELEC: elec = level; break;
+ case MR_RES_POISON: poison = level; break;
+ case MR_RES_FIRE: fire = level; break;
+ case MR_RES_HELLFIRE: hellfire = level; break;
+ case MR_RES_COLD: cold = level; break;
+ case MR_RES_ASPHYX: asphyx = level; break;
+ case MR_RES_ACID: acid = level; break;
+ case MR_VUL_ELEC: elec = -level; break;
+ case MR_VUL_POISON: poison = -level; break;
+ case MR_VUL_FIRE: fire = -level; break;
+ case MR_VUL_COLD: cold = -level; break;
+
+ case MR_RES_PIERCE: pierce = level; break;
+ case MR_RES_SLICE: slice = level; break;
+ case MR_RES_BLUDGEON: bludgeon = level; break;
+ case MR_VUL_PIERCE: pierce = -level; break;
+ case MR_VUL_SLICE: slice = -level; break;
+ case MR_VUL_BLUDGEON: bludgeon = -level; break;
+
+ case MR_RES_STICKY_FLAME: sticky_flame = true; break;
+
+ default: break;
+ }
+ }
+}
+
+const mon_resist_def &mon_resist_def::operator |= (const mon_resist_def &o)
+{
+ elec += o.elec;
+ poison += o.poison;
+ fire += o.fire;
+ cold += o.cold;
+ hellfire += o.hellfire;
+ asphyx += o.asphyx;
+ acid += o.acid;
+ pierce += o.pierce;
+ slice += o.slice;
+ bludgeon += o.bludgeon;
+ sticky_flame = sticky_flame || o.sticky_flame;
+ return (*this);
+}
+
+mon_resist_def mon_resist_def::operator | (const mon_resist_def &o) const
+{
+ mon_resist_def c(*this);
+ return (c |= o);
+}