summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-21 21:23:21 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-03-21 21:23:21 +0000
commit109b00ddba65e56db1a90a374115df69070bca71 (patch)
tree0d22819524e8d7a5179e7ee280a4b16b16d6ded2 /crawl-ref
parent101ce9277219b6925dc9e7c70692984c6544c5cd (diff)
downloadcrawl-ref-109b00ddba65e56db1a90a374115df69070bca71.tar.gz
crawl-ref-109b00ddba65e56db1a90a374115df69070bca71.zip
Cleaned up monster enchantments. Instead of the old enum abuse (ENCH_ABJ_I, II,
etc.), enchantment is stored as a struct (ENCH_which, degree, whose_enchantment). This allows us to do such things as award experience for monsters poisoned by friends, or confused monsters bashing themselves or falling into lava (not implemented, but could be :-)). Doing monster_die() correctly is a little tricky for friendly-enchantment-deaths because the original monster may not be around to answer questions, so we fake the killer's stats for indirect friendly kills (which means that some gods may not award piety for minion-cast enchantments, f'r'instance). I think we can live with that for now. Breaks save file compatibility as usual. Clouds could also use similar treatment - poison clouds created by a friendly are not correctly tracked yet. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1075 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/Kills.cc4
-rw-r--r--crawl-ref/source/acr.cc18
-rw-r--r--crawl-ref/source/beam.cc191
-rw-r--r--crawl-ref/source/beam.h4
-rw-r--r--crawl-ref/source/debug.cc48
-rw-r--r--crawl-ref/source/decks.cc48
-rw-r--r--crawl-ref/source/defines.h3
-rw-r--r--crawl-ref/source/describe.cc4
-rw-r--r--crawl-ref/source/direct.cc106
-rw-r--r--crawl-ref/source/enum.h76
-rw-r--r--crawl-ref/source/externs.h54
-rw-r--r--crawl-ref/source/fight.cc8
-rw-r--r--crawl-ref/source/it_use3.cc12
-rw-r--r--crawl-ref/source/item_use.cc2
-rw-r--r--crawl-ref/source/items.cc151
-rw-r--r--crawl-ref/source/libutil.h3
-rw-r--r--crawl-ref/source/mon-util.cc859
-rw-r--r--crawl-ref/source/mon-util.h8
-rw-r--r--crawl-ref/source/monplace.cc34
-rw-r--r--crawl-ref/source/monspeak.cc8
-rw-r--r--crawl-ref/source/monstuff.cc489
-rw-r--r--crawl-ref/source/mstuff2.cc64
-rw-r--r--crawl-ref/source/player.cc9
-rw-r--r--crawl-ref/source/religion.cc20
-rw-r--r--crawl-ref/source/spells1.cc24
-rw-r--r--crawl-ref/source/spells2.cc40
-rw-r--r--crawl-ref/source/spells3.cc7
-rw-r--r--crawl-ref/source/spells4.cc86
-rw-r--r--crawl-ref/source/spl-cast.cc40
-rw-r--r--crawl-ref/source/stuff.h6
-rw-r--r--crawl-ref/source/tags.cc37
-rw-r--r--crawl-ref/source/view.cc2
32 files changed, 1111 insertions, 1354 deletions
diff --git a/crawl-ref/source/Kills.cc b/crawl-ref/source/Kills.cc
index b146a89cd5..8a85e04921 100644
--- a/crawl-ref/source/Kills.cc
+++ b/crawl-ref/source/Kills.cc
@@ -671,8 +671,8 @@ kill_monster_desc::kill_monster_desc(const monsters *mon)
}
if (modifier != M_NORMAL) monnum = mon->number;
- if (mons_has_ench(mon, ENCH_SHAPESHIFTER) ||
- mons_has_ench(mon, ENCH_GLOWING_SHAPESHIFTER))
+ if (mon->has_ench(ENCH_SHAPESHIFTER) ||
+ mon->has_ench(ENCH_GLOWING_SHAPESHIFTER))
modifier = M_SHAPESHIFTER;
// XXX: Ugly hack - merge all mimics into one mimic record.
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index e31ec340c2..5b75740269 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -2698,23 +2698,7 @@ static bool initialise(void)
strcpy(info, "");
for (i = 0; i < MAX_MONSTERS; i++)
- {
- menv[i].type = -1;
- menv[i].speed_increment = 10;
- menv[i].flags = 0;
- menv[i].behaviour = BEH_SLEEP;
-
- menv[i].foe = NON_MONSTER;
- menv[i].attitude = ATT_HOSTILE;
-
- for (j = 0; j < NUM_MON_ENCHANTS; j++)
- menv[i].enchantment[j] = ENCH_NONE;
-
- for (j = 0; j < NUM_MONSTER_SLOTS; j++)
- menv[i].inv[j] = NON_ITEM;
-
- menv[i].number = 0;
- }
+ menv[i].reset();
for (i = 0; i < GXM; i++)
{
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 593f6c3cc3..38cca50cd3 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -68,7 +68,7 @@ static FixedArray < bool, 19, 19 > explode_map;
// helper functions (some of these, esp. affect(), should probably
// be public):
-static void sticky_flame_monster( int mn, bool source, int hurt_final );
+static void sticky_flame_monster( int mn, kill_category who, int hurt_final );
static bool affectsWall(const bolt &beam, int wall_feature);
static bool isBouncy(struct bolt &beam, unsigned char gridtype);
static void beam_drop_object( struct bolt &beam, item_def *item, int x, int y );
@@ -126,6 +126,22 @@ static void monster_die(monsters *mons, const bolt &beam)
monster_die(mons, beam.killer(), beam.beam_source);
}
+static kill_category whose_kill(const bolt &beam)
+{
+ if (YOU_KILL(beam.thrower))
+ return (KC_YOU);
+ else if (MON_KILL(beam.thrower))
+ {
+ if (beam.beam_source >= 0 && beam.beam_source < MAX_MONSTERS)
+ {
+ const monsters &mons = menv[beam.beam_source];
+ if (mons.attitude == ATT_FRIENDLY)
+ return (KC_FRIENDLY);
+ }
+ }
+ return (KC_OTHER);
+}
+
// simple animated flash from Rupert Smith (and expanded to be more generic):
void zap_animation( int colour, const monsters *mon, bool force )
{
@@ -1565,7 +1581,7 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt,
}
else if (doFlavouredEffects && !one_chance_in(3))
{
- poison_monster( monster, YOU_KILL(pbolt.thrower) );
+ poison_monster( monster, whose_kill(pbolt) );
}
break;
@@ -1579,14 +1595,14 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt,
// Poison arrow can poison any living thing regardless of
// poison resistance. -- bwr
if (mons_has_lifeforce(monster))
- poison_monster( monster, YOU_KILL(pbolt.thrower), 2, true );
+ poison_monster( monster, whose_kill(pbolt), 2, true );
}
hurted /= 2;
}
else if (doFlavouredEffects)
{
- poison_monster( monster, YOU_KILL(pbolt.thrower), 4 );
+ poison_monster( monster, whose_kill(pbolt), 4 );
}
break;
@@ -1638,7 +1654,7 @@ int mons_adjust_flavoured( struct monsters *monster, struct bolt &pbolt,
return (hurted);
if (mons_res_poison( monster ) <= 0)
- poison_monster( monster, YOU_KILL(pbolt.thrower) );
+ poison_monster( monster, whose_kill(pbolt) );
if (one_chance_in( 3 + 2 * mons_res_negative_energy(monster) ))
{
@@ -1806,10 +1822,10 @@ bool mass_enchantment( int wh_enchant, int pow, int origin )
continue;
}
- if (mons_has_ench(monster, wh_enchant))
+ if (monster->has_ench(static_cast<enchant_type>(wh_enchant)))
continue;
- if (mons_add_ench(monster, wh_enchant))
+ if (monster->add_ench(static_cast<enchant_type>(wh_enchant)))
{
if (player_monster_visible( monster ))
{
@@ -1860,7 +1876,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
{
case BEAM_SLOW: /* 0 = slow monster */
// try to remove haste, if monster is hasted
- if (mons_del_ench(monster, ENCH_HASTE))
+ if (monster->del_ench(ENCH_HASTE))
{
if (simple_monster_message(monster, " is no longer moving quickly."))
pbolt.obvious_effect = true;
@@ -1869,9 +1885,9 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
}
// not hasted, slow it
- if (!mons_has_ench(monster, ENCH_SLOW)
+ if (!monster->has_ench(ENCH_SLOW)
&& !mons_is_stationary(monster)
- && mons_add_ench(monster, ENCH_SLOW))
+ && monster->add_ench(ENCH_SLOW))
{
if (!mons_is_paralysed(monster)
&& simple_monster_message(monster, " seems to slow down."))
@@ -1882,7 +1898,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
return (MON_AFFECTED);
case BEAM_HASTE: // 1 = haste
- if (mons_del_ench(monster, ENCH_SLOW))
+ if (monster->del_ench(ENCH_SLOW))
{
if (simple_monster_message(monster, " is no longer moving slowly."))
pbolt.obvious_effect = true;
@@ -1891,9 +1907,9 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
}
// not slowed, haste it
- if (!mons_has_ench(monster, ENCH_HASTE)
+ if (!monster->has_ench(ENCH_HASTE)
&& !mons_is_stationary(monster)
- && mons_add_ench(monster, ENCH_HASTE))
+ && monster->add_ench(ENCH_HASTE))
{
if (!mons_is_paralysed(monster)
&& simple_monster_message(monster, " seems to speed up."))
@@ -1925,7 +1941,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
return (MON_AFFECTED);
case BEAM_CONFUSION: /* 4 = confusion */
- if (mons_add_ench(monster, ENCH_CONFUSION))
+ if (monster->add_ench(ENCH_CONFUSION))
{
// put in an exception for fungi, plants and other things you won't
// notice becoming confused.
@@ -1939,8 +1955,8 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
{
const std::string monster_name = ptr_monam(monster, DESC_CAP_THE);
- if (!mons_has_ench(monster, ENCH_INVIS)
- && mons_add_ench(monster, ENCH_INVIS))
+ if (!monster->has_ench(ENCH_INVIS)
+ && monster->add_ench(ENCH_INVIS))
{
// Can't use simple_monster_message here, since it checks
// for visibility of the monster (and its now invisible) -- bwr
@@ -1957,7 +1973,7 @@ int mons_ench_f2(struct monsters *monster, struct bolt &pbolt)
return (MON_AFFECTED);
}
case BEAM_CHARM: /* 9 = charm */
- if (mons_add_ench(monster, ENCH_CHARM))
+ if (monster->add_ench(ENCH_CHARM))
{
// break fleeing and suchlike
monster->behaviour = BEH_SEEK;
@@ -1986,8 +2002,8 @@ static void slow_monster(monsters *mon, int /* degree */)
static void beam_paralyses_monster(bolt &pbolt, monsters *monster)
{
- if (!mons_has_ench(monster, ENCH_PARALYSIS)
- && mons_add_ench(monster, ENCH_PARALYSIS))
+ if (!monster->has_ench(ENCH_PARALYSIS)
+ && monster->add_ench(ENCH_PARALYSIS))
{
if (simple_monster_message(monster, " suddenly stops moving!"))
pbolt.obvious_effect = true;
@@ -1998,14 +2014,14 @@ static void beam_paralyses_monster(bolt &pbolt, monsters *monster)
// Returns true if the curare killed the monster.
bool curare_hits_monster( const bolt &beam,
- monsters *monster,
- bool fromPlayer,
+ monsters *monster,
+ kill_category who,
int levels )
{
const bool res_poison = mons_res_poison(monster);
bool mondied = false;
- poison_monster(monster, fromPlayer, levels, false);
+ poison_monster(monster, who, levels, false);
if (!mons_res_asphyx(monster))
{
@@ -2030,134 +2046,55 @@ bool curare_hits_monster( const bolt &beam,
}
// Deities take notice.
- if (fromPlayer)
+ if (who == KC_YOU)
did_god_conduct( DID_POISON, 5 + random2(3) );
return (mondied);
}
// actually poisons a monster (w/ message)
-void poison_monster( struct monsters *monster, bool fromPlayer, int levels,
+void poison_monster( monsters *monster,
+ kill_category from_whom,
+ int levels,
bool force )
{
- bool yourPoison = false;
- int ench = ENCH_NONE;
- int old_strength = 0;
-
- if (monster->type == -1)
+ if (!monster->alive())
return;
if (!force && mons_res_poison(monster) > 0)
return;
- // who gets the credit if monster dies of poison?
- ench = mons_has_ench( monster, ENCH_POISON_I, ENCH_POISON_IV );
- if (ench != ENCH_NONE)
- {
- old_strength = ench - ENCH_POISON_I;
- }
- else
- {
- ench = mons_has_ench(monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV);
- if (ench != ENCH_NONE)
- {
- old_strength = ench - ENCH_YOUR_POISON_I;
- yourPoison = true;
- }
- }
-
- // delete old poison
- mons_del_ench( monster, ENCH_POISON_I, ENCH_POISON_IV, true );
- mons_del_ench( monster, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV, true );
-
- // Calculate new strength:
- int new_strength = old_strength + levels;
- if (new_strength > 3)
- new_strength = 3;
-
- // now, if player poisons the monster at ANY TIME, they should
- // get credit for the kill if the monster dies from poison. This
- // really isn't that abusable -- GDL.
- if (fromPlayer || yourPoison)
- ench = ENCH_YOUR_POISON_I + new_strength;
- else
- ench = ENCH_POISON_I + new_strength;
+ const mon_enchant old_pois = monster->get_ench(ENCH_POISON);
+ monster->add_ench( mon_enchant(ENCH_POISON, levels, from_whom) );
+ const mon_enchant new_pois = monster->get_ench(ENCH_POISON);
// actually do the poisoning
// note: order important here
- if (mons_add_ench( monster, ench ) && new_strength > old_strength)
+ if (new_pois.degree > old_pois.degree)
{
simple_monster_message( monster,
- (old_strength == 0) ? " looks ill."
- : " looks even sicker." );
+ !old_pois.degree? " looks ill."
+ : " looks even sicker." );
}
// finally, take care of deity preferences
- if (fromPlayer)
+ if (from_whom == KC_YOU)
did_god_conduct( DID_POISON, 5 + random2(3) );
} // end poison_monster()
// actually napalms a monster (w/ message)
-void sticky_flame_monster( int mn, bool fromPlayer, int levels )
+void sticky_flame_monster( int mn, kill_category who, int levels )
{
- bool yourFlame = fromPlayer;
- int currentFlame;
- int currentStrength = 0;
+ monsters *monster = &menv[mn];
- struct monsters *monster = &menv[mn];
-
- if (monster->type == -1)
+ if (!monster->alive())
return;
if (mons_res_fire(monster) > 0)
return;
- // who gets the credit if monster dies of napalm?
- currentFlame = mons_has_ench( monster, ENCH_STICKY_FLAME_I,
- ENCH_STICKY_FLAME_IV );
-
- if (currentFlame != ENCH_NONE)
- {
- currentStrength = currentFlame - ENCH_STICKY_FLAME_I;
- yourFlame = false;
- }
- else
- {
- currentFlame = mons_has_ench( monster, ENCH_YOUR_STICKY_FLAME_I,
- ENCH_YOUR_STICKY_FLAME_IV );
-
- if (currentFlame != ENCH_NONE)
- {
- currentStrength = currentFlame - ENCH_YOUR_STICKY_FLAME_I;
- yourFlame = true;
- }
- else
- currentStrength = -1; // no flame yet!
- }
-
- // delete old flame
- mons_del_ench( monster, ENCH_STICKY_FLAME_I, ENCH_STICKY_FLAME_IV, true );
- mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I, ENCH_YOUR_STICKY_FLAME_IV,
- true );
-
- // increase sticky flame strength, cap at 3 (level is 0..3)
- currentStrength += levels;
-
- if (currentStrength > 3)
- currentStrength = 3;
-
- // now, if player flames the monster at ANY TIME, they should
- // get credit for the kill if the monster dies from napalm. This
- // really isn't that abusable -- GDL.
- if (fromPlayer || yourFlame)
- currentStrength += ENCH_YOUR_STICKY_FLAME_I;
- else
- currentStrength += ENCH_STICKY_FLAME_I;
-
- // actually do flame
- if (mons_add_ench( monster, currentStrength ))
+ if (monster->add_ench(mon_enchant(ENCH_STICKY_FLAME, levels, who)))
simple_monster_message(monster, " is covered in liquid fire!");
-
} // end sticky_flame_monster
/*
@@ -2229,7 +2166,7 @@ bool check_line_of_sight( int sx, int sy, int tx, int ty )
*/
void mimic_alert(monsters *mimic)
{
- if (mons_has_ench( mimic, ENCH_TP_I, ENCH_TP_IV ))
+ if (mimic->has_ench(ENCH_TP))
return;
monster_teleport( mimic, !one_chance_in(3) );
@@ -2492,7 +2429,7 @@ int affect(struct bolt &beam, int x, int y)
// if there is a monster at this location, affect it
// submerged monsters aren't really there -- bwr
int mid = mgrd[x][y];
- if (mid != NON_MONSTER && !mons_has_ench( &menv[mid], ENCH_SUBMERGED ))
+ if (mid != NON_MONSTER && !menv[mid].has_ench( ENCH_SUBMERGED ))
{
if (!beam.is_big_cloud
&& (!beam.is_explosion || beam.in_explosion_phase))
@@ -3381,7 +3318,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon)
if (beam.is_tracer)
{
// check can see other monster
- if (!beam.can_see_invis && mons_has_ench(&menv[tid], ENCH_INVIS))
+ if (!beam.can_see_invis && menv[tid].has_ench(ENCH_INVIS))
{
// can't see this monster, ignore it
return 0;
@@ -3482,7 +3419,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon)
// BEGIN non-enchantment (could still be tracer)
- if (mons_has_ench( mon, ENCH_SUBMERGED ) && !beam.aimed_at_feet)
+ if (mon->has_ench(ENCH_SUBMERGED) && !beam.aimed_at_feet)
return (0); // missed me!
// we need to know how much the monster _would_ be hurt by this, before
@@ -3638,7 +3575,7 @@ static int affect_monster(struct bolt &beam, struct monsters *mon)
if (levels > 4)
levels = 4;
- sticky_flame_monster( tid, YOU_KILL(beam.thrower), levels );
+ sticky_flame_monster( tid, whose_kill(beam), levels );
}
@@ -3652,18 +3589,18 @@ static int affect_monster(struct bolt &beam, struct monsters *mon)
if (beam.ench_power == AUTOMATIC_HIT
&& random2(100) < 90 - (3 * mon->ac))
{
- poison_monster( mon, YOU_KILL(beam.thrower), 2 );
+ poison_monster( mon, whose_kill(beam), 2 );
}
else if (random2(hurt_final) - random2(mon->ac) > 0)
{
- poison_monster( mon, YOU_KILL(beam.thrower) );
+ poison_monster( mon, whose_kill(beam) );
}
}
bool wake_mimic = true;
if (beam.name.find("curare") != std::string::npos)
{
- if (curare_hits_monster( beam, mon, YOU_KILL(beam.thrower), 2 ))
+ if (curare_hits_monster( beam, mon, whose_kill(beam), 2 ))
wake_mimic = false;
}
@@ -3863,7 +3800,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon)
if (beam.flavour == BEAM_SLEEP)
{
- if (mons_has_ench( mon, ENCH_SLEEP_WARY )) // slept recently
+ if (mon->has_ench(ENCH_SLEEP_WARY)) // slept recently
return (MON_RESIST);
if (mons_holiness(mon) != MH_NATURAL) // no unnatural
@@ -3873,7 +3810,7 @@ static int affect_monster_enchantment(struct bolt &beam, struct monsters *mon)
beam.obvious_effect = true;
mon->behaviour = BEH_SLEEP;
- mons_add_ench( mon, ENCH_SLEEP_WARY );
+ mon->add_ench(ENCH_SLEEP_WARY);
return (MON_AFFECTED);
}
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index f95477fb29..87930575de 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -66,8 +66,8 @@ int mons_ench_f2( struct monsters *monster, struct bolt &pbolt );
/* ***********************************************************************
* called from: fight - monstuff - spells2
* *********************************************************************** */
-void poison_monster( struct monsters *monster, bool fromPlayer, int levels = 1,
- bool force = false );
+void poison_monster( struct monsters *monster, kill_category who,
+ int levels = 1, bool force = false );
/* ***********************************************************************
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 80da858529..34e4f13530 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -878,34 +878,11 @@ void tweak_object(void)
//---------------------------------------------------------------
#if DEBUG_DIAGNOSTICS
-static const char *enchant_names[] =
-{
- "None",
- "Slow", "Haste", "*BUG-3*", "Fear", "Conf", "Invis",
- "YPois-1", "YPois-2", "YPois-3", "YPois-4",
- "YShug-1", "YShug-2", "YShug-3", "YShug-4",
- "YRot-1", "YRot-2", "YRot-3", "YRot-4",
- "Summon", "Abj-1", "Abj-2", "Abj-3", "Abj-4", "Abj-5", "Abj-6",
- "Corona-1", "Corona-2", "Corona-3", "Corona-4",
- "Charm", "YSticky-1", "YSticky-2", "YSticky-3", "YSticky-4",
- "*BUG-35*", "*BUG-36*", "*BUG-37*",
- "GlowShapeshifter", "Shapeshifter",
- "Tele-1", "Tele-2", "Tele-3", "Tele-4",
- "*BUG-44*", "*BUG-45*", "*BUG-46*", "*BUG-47*", "*BUG-48*", "*BUG-49*",
- "*BUG-50*", "*BUG-51*", "*BUG-52*", "*BUG-53*", "*BUG-54*", "*BUG-55*",
- "*BUG-56*",
- "Pois-1", "Pois-2", "Pois-3", "Pois-4",
- "Sticky-1", "Sticky-2", "Sticky-3", "Sticky-4",
- "OldAbj-1", "OldAbj-2", "OldAbj-3", "OldAbj-4", "OldAbj-5", "OldAbj-6",
- "OldCreatedFriendly", "SleepWary", "Submerged", "Short Lived",
- "*BUG-too big*"
-};
-
void stethoscope(int mwh)
{
struct dist stth;
int steth_x, steth_y;
- int i, j;
+ int i;
if (mwh != RANDOM_MONSTER)
i = mwh;
@@ -1012,25 +989,10 @@ void stethoscope(int mwh)
mpr( info, MSGCH_DIAGNOSTICS );
- // print enchantments
- strncpy( info, "ench: ", INFO_SIZE );
- for (j = 0; j < 6; j++)
- {
- if (menv[i].enchantment[j] >= NUM_ENCHANTMENTS)
- strncat( info, enchant_names[ NUM_ENCHANTMENTS ], INFO_SIZE );
- else
- strncat( info, enchant_names[ menv[i].enchantment[j] ], INFO_SIZE );
-
- if (strlen( info ) <= 70)
- strncat( info, " ", INFO_SIZE );
- else if (j < 5)
- {
- mpr( info, MSGCH_DIAGNOSTICS );
- strncpy( info, "ench: ", INFO_SIZE );
- }
- }
-
- mpr( info, MSGCH_DIAGNOSTICS );
+ mprf(MSGCH_DIAGNOSTICS, "ench: %s",
+ comma_separated_line(menv[i].enchantments.begin(),
+ menv[i].enchantments.end(),
+ ", ").c_str());
if (menv[i].type == MONS_PLAYER_GHOST
|| menv[i].type == MONS_PANDEMONIUM_DEMON)
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index a76835a0f4..deb8b1629c 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -323,9 +323,9 @@ static void cards(unsigned char which_card)
case CARD_BUTTERFLY:
mpr("You have drawn the Butterfly.");
- summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 2;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
+ summ_dur = 1 + random2(3) + you.skills[SK_EVOCATIONS] / 2;
+ if (summ_dur > 6)
+ summ_dur = 6;
if (create_monster( MONS_BUTTERFLY, summ_dur, BEH_FRIENDLY,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
@@ -545,9 +545,7 @@ static void cards(unsigned char which_card)
case CARD_DEMON_LESSER:
mpr("On the card is a picture of a little demon.");
- summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 3;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
+ summ_dur = cap_int(1 + random2(3) + you.skills[SK_EVOCATIONS] / 3, 6);
if (create_monster( summon_any_demon( DEMON_LESSER ), summ_dur,
BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target,
@@ -560,9 +558,7 @@ static void cards(unsigned char which_card)
case CARD_DEMON_COMMON:
mpr("On the card is a picture of a demon.");
- summ_dur = ENCH_ABJ_I + random2(3) + you.skills[SK_EVOCATIONS] / 4;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
+ summ_dur = cap_int(1 + random2(3) + you.skills[SK_EVOCATIONS] / 4, 6);
if (create_monster( summon_any_demon( DEMON_COMMON ), summ_dur,
BEH_FRIENDLY, you.x_pos, you.y_pos, you.pet_target,
@@ -581,7 +577,7 @@ static void cards(unsigned char which_card)
if (summ_beh == BEH_CHARMED)
mpr( "You don't feel so good about this..." );
- if (create_monster( summon_any_demon( DEMON_GREATER ), ENCH_ABJ_V,
+ if (create_monster( summon_any_demon( DEMON_GREATER ), 5,
summ_beh, you.x_pos, you.y_pos,
you.pet_target, 250 ) != -1)
{
@@ -598,7 +594,7 @@ static void cards(unsigned char which_card)
for (loopy = 0; loopy < summ_num; loopy++)
{
- if (create_monster( summon_any_demon( DEMON_LESSER ), ENCH_ABJ_VI,
+ if (create_monster( summon_any_demon( DEMON_LESSER ), 6,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 ) != -1)
{
@@ -613,10 +609,7 @@ static void cards(unsigned char which_card)
case CARD_YAK:
mpr("On the card is a picture of a huge shaggy yak.");
- summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 2;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 2, 6);
if (create_monster( MONS_DEATH_YAK, summ_dur, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
@@ -627,10 +620,7 @@ static void cards(unsigned char which_card)
case CARD_FIEND:
mpr("On the card is a picture of a huge scaly devil.");
- summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 6;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 6, 6);
if (create_monster( MONS_FIEND, summ_dur, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
@@ -641,10 +631,7 @@ static void cards(unsigned char which_card)
case CARD_DRAGON:
mpr("On the card is a picture of a huge scaly dragon.");
- summ_dur = ENCH_ABJ_III + you.skills[SK_EVOCATIONS] / 6;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(3 + you.skills[SK_EVOCATIONS] / 6, 6);
if (create_monster( (coinflip() ? MONS_DRAGON : MONS_ICE_DRAGON),
summ_dur, BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 ) != -1)
@@ -656,10 +643,7 @@ static void cards(unsigned char which_card)
case CARD_GOLEM:
mpr("On the card is a picture of a statue.");
- summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6);
if (create_monster( MONS_CLAY_GOLEM + random2(6), summ_dur,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 ) != -1)
@@ -671,10 +655,7 @@ static void cards(unsigned char which_card)
case CARD_THING_FUGLY:
mpr("On the card is a picture of a very ugly thing.");
- summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6);
if (create_monster( MONS_VERY_UGLY_THING, summ_dur, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
@@ -699,10 +680,7 @@ static void cards(unsigned char which_card)
else
mpr("On the card is a picture of a hideous abomination.");
- summ_dur = ENCH_ABJ_II + you.skills[SK_EVOCATIONS] / 4;
- if (summ_dur > ENCH_ABJ_VI)
- summ_dur = ENCH_ABJ_VI;
-
+ summ_dur = cap_int(2 + you.skills[SK_EVOCATIONS] / 4, 6);
if (create_monster( MONS_UNSEEN_HORROR, summ_dur, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h
index 9f1a642503..2a9c8d5aca 100644
--- a/crawl-ref/source/defines.h
+++ b/crawl-ref/source/defines.h
@@ -140,6 +140,9 @@
// lowest grid value which can be seen through
#define MINSEE 11
+// Can be passed to monster_die to indicate that a friendly did the killing.
+#define ANON_FRIENDLY_MONSTER -1
+
// This value is used to make test_hit checks always succeed
#define AUTOMATIC_HIT 1500
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index fe451caea1..bff0ca3e99 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -6072,7 +6072,7 @@ void describe_monsters(int class_described, unsigned char which_mons)
break;
case MONS_PSYCHE:
- description += "A fair-haired magess.";
+ description += "A fair-haired mage.";
break;
case MONS_DONALD:
@@ -6160,7 +6160,7 @@ void describe_monsters(int class_described, unsigned char which_mons)
break;
case MONS_EROLCHA:
- description += "An especially cunning ogre magess.";
+ description += "An especially cunning ogre mage.";
break;
case MONS_URUG:
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 299260289b..6cbc6a4120 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -1382,6 +1382,54 @@ std::string feature_description(int mx, int my)
return (desc);
}
+static void describe_mons_enchantment(const monsters &mons,
+ const mon_enchant &ench,
+ bool paralysed)
+{
+ // Suppress silly-looking combinations, even if they're
+ // internally valid.
+ if (paralysed && (ench.ench == ENCH_SLOW || ench.ench == ENCH_HASTE))
+ return;
+
+ strcpy(info, mons_pronoun(mons.type, PRONOUN_CAP));
+
+ switch (ench.ench)
+ {
+ case ENCH_POISON:
+ strcat(info, " is poisoned.");
+ break;
+ case ENCH_ROT:
+ strcat(info, " is rotting away."); //jmf: "covered in sores"?
+ break;
+ case ENCH_BACKLIGHT:
+ strcat(info, " is softly glowing.");
+ break;
+ case ENCH_SLOW:
+ strcat(info, " is moving slowly.");
+ break;
+ case ENCH_HASTE:
+ strcat(info, " is moving very quickly.");
+ break;
+ case ENCH_CONFUSION:
+ strcat(info, " appears to be bewildered and confused.");
+ break;
+ case ENCH_INVIS:
+ strcat(info, " is slightly transparent.");
+ break;
+ case ENCH_CHARM:
+ strcat(info, " is in your thrall.");
+ break;
+ case ENCH_STICKY_FLAME:
+ strcat(info, " is covered in liquid flames.");
+ break;
+ default:
+ info[0] = 0;
+ break;
+ } // end switch
+ if (info[0])
+ mpr(info);
+}
+
static void describe_cell(int mx, int my)
{
char str_pass[ ITEMNAME_SIZE ];
@@ -1484,62 +1532,10 @@ static void describe_cell(int mx, int my)
if (paralysed)
mprf("%s is paralysed.", mons_pronoun(menv[i].type, PRONOUN_CAP));
- for (int p = 0; p < NUM_MON_ENCHANTS; p++)
+ for (mon_enchant_list::const_iterator e = menv[i].enchantments.begin();
+ e != menv[i].enchantments.end(); ++e)
{
- const unsigned ench = menv[i].enchantment[p];
-
- // Suppress silly-looking combinations, even if they're
- // internally valid.
- if (paralysed && (ench == ENCH_SLOW || ench == ENCH_HASTE))
- continue;
-
- strcpy(info, mons_pronoun(menv[i].type, PRONOUN_CAP));
-
- switch (ench)
- {
- case ENCH_YOUR_ROT_I:
- case ENCH_YOUR_ROT_II:
- case ENCH_YOUR_ROT_III:
- case ENCH_YOUR_ROT_IV:
- strcat(info, " is rotting away."); //jmf: "covered in sores"?
- break;
- case ENCH_BACKLIGHT_I:
- case ENCH_BACKLIGHT_II:
- case ENCH_BACKLIGHT_III:
- case ENCH_BACKLIGHT_IV:
- strcat(info, " is softly glowing.");
- break;
- case ENCH_SLOW:
- strcat(info, " is moving slowly.");
- break;
- case ENCH_HASTE:
- strcat(info, " is moving very quickly.");
- break;
- case ENCH_CONFUSION:
- strcat(info, " appears to be bewildered and confused.");
- break;
- case ENCH_INVIS:
- strcat(info, " is slightly transparent.");
- break;
- case ENCH_CHARM:
- strcat(info, " is in your thrall.");
- break;
- case ENCH_YOUR_STICKY_FLAME_I:
- case ENCH_YOUR_STICKY_FLAME_II:
- case ENCH_YOUR_STICKY_FLAME_III:
- case ENCH_YOUR_STICKY_FLAME_IV:
- case ENCH_STICKY_FLAME_I:
- case ENCH_STICKY_FLAME_II:
- case ENCH_STICKY_FLAME_III:
- case ENCH_STICKY_FLAME_IV:
- strcat(info, " is covered in liquid flames.");
- break;
- default:
- info[0] = 0;
- break;
- } // end switch
- if (info[0])
- mpr(info);
+ describe_mons_enchantment(menv[i], *e, paralysed);
}
#if DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index d85a07b8ef..38c65184d6 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1174,64 +1174,25 @@ enum enchant_type
{
ENCH_NONE = 0, // 0
ENCH_SLOW,
- ENCH_HASTE, // 2
- ENCH_FEAR = 4, // 4
- ENCH_CONFUSION, // 5
- ENCH_INVIS,
- ENCH_YOUR_POISON_I,
- ENCH_YOUR_POISON_II,
- ENCH_YOUR_POISON_III,
- ENCH_YOUR_POISON_IV, // 10
- ENCH_BERSERK_I,
- ENCH_BERSERK_II,
- ENCH_BERSERK_III,
- ENCH_BERSERK_IV,
- ENCH_YOUR_ROT_I, // 15 //jmf: rotting effect for monsters
- ENCH_YOUR_ROT_II,
- ENCH_YOUR_ROT_III,
- ENCH_YOUR_ROT_IV,
- ENCH_SUMMON = 19, // 19
- ENCH_ABJ_I, // 20
- ENCH_ABJ_II,
- ENCH_ABJ_III,
- ENCH_ABJ_IV,
- ENCH_ABJ_V,
- ENCH_ABJ_VI, // 25
- ENCH_BACKLIGHT_I, //jmf: backlight for Corona spell
- ENCH_BACKLIGHT_II,
- ENCH_BACKLIGHT_III,
- ENCH_BACKLIGHT_IV,
- ENCH_CHARM = 30, // 30
- ENCH_YOUR_STICKY_FLAME_I,
- ENCH_YOUR_STICKY_FLAME_II,
- ENCH_YOUR_STICKY_FLAME_III,
- ENCH_YOUR_STICKY_FLAME_IV, // 34
- ENCH_GLOWING_SHAPESHIFTER = 38, // 38
- ENCH_SHAPESHIFTER,
- ENCH_TP_I, // 40
- ENCH_TP_II,
- ENCH_TP_III,
- ENCH_TP_IV, // 43
- ENCH_POISON_I = 57, // 57
- ENCH_POISON_II,
- ENCH_POISON_III,
- ENCH_POISON_IV, // 60
- ENCH_STICKY_FLAME_I,
- ENCH_STICKY_FLAME_II,
- ENCH_STICKY_FLAME_III,
- ENCH_STICKY_FLAME_IV,
- ENCH_FRIEND_ABJ_I, // no longer used
- ENCH_FRIEND_ABJ_II, // no longer used
- ENCH_FRIEND_ABJ_III, // no longer used
- ENCH_FRIEND_ABJ_IV, // no longer used
- ENCH_FRIEND_ABJ_V, // no longer used
- ENCH_FRIEND_ABJ_VI, // no longer used
- ENCH_CREATED_FRIENDLY, // no longer used
+ ENCH_HASTE,
+ ENCH_FEAR,
+ ENCH_CONFUSION,
+ ENCH_INVIS, // 5
+ ENCH_POISON,
+ ENCH_BERSERK,
+ ENCH_ROT,
+ ENCH_SUMMON,
+ ENCH_ABJ, // 10
+ ENCH_BACKLIGHT,
+ ENCH_CHARM,
+ ENCH_STICKY_FLAME,
+ ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER, // 15
+ ENCH_TP,
ENCH_SLEEP_WARY,
- ENCH_SUBMERGED, // 73 (includes air elementals in air)
- ENCH_SHORT_LIVED, // 74 for ball lightning
-
- ENCH_PARALYSIS,
+ ENCH_SUBMERGED,
+ ENCH_SHORT_LIVED,
+ ENCH_PARALYSIS, // 20
NUM_ENCHANTMENTS
};
@@ -1652,6 +1613,7 @@ enum kill_method_type
NUM_KILLBY
};
+// This order is *critical*. Don't mess with it (see mon_enchant)
enum kill_category
{
KC_YOU,
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 9793c5cc34..0b50040f56 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -20,6 +20,7 @@
#include <list>
#include <string>
#include <map>
+#include <set>
#include <memory>
#include <time.h>
@@ -108,6 +109,7 @@ public:
virtual int id() const = 0;
virtual actor_type atype() const = 0;
+ virtual kill_category kill_alignment() const = 0;
virtual god_type deity() const = 0;
virtual bool alive() const = 0;
@@ -704,6 +706,8 @@ public:
bool is_levitating() const;
bool cannot_speak() const;
+ kill_category kill_alignment() const;
+
bool has_spell(int spell) const;
size_type transform_size(int psize = PSIZE_TORSO) const;
@@ -821,15 +825,40 @@ class level_id;
struct mon_enchant
{
enchant_type ench;
- kill_category who; // Who set this enchantment?
int degree;
+ kill_category who; // Who set this enchantment?
+
+ mon_enchant(enchant_type e = ENCH_NONE, int deg = 0,
+ kill_category whose = KC_OTHER)
+ : ench(e), degree(deg), who(whose)
+ {
+ }
+
+ int killer() const;
+ int kill_agent() const;
+
+ operator std::string () const;
+ const char *kill_category_desc(kill_category) const;
+ void merge_killer(kill_category who);
+ void cap_degree();
- mon_enchant(enchant_type e, int deg = 1, kill_category whose = KC_OTHER)
- : ench(e), who(whose), degree(deg)
+ bool operator < (const mon_enchant &other) const
{
+ return (ench < other.ench);
}
+
+ bool operator == (const mon_enchant &other) const
+ {
+ // NOTE: This does *not* check who/degree.
+ return (ench == other.ench);
+ }
+
+ mon_enchant &operator += (const mon_enchant &other);
+ mon_enchant operator + (const mon_enchant &other) const;
};
+typedef std::set<mon_enchant> mon_enchant_list;
+
class monsters : public actor
{
public:
@@ -856,7 +885,7 @@ public:
unsigned char attitude; // from MONS_ATTITUDE
unsigned int behaviour;
unsigned int foe;
- FixedVector<unsigned int, NUM_MON_ENCHANTS> enchantment;
+ mon_enchant_list enchantments;
unsigned long flags; // bitfield of boolean flags
unsigned int number; // #heads (hydra), etc.
@@ -870,6 +899,23 @@ public:
std::auto_ptr<ghost_demon> ghost; // Ghost information.
public:
+ kill_category kill_alignment() const;
+
+ bool has_ench(enchant_type ench,
+ enchant_type ench2 = ENCH_NONE) const;
+ mon_enchant get_ench(enchant_type ench,
+ enchant_type ench2 = ENCH_NONE) const;
+ bool add_ench(const mon_enchant &);
+ void update_ench(const mon_enchant &);
+ bool del_ench(enchant_type ench, bool quiet = false);
+
+ void lose_ench_levels(const mon_enchant &e, int levels);
+ void remove_enchantment_effect(const mon_enchant &me, bool quiet = false);
+ void apply_enchantments(int speed);
+ void apply_enchantment(mon_enchant me, int speed);
+
+ void timeout_enchantments(int levels);
+
bool needs_transit() const;
void set_transit(level_id destination);
bool find_place_to_live(bool near_player = false);
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 14257e3861..201bc02a90 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -823,7 +823,7 @@ bool melee_attack::player_apply_aux_unarmed()
attack_strength_punctuation().c_str());
if (damage_brand == SPWPN_VENOM && coinflip())
- poison_monster( def, true );
+ poison_monster( def, KC_YOU );
if (mons_holiness(def) == MH_HOLY)
did_god_conduct(DID_KILL_ANGEL, 1);
@@ -1870,7 +1870,7 @@ void melee_attack::player_apply_staff_damage()
{
// Poison monster message needs to arrive after hit message.
emit_nodmg_hit_message();
- poison_monster(def, true);
+ poison_monster(def, KC_YOU);
}
break;
}
@@ -2120,7 +2120,7 @@ int melee_attack::player_to_hit(bool random_factor)
// Check for backlight (Corona).
if (defender
&& defender->atype() == ACT_MONSTER
- && mons_has_ench(def, ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV))
+ && def->has_ench(ENCH_BACKLIGHT))
{
your_to_hit += 2 + random2(8);
}
@@ -2141,7 +2141,7 @@ void melee_attack::player_stab_check()
}
// confused (but not perma-confused)
- if (mons_has_ench(def, ENCH_CONFUSION)
+ if (def->has_ench(ENCH_CONFUSION)
&& !mons_class_flag(def->type, M_CONFUSED))
{
stab_attempt = true;
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index a7b96a93ca..7ae760b26f 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -189,7 +189,7 @@ void special_wielded(void)
if (random2(8) <= player_spec_death())
{
did_god_conduct( DID_NECROMANCY, 1 );
- create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_FRIENDLY,
+ create_monster( MONS_SHADOW, 2, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 );
}
@@ -404,7 +404,7 @@ bool evoke_wielded( void )
: MONS_HELLION + random2(10));
bool good_summon = (create_monster( spell_casted,
- ENCH_ABJ_VI, BEH_HOSTILE,
+ 6, BEH_HOSTILE,
you.x_pos, you.y_pos,
MHITYOU, 250) != -1);
@@ -630,7 +630,7 @@ bool evoke_wielded( void )
else
{
mpr("You produce a hideous howling noise!");
- int midx = create_monster( MONS_BEAST, ENCH_ABJ_IV,
+ int midx = create_monster( MONS_BEAST, 4,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
// avoid scumming; also prevents it from showing up on notes
@@ -725,7 +725,7 @@ static bool efreet_flask(void)
mpr("You open the flask...");
- const int efreet = create_monster( MONS_EFREET, ENCH_ABJ_V, behaviour,
+ const int efreet = create_monster( MONS_EFREET, 5, behaviour,
you.x_pos, you.y_pos, MHITYOU, 250,
false, false, true );
if (efreet != -1)
@@ -923,7 +923,7 @@ void tome_of_power(char sc_read_2)
case 10:
- if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_HOSTILE,
+ if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
mpr("A horrible Thing appears!");
@@ -1023,7 +1023,7 @@ static bool box_of_beasts(void)
int beh = (one_chance_in(you.skills[SK_EVOCATIONS] + 5) ? BEH_HOSTILE
: BEH_FRIENDLY);
- if (create_monster( beasty, ENCH_ABJ_II + random2(4), beh,
+ if (create_monster( beasty, 2 + random2(4), beh,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
mpr("...and something leaps out!");
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 3e7d167c8a..c26b4ea707 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -3343,7 +3343,7 @@ void read_scroll(void)
break;
case SCR_SUMMONING:
- if (create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_VI, BEH_FRIENDLY,
+ if (create_monster( MONS_ABOMINATION_SMALL, 6, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
mpr("A horrible Thing appears!");
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 98be971353..734bec9fd6 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -2079,155 +2079,6 @@ void update_corpses(double elapsedTime)
}
}
-static bool remove_enchant_levels( struct monsters *mon, int slot, int min,
- int levels )
-{
- const int new_level = mon->enchantment[slot] - levels;
-
- if (new_level < min)
- {
- mons_del_ench( mon,
- mon->enchantment[slot], mon->enchantment[slot], true );
- return (true);
- }
- else
- {
- mon->enchantment[slot] = new_level;
- }
-
- return (false);
-}
-
-//---------------------------------------------------------------
-//
-// update_enchantments
-//
-// Update a monster's enchantments when the player returns
-// to the level.
-//
-// Management for enchantments... problems with this are the oddities
-// (monster dying from poison several thousands of turns later), and
-// game balance.
-//
-// Consider: Poison/Sticky Flame a monster at range and leave, monster
-// dies but can't leave level to get to player (implied game balance of
-// the delayed damage is that the monster could be a danger before
-// it dies). This could be fixed by keeping some monsters active
-// off level and allowing them to take stairs (a very serious change).
-//
-// Compare this to the current abuse where the player gets
-// effectively extended duration of these effects (although only
-// the actual effects only occur on level, the player can leave
-// and heal up without having the effect disappear).
-//
-// This is a simple compromise between the two... the enchantments
-// go away, but the effects don't happen off level. -- bwr
-//
-//---------------------------------------------------------------
-static void update_enchantments( struct monsters *mon, int levels )
-{
- int i;
-
- for (i = 0; i < NUM_MON_ENCHANTS; i++)
- {
- switch (mon->enchantment[i])
- {
- case ENCH_YOUR_POISON_I:
- case ENCH_YOUR_POISON_II:
- case ENCH_YOUR_POISON_III:
- case ENCH_YOUR_POISON_IV:
- remove_enchant_levels( mon, i, ENCH_YOUR_POISON_I, levels );
- break;
-
- case ENCH_YOUR_ROT_I:
- case ENCH_YOUR_ROT_II:
- case ENCH_YOUR_ROT_III:
- case ENCH_YOUR_ROT_IV:
- remove_enchant_levels( mon, i, ENCH_YOUR_ROT_I, levels );
- break;
-
- case ENCH_BACKLIGHT_I:
- case ENCH_BACKLIGHT_II:
- case ENCH_BACKLIGHT_III:
- case ENCH_BACKLIGHT_IV:
- remove_enchant_levels( mon, i, ENCH_BACKLIGHT_I, levels );
- break;
-
- case ENCH_YOUR_STICKY_FLAME_I:
- case ENCH_YOUR_STICKY_FLAME_II:
- case ENCH_YOUR_STICKY_FLAME_III:
- case ENCH_YOUR_STICKY_FLAME_IV:
- remove_enchant_levels( mon, i, ENCH_YOUR_STICKY_FLAME_I, levels );
- break;
-
- case ENCH_POISON_I:
- case ENCH_POISON_II:
- case ENCH_POISON_III:
- case ENCH_POISON_IV:
- remove_enchant_levels( mon, i, ENCH_POISON_I, levels );
- break;
-
- case ENCH_STICKY_FLAME_I:
- case ENCH_STICKY_FLAME_II:
- case ENCH_STICKY_FLAME_III:
- case ENCH_STICKY_FLAME_IV:
- remove_enchant_levels( mon, i, ENCH_STICKY_FLAME_I, levels );
- break;
-
- case ENCH_ABJ_I:
- case ENCH_ABJ_II:
- case ENCH_ABJ_III:
- case ENCH_ABJ_IV:
- case ENCH_ABJ_V:
- case ENCH_ABJ_VI:
- if (remove_enchant_levels( mon, i, ENCH_ABJ_I, levels ))
- {
- // Re-add ABJ_I so that monster_die doesn't try to send the
- // monster to the Abyss on KILL_RESET.
- mons_add_ench( mon, ENCH_ABJ_I );
- monster_die( mon, KILL_RESET, 0 );
- }
- break;
-
-
- case ENCH_SHORT_LIVED:
- mons_add_ench( mon, ENCH_ABJ_I );
- monster_die( mon, KILL_RESET, 0 );
- break;
-
- case ENCH_TP_I:
- case ENCH_TP_II:
- case ENCH_TP_III:
- case ENCH_TP_IV:
- monster_teleport( mon, true );
- break;
-
- case ENCH_CONFUSION:
- monster_blink( mon );
- break;
-
- case ENCH_GLOWING_SHAPESHIFTER:
- case ENCH_SHAPESHIFTER:
- case ENCH_CREATED_FRIENDLY:
- case ENCH_SUBMERGED:
- default:
- // don't touch these
- break;
-
- case ENCH_SLOW:
- case ENCH_HASTE:
- case ENCH_FEAR:
- case ENCH_INVIS:
- case ENCH_CHARM:
- case ENCH_SLEEP_WARY:
- // delete enchantment (using function to get this done cleanly)
- mons_del_ench(mon, mon->enchantment[i], mon->enchantment[i], true);
- break;
- }
- }
-}
-
-
//---------------------------------------------------------------
//
// update_level
@@ -2279,7 +2130,7 @@ void update_level( double elapsedTime )
}
if (turns >= 10)
- update_enchantments( mon, turns / 10 );
+ mon->timeout_enchantments( turns / 10 );
// Don't move water, lava, or stationary monsters around
if (monster_habitat( mon->type ) != DNGN_FLOOR
diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h
index 6baf428aa0..4e5db549b3 100644
--- a/crawl-ref/source/libutil.h
+++ b/crawl-ref/source/libutil.h
@@ -100,7 +100,8 @@ std::string comma_separated_line(Z start, Z end,
{
if (i != start)
{
- if (i + 1 != end)
+ Z tmp = i;
+ if (++tmp != end)
text += comma;
else
text += andc;
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 9b61ec053c..a7a7a35de6 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -516,8 +516,8 @@ char mons_see_invis( struct monsters *mon )
// with respect to mon's perception, but doesn't do walls or range.
bool mons_monster_visible( struct monsters *mon, struct monsters *targ )
{
- if (mons_has_ench(targ, ENCH_SUBMERGED)
- || (mons_has_ench(targ, ENCH_INVIS) && !mons_see_invis(mon)))
+ if (targ->has_ench(ENCH_SUBMERGED)
+ || (targ->has_ench(ENCH_INVIS) && !mons_see_invis(mon)))
{
return (false);
}
@@ -952,7 +952,7 @@ bool mons_has_lifeforce( const monsters *mon )
const int holy = mons_holiness( mon );
return (holy == MH_NATURAL || holy == MH_PLANT);
- // && !mons_has_ench( mon, ENCH_PETRIFY ));
+ // && !mon->has_ench(ENCH_PETRIFY));
}
int mons_skeleton(int mc)
@@ -1382,8 +1382,7 @@ void define_monster(int index)
mons_load_spells( &mons, spells );
// reset monster enchantments
- for (int i = 0; i < NUM_MON_ENCHANTS; i++)
- mons.enchantment[i] = ENCH_NONE;
+ mons.enchantments.clear();
} // end define_monster()
std::string str_monam(const monsters *mon, description_level_type desc,
@@ -1695,7 +1694,7 @@ bool mons_aligned(int m1, int m2)
else
{
mon1 = &menv[m1];
- fr1 = (mon1->attitude == ATT_FRIENDLY) || mons_has_ench(mon1, ENCH_CHARM);
+ fr1 = (mon1->attitude == ATT_FRIENDLY) || mon1->has_ench(ENCH_CHARM);
}
if (m2 == MHITYOU)
@@ -1703,7 +1702,7 @@ bool mons_aligned(int m1, int m2)
else
{
mon2 = &menv[m2];
- fr2 = (mon2->attitude == ATT_FRIENDLY) || mons_has_ench(mon2, ENCH_CHARM);
+ fr2 = (mon2->attitude == ATT_FRIENDLY) || mon2->has_ench(ENCH_CHARM);
}
return (fr1 == fr2);
@@ -1716,7 +1715,7 @@ bool mons_wields_two_weapons(const monsters *m)
bool mons_is_summoned(const monsters *m)
{
- return (mons_has_ench(m, ENCH_ABJ_I, ENCH_ABJ_VI));
+ return (m->has_ench(ENCH_ABJ));
}
// Does not check whether the monster can dual-wield - that is the
@@ -1741,23 +1740,23 @@ int mons_size(const monsters *m)
bool mons_friendly(const monsters *m)
{
- return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM));
+ return (m->attitude == ATT_FRIENDLY || m->has_ench(ENCH_CHARM));
}
bool mons_is_submerged( const monsters *mon )
{
// FIXME, switch to 4.1's MF_SUBMERGED system which is much cleaner.
- return (mons_has_ench(mon, ENCH_SUBMERGED));
+ return (mon->has_ench(ENCH_SUBMERGED));
}
bool mons_is_paralysed(const monsters *m)
{
- return (mons_has_ench(m, ENCH_PARALYSIS));
+ return (m->has_ench(ENCH_PARALYSIS));
}
bool mons_is_confused(const monsters *m)
{
- return (mons_has_ench(m, ENCH_CONFUSION) &&
+ return (m->has_ench(ENCH_CONFUSION) &&
!mons_class_flag(m->type, M_CONFUSED));
}
@@ -1836,194 +1835,6 @@ bool mons_should_fire(struct bolt &beam)
return (false);
}
-int mons_has_ench(const monsters *mon, unsigned int ench, unsigned int ench2)
-{
- // silliness
- if (ench == ENCH_NONE)
- return (ench);
-
- if (ench2 == ENCH_NONE)
- ench2 = ench;
-
- for (int p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
- return (mon->enchantment[p]);
- }
-
- return (ENCH_NONE);
-}
-
-// Returning the deleted enchantment is important! See abjuration. -- bwr
-int mons_del_ench( struct monsters *mon, unsigned int ench, unsigned int ench2,
- bool quiet )
-{
- unsigned int p;
- int ret_val = ENCH_NONE;
-
- // silliness
- if (ench == ENCH_NONE)
- return (ENCH_NONE);
-
- if (ench2 == ENCH_NONE)
- ench2 = ench;
-
- for (p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
- break;
- }
-
- if (p == NUM_MON_ENCHANTS)
- return (ENCH_NONE);
-
- ret_val = mon->enchantment[p];
- mon->enchantment[p] = ENCH_NONE;
-
- // check for slow/haste
- if (ench == ENCH_HASTE)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) / 2);
- else
- mon->speed /= 2;
- }
-
- if (ench == ENCH_SLOW)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) * 2);
- else
- mon->speed *= 2;
- }
-
- if (ench == ENCH_PARALYSIS)
- {
- if (!quiet)
- simple_monster_message(mon, " is no longer paralysed.");
-
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_FEAR)
- {
- if (!quiet)
- simple_monster_message(mon, " seems to regain its courage.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_CONFUSION)
- {
- if (!quiet)
- simple_monster_message(mon, " seems less confused.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_INVIS)
- {
- // invisible monsters stay invisible
- if (mons_class_flag(mon->type, M_INVIS))
- {
- mon->enchantment[p] = ENCH_INVIS;
- }
- else if (mons_near(mon) && !player_see_invis()
- && !mons_has_ench( mon, ENCH_SUBMERGED ))
- {
- if (!quiet)
- {
- strcpy( info, ptr_monam( mon, DESC_CAP_A ) );
- strcat( info, " appears!" );
- mpr( info );
- }
- seen_monster(mon);
- }
- }
-
- if (ench == ENCH_CHARM)
- {
- if (!quiet)
- simple_monster_message(mon, " is no longer charmed.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_BACKLIGHT_I)
- {
- if (!quiet)
- simple_monster_message(mon, " stops glowing.");
- }
-
- if (ench == ENCH_STICKY_FLAME_I || ench == ENCH_YOUR_STICKY_FLAME_I)
- {
- if (!quiet)
- simple_monster_message(mon, " stops burning.");
- }
-
- if (ench == ENCH_POISON_I || ench == ENCH_YOUR_POISON_I)
- {
- if (!quiet)
- simple_monster_message(mon, " looks more healthy.");
- }
-
- if (ench == ENCH_YOUR_ROT_I)
- {
- if (!quiet)
- simple_monster_message(mon, " is no longer rotting.");
- }
-
- return (ret_val);
-}
-
-bool mons_add_ench(struct monsters *mon, unsigned int ench)
-{
- // silliness
- if (ench == ENCH_NONE)
- return (false);
-
- int newspot = -1;
-
- // don't double-add
- for (int p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] == ench)
- return (true);
-
- if (mon->enchantment[p] == ENCH_NONE && newspot < 0)
- newspot = p;
- }
-
- if (newspot < 0)
- return (false);
-
- mon->enchantment[newspot] = ench;
-// if ench == ENCH_FEAR //mv: withou this fear & repel undead spell doesn't work
-
-
- // check for slow/haste
- if (ench == ENCH_HASTE)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) * 2);
- else
- mon->speed *= 2;
- }
-
- if (ench == ENCH_SLOW)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) / 2);
- else
- mon->speed /= 2;
- }
-
- return (true);
-}
-
// used to determine whether or not a monster should always
// fire this spell if selected. If not, we should use a
// tracer.
@@ -2251,12 +2062,12 @@ bool ms_waste_of_time( struct monsters *mon, int monspell )
switch (monspell)
{
case MS_HASTE:
- if (mons_has_ench( mon, ENCH_HASTE ))
+ if (mon->has_ench(ENCH_HASTE))
ret = true;
break;
case MS_INVIS:
- if (mons_has_ench( mon, ENCH_INVIS ) ||
+ if (mon->has_ench(ENCH_INVIS) ||
(mons_friendly(mon) && !player_see_invis(false)))
ret = true;
break;
@@ -2268,7 +2079,7 @@ bool ms_waste_of_time( struct monsters *mon, int monspell )
case MS_TELEPORT:
// Monsters aren't smart enough to know when to cancel teleport.
- if (mons_has_ench( mon, ENCH_TP_I, ENCH_TP_IV ))
+ if (mon->has_ench( ENCH_TP ))
ret = true;
break;
@@ -2281,7 +2092,7 @@ bool ms_waste_of_time( struct monsters *mon, int monspell )
}
else if (mon->foe != MHITNOT)
{
- if (mons_has_ench( &menv[mon->foe], ENCH_TP_I, ENCH_TP_IV))
+ if (menv[mon->foe].has_ench(ENCH_TP))
return (true);
}
// intentional fall-through
@@ -2576,7 +2387,7 @@ monsters::monsters()
: type(-1), hit_points(0), max_hit_points(0), hit_dice(0),
ac(0), ev(0), speed(0), speed_increment(0), x(0), y(0),
target_x(0), target_y(0), inv(), spells(), attitude(ATT_NEUTRAL),
- behaviour(BEH_WANDER), foe(MHITYOU), enchantment(), flags(0L),
+ behaviour(BEH_WANDER), foe(MHITYOU), enchantments(), flags(0L),
number(0), colour(BLACK), foe_memory(0), god(GOD_NO_GOD),
ghost()
{
@@ -2612,7 +2423,7 @@ void monsters::init_with(const monsters &mon)
attitude = mon.attitude;
behaviour = mon.behaviour;
foe = mon.foe;
- enchantment = mon.enchantment;
+ enchantments = mon.enchantments;
flags = mon.flags;
number = mon.number;
colour = mon.colour;
@@ -2905,8 +2716,8 @@ void monsters::poison(actor *agent, int amount)
// Scale poison down for monsters.
if (!(amount /= 2))
amount = 1;
-
- poison_monster(this, agent->atype() == ACT_PLAYER, amount);
+
+ poison_monster(this, agent->kill_alignment(), amount);
}
int monsters::skill(skill_type sk, bool) const
@@ -3039,7 +2850,7 @@ void monsters::ghost_init()
load_spells(MST_GHOST);
inv.init(NON_ITEM);
- enchantment.init(ENCH_NONE);
+ enchantments.clear();
find_place_to_live();
}
@@ -3119,7 +2930,7 @@ void monsters::reset()
{
destroy_inventory();
- enchantment.init(ENCH_NONE);
+ enchantments.clear();
inv.init(NON_ITEM);
flags = 0;
@@ -3133,6 +2944,7 @@ void monsters::reset()
attitude = ATT_HOSTILE;
behaviour = BEH_SLEEP;
foe = MHITNOT;
+ number = 0;
if (in_bounds(x, y))
mgrd[x][y] = NON_MONSTER;
@@ -3146,7 +2958,7 @@ bool monsters::needs_transit() const
return ((mons_is_unique(type)
|| (flags & MF_BANISHED)
|| (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25)))
- && !mons_has_ench(this, ENCH_ABJ_I, ENCH_ABJ_VI));
+ && !mons_is_summoned(this));
}
void monsters::set_transit(level_id dest)
@@ -3192,3 +3004,628 @@ void monsters::load_spells(int book)
}
}
}
+
+bool monsters::has_ench(enchant_type ench,
+ enchant_type ench2) const
+{
+ if (ench2 == ENCH_NONE)
+ ench2 = ench;
+
+ for (int i = ench; i <= ench2; ++i)
+ {
+ if (enchantments.find( static_cast<enchant_type>(i) ) !=
+ enchantments.end())
+ {
+ return (true);
+ }
+ }
+ return (false);
+}
+
+mon_enchant monsters::get_ench(enchant_type ench1,
+ enchant_type ench2) const
+{
+ if (ench2 == ENCH_NONE)
+ ench2 = ench1;
+
+ for (int e = ench1; e <= ench2; ++e)
+ {
+ mon_enchant_list::const_iterator i =
+ enchantments.find(static_cast<enchant_type>(e));
+ if (i != enchantments.end())
+ return (*i);
+ }
+
+ return (mon_enchant());
+}
+
+void monsters::update_ench(const mon_enchant &ench)
+{
+ if (ench.ench != ENCH_NONE)
+ {
+ mon_enchant_list::iterator i = enchantments.find(ench);
+ if (i != enchantments.end())
+ enchantments.erase(i);
+ enchantments.insert(ench);
+ }
+}
+
+bool monsters::add_ench(const mon_enchant &ench)
+{
+ // silliness
+ if (ench.ench == ENCH_NONE)
+ return (false);
+
+ mon_enchant_list::iterator i = enchantments.find(ench);
+ if (i == enchantments.end())
+ enchantments.insert(ench);
+ else
+ {
+ mon_enchant new_ench = *i + ench;
+ enchantments.erase(i);
+ enchantments.insert(new_ench);
+ }
+
+ // check for slow/haste
+ if (ench.ench == ENCH_HASTE)
+ {
+ if (speed >= 100)
+ speed = 100 + ((speed - 100) * 2);
+ else
+ speed *= 2;
+ }
+
+ if (ench.ench == ENCH_SLOW)
+ {
+ if (speed >= 100)
+ speed = 100 + ((speed - 100) / 2);
+ else
+ speed /= 2;
+ }
+
+ return (true);
+}
+
+bool monsters::del_ench(enchant_type ench, bool quiet)
+{
+ mon_enchant_list::iterator i = enchantments.find(ench);
+ if (i == enchantments.end())
+ return (false);
+
+ mon_enchant me = *i;
+ enchantments.erase(i);
+
+ remove_enchantment_effect(me, quiet);
+ return (true);
+}
+
+void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
+{
+ switch (me.ench)
+ {
+ case ENCH_HASTE:
+ if (speed >= 100)
+ speed = 100 + ((speed - 100) / 2);
+ else
+ speed /= 2;
+ break;
+
+ case ENCH_SLOW:
+ if (speed >= 100)
+ speed = 100 + ((speed - 100) * 2);
+ else
+ speed *= 2;
+ break;
+
+ case ENCH_PARALYSIS:
+ if (!quiet)
+ simple_monster_message(this, " is no longer paralysed.");
+
+ behaviour_event(this, ME_EVAL);
+ break;
+
+ case ENCH_FEAR:
+ if (!quiet)
+ simple_monster_message(this, " seems to regain its courage.");
+
+ // reevaluate behaviour
+ behaviour_event(this, ME_EVAL);
+ break;
+
+ case ENCH_CONFUSION:
+ if (!quiet)
+ simple_monster_message(this, " seems less confused.");
+
+ // reevaluate behaviour
+ behaviour_event(this, ME_EVAL);
+ break;
+
+ case ENCH_INVIS:
+ // invisible monsters stay invisible
+ if (mons_class_flag(type, M_INVIS))
+ add_ench( mon_enchant(ENCH_INVIS) );
+ else if (mons_near(this) && !player_see_invis()
+ && !has_ench( ENCH_SUBMERGED ))
+ {
+ if (!quiet)
+ mprf("%s appears!", name(DESC_CAP_A).c_str() );
+
+ seen_monster(this);
+ }
+ break;
+
+ case ENCH_CHARM:
+ if (!quiet)
+ simple_monster_message(this, " is no longer charmed.");
+
+ // reevaluate behaviour
+ behaviour_event(this, ME_EVAL);
+ break;
+
+ case ENCH_BACKLIGHT:
+ if (!quiet)
+ simple_monster_message(this, " stops glowing.");
+ break;
+
+ case ENCH_STICKY_FLAME:
+ if (!quiet)
+ simple_monster_message(this, " stops burning.");
+ break;
+
+ case ENCH_POISON:
+ if (!quiet)
+ simple_monster_message(this, " looks more healthy.");
+ break;
+
+ case ENCH_ROT:
+ if (!quiet)
+ simple_monster_message(this, " is no longer rotting.");
+ break;
+
+ case ENCH_ABJ:
+ case ENCH_SHORT_LIVED:
+ add_ench( mon_enchant(ENCH_ABJ) );
+ monster_die( this, quiet? KILL_DISMISSED : KILL_RESET, 0 );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void monsters::lose_ench_levels(const mon_enchant &e, int levels)
+{
+ if (!levels)
+ return;
+
+ mon_enchant me(e);
+ me.degree -= levels;
+
+ if (me.degree < 1)
+ del_ench(e.ench);
+ else
+ update_ench(me);
+}
+
+//---------------------------------------------------------------
+//
+// timeout_enchantments
+//
+// Update a monster's enchantments when the player returns
+// to the level.
+//
+// Management for enchantments... problems with this are the oddities
+// (monster dying from poison several thousands of turns later), and
+// game balance.
+//
+// Consider: Poison/Sticky Flame a monster at range and leave, monster
+// dies but can't leave level to get to player (implied game balance of
+// the delayed damage is that the monster could be a danger before
+// it dies). This could be fixed by keeping some monsters active
+// off level and allowing them to take stairs (a very serious change).
+//
+// Compare this to the current abuse where the player gets
+// effectively extended duration of these effects (although only
+// the actual effects only occur on level, the player can leave
+// and heal up without having the effect disappear).
+//
+// This is a simple compromise between the two... the enchantments
+// go away, but the effects don't happen off level. -- bwr
+//
+//---------------------------------------------------------------
+void monsters::timeout_enchantments(int levels)
+{
+ for (mon_enchant_list::iterator i = enchantments.begin();
+ i != enchantments.end(); )
+ {
+ mon_enchant_list::iterator cur = i++;
+
+ switch (cur->ench)
+ {
+ case ENCH_POISON: case ENCH_ROT: case ENCH_BACKLIGHT:
+ case ENCH_STICKY_FLAME: case ENCH_ABJ: case ENCH_SHORT_LIVED:
+ case ENCH_SLOW: case ENCH_HASTE: case ENCH_FEAR:
+ case ENCH_INVIS: case ENCH_CHARM: case ENCH_SLEEP_WARY:
+ lose_ench_levels(*cur, levels);
+ break;
+
+ case ENCH_TP:
+ teleport(true);
+ break;
+
+ case ENCH_CONFUSION:
+ blink();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+// used to adjust time durations in handle_enchantment() for monster speed
+static inline int mod_speed( int val, int speed )
+{
+ return (speed ? (val * 10) / speed : val);
+}
+
+void monsters::apply_enchantment(mon_enchant me, int spd)
+{
+ switch (me.ench)
+ {
+ case ENCH_SLOW:
+ if (random2(250) <= mod_speed( hit_dice + 10, spd ))
+ del_ench(me.ench);
+ break;
+
+ case ENCH_HASTE:
+ if (random2(1000) < mod_speed( 25, spd ))
+ del_ench(ENCH_HASTE);
+ break;
+
+ case ENCH_FEAR:
+ if (random2(150) <= mod_speed( hit_dice + 5, spd ))
+ del_ench(ENCH_FEAR);
+ break;
+
+ case ENCH_PARALYSIS:
+ if (random2(120) < mod_speed( hit_dice + 5, spd ))
+ del_ench(ENCH_PARALYSIS);
+ break;
+
+ case ENCH_CONFUSION:
+ if (random2(120) < mod_speed( hit_dice + 5, spd ))
+ {
+ // don't delete perma-confusion
+ if (!mons_class_flag(type, M_CONFUSED))
+ del_ench(ENCH_CONFUSION);
+ }
+ break;
+
+ case ENCH_INVIS:
+ if (random2(1000) < mod_speed( 25, spd ))
+ {
+ // don't delete perma-invis
+ if (!mons_class_flag( type, M_INVIS ))
+ del_ench(ENCH_INVIS);
+ }
+ break;
+
+ case ENCH_SUBMERGED:
+ {
+ // not even air elementals unsubmerge into clouds
+ if (env.cgrid[x][y] != EMPTY_CLOUD)
+ break;
+
+ // Air elementals are a special case, as their
+ // submerging in air isn't up to choice. -- bwr
+ if (type == MONS_AIR_ELEMENTAL)
+ {
+ heal_monster( this, 1, one_chance_in(5) );
+
+ if (one_chance_in(5))
+ del_ench(ENCH_SUBMERGED);
+
+ break;
+ }
+
+ // Now we handle the others:
+ int 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))
+ 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)
+ && (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)))
+ {
+ del_ench(ENCH_SUBMERGED);
+ }
+ break;
+ }
+ case ENCH_POISON:
+ {
+ int poisonval = me.degree;
+ int dam = (poisonval >= 4) ? 1 : 0;
+
+ if (coinflip())
+ dam += roll_dice( 1, poisonval + 1 );
+
+ 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 );
+
+#if DEBUG_DIAGNOSTICS
+ // for debugging, we don't have this silent.
+ simple_monster_message( this, " takes poison damage.",
+ MSGCH_DIAGNOSTICS );
+ snprintf( info, INFO_SIZE, "poison damage: %d", dam );
+ mpr( info, MSGCH_DIAGNOSTICS );
+#endif
+
+ if (hit_points < 1)
+ {
+ monster_die(this, me.killer(), me.kill_agent());
+ break;
+ }
+ }
+
+ // chance to get over poison (1 in 8, modified for speed)
+ if (random2(1000) < mod_speed( 125, spd ))
+ lose_ench_levels(me, 1);
+ break;
+ }
+ case ENCH_ROT:
+ if (hit_points > 1
+ && random2(1000) < mod_speed( 333, spd ))
+ {
+ hurt_monster(this, 1);
+ }
+
+ if (random2(1000) < mod_speed( me.degree == 1? 250 : 333, spd ))
+ lose_ench_levels(me, 1);
+
+ break;
+
+ case ENCH_BACKLIGHT:
+ if (random2(1000) < mod_speed( me.degree == 1? 100 : 200, spd ))
+ lose_ench_levels(me, 1);
+ break;
+
+ // 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;
+
+ // 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 );
+ simple_monster_message(this, " burns!");
+
+#if DEBUG_DIAGNOSTICS
+ mprf( MSGCH_DIAGNOSTICS, "sticky flame damage: %d", dam );
+#endif
+
+ if (hit_points < 1)
+ {
+ monster_die(this, me.killer(), me.kill_agent());
+ break;
+ }
+ }
+
+ // chance to get over sticky flame (1 in 5, modified for speed)
+ if (random2(1000) < mod_speed( 200, spd ))
+ lose_ench_levels(me, 1);
+ break;
+ }
+
+ case ENCH_SHORT_LIVED:
+ // This should only be used for ball lightning -- bwr
+ if (random2(1000) < mod_speed( 200, spd ))
+ hit_points = -1;
+ break;
+
+ // 19 is taken by summoning:
+ // If these are changed, must also change abjuration
+ case ENCH_ABJ:
+ {
+ const int mspd =
+ me.degree == 6? 10 :
+ me.degree == 5? 20 : 100;
+
+ if (random2(1000) < mod_speed( mspd, spd ))
+ lose_ench_levels(me, 1);
+ break;
+ }
+
+ case ENCH_CHARM:
+ if (random2(500) <= mod_speed( hit_dice + 10, spd ))
+ del_ench(ENCH_CHARM);
+ break;
+
+ case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
+ // number of actions is fine for shapeshifters
+ if (type == MONS_GLOWING_SHAPESHIFTER
+ || random2(1000) < mod_speed( 250, spd ))
+ {
+ monster_polymorph(this, RANDOM_MONSTER, 0);
+ }
+ break;
+
+ case ENCH_SHAPESHIFTER: // this ench never runs out
+ if (type == MONS_SHAPESHIFTER
+ || random2(1000) < mod_speed( 1000 / ((15 * hit_dice) / 5), spd ))
+ {
+ monster_polymorph(this, RANDOM_MONSTER, 0);
+ }
+ break;
+
+ case ENCH_TP:
+ if (me.degree <= 1)
+ {
+ del_ench(ENCH_TP);
+ monster_teleport( this, true );
+ }
+ else
+ {
+ int tmp = mod_speed( 1000, spd );
+
+ if (tmp < 1000 && random2(1000) < tmp)
+ lose_ench_levels(me, 1);
+ else if (me.degree - tmp / 1000 >= 1)
+ {
+ lose_ench_levels(me, tmp / 1000);
+ tmp %= 1000;
+
+ if (random2(1000) < tmp)
+ {
+ if (me.degree > 1)
+ lose_ench_levels(me, 1);
+ else
+ {
+ del_ench( ENCH_TP );
+ monster_teleport( this, true );
+ }
+ }
+ }
+ else
+ {
+ del_ench( ENCH_TP );
+ monster_teleport( this, true );
+ }
+ }
+ break;
+
+ case ENCH_SLEEP_WARY:
+ if (random2(1000) < mod_speed( 50, spd ))
+ del_ench(ENCH_SLEEP_WARY);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void monsters::apply_enchantments(int spd)
+{
+ for (mon_enchant_list::iterator i = enchantments.begin();
+ i != enchantments.end(); )
+ {
+ mon_enchant_list::iterator cur = i++;
+ apply_enchantment(*cur, spd);
+ }
+}
+
+kill_category monsters::kill_alignment() const
+{
+ return (attitude == ATT_FRIENDLY? KC_FRIENDLY : KC_OTHER);
+}
+
+/////////////////////////////////////////////////////////////////////////
+// mon_enchant
+
+static const char *enchant_names[] =
+{
+ "none", "slow", "haste", "fear", "conf", "inv", "pois", "bers",
+ "rot", "summon", "abj", "backlit", "charm", "fire",
+ "gloshifter", "shifter", "tp", "wary", "submerged",
+ "short lived", "paralysis", "bug"
+};
+
+const char *mons_enchantment_name(enchant_type ench)
+{
+ ASSERT(NUM_ENCHANTMENTS ==
+ (sizeof(enchant_names) / sizeof(*enchant_names)) - 1);
+
+ if (ench > NUM_ENCHANTMENTS)
+ ench = NUM_ENCHANTMENTS;
+
+ return (enchant_names[ench]);
+}
+
+mon_enchant::operator std::string () const
+{
+ return make_stringf("%s (%d%s)",
+ mons_enchantment_name(ench),
+ degree,
+ kill_category_desc(who));
+}
+
+const char *mon_enchant::kill_category_desc(kill_category k) const
+{
+ return (k == KC_YOU? "you" :
+ k == KC_FRIENDLY? "pet" : "");
+}
+
+void mon_enchant::merge_killer(kill_category k)
+{
+ who = who < k? who : k;
+}
+
+void mon_enchant::cap_degree()
+{
+ // Hard cap to simulate old enum behaviour, we should really throw this
+ // out entirely.
+ const int max = ench == ENCH_ABJ? 6 : 4;
+ if (degree > max)
+ degree = max;
+}
+
+mon_enchant &mon_enchant::operator += (const mon_enchant &other)
+{
+ if (ench == other.ench)
+ {
+ degree += other.degree;
+ cap_degree();
+ merge_killer(other.who);
+ }
+ return (*this);
+}
+
+mon_enchant mon_enchant::operator + (const mon_enchant &other) const
+{
+ mon_enchant tmp(*this);
+ tmp += other;
+ return (tmp);
+}
+
+int mon_enchant::killer() const
+{
+ return (who == KC_YOU? KILL_YOU :
+ who == KC_FRIENDLY? KILL_MON :
+ KILL_MISC);
+}
+
+int mon_enchant::kill_agent() const
+{
+ return (who == KC_FRIENDLY? ANON_FRIENDLY_MONSTER : 0);
+}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 20774df6d8..f35f9cce2f 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -415,14 +415,6 @@ bool mons_has_lifeforce( const monsters *mon );
monster_type mons_genus( int mc );
monster_type mons_species( int mc );
-int mons_has_ench( const monsters *mon, unsigned int ench,
- unsigned int ench2 = ENCH_NONE );
-
-int mons_del_ench( struct monsters *mon, unsigned int ench,
- unsigned int ench2 = ENCH_NONE, bool quiet = false );
-
-bool mons_add_ench( struct monsters *mon, unsigned int ench );
-
bool mons_looks_stabbable(const monsters *m);
bool mons_looks_distracted(const monsters *m);
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 46dba3c92c..4ffaf59650 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -447,13 +447,9 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
if (id == MAX_MONSTERS)
return -1;
- // scrap monster inventory
- for (i = 0; i < NUM_MONSTER_SLOTS; i++)
- menv[id].inv[i] = NON_ITEM;
-
+ menv[id].inv.init(NON_ITEM);
// scrap monster enchantments
- for (i = 0; i < NUM_MON_ENCHANTS; i++)
- menv[id].enchantment[i] = ENCH_NONE;
+ menv[id].enchantments.clear();
// setup habitat and placement
if (first_band_member)
@@ -530,16 +526,16 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
menv[id].number = extra;
if (mons_class_flag(mon_type, M_INVIS))
- mons_add_ench(&menv[id], ENCH_INVIS);
+ menv[id].add_ench(ENCH_INVIS);
if (mons_class_flag(mon_type, M_CONFUSED))
- mons_add_ench(&menv[id], ENCH_CONFUSION);
+ menv[id].add_ench(ENCH_CONFUSION);
if (mon_type == MONS_SHAPESHIFTER)
- mons_add_ench(&menv[id], ENCH_SHAPESHIFTER);
+ menv[id].add_ench(ENCH_SHAPESHIFTER);
if (mon_type == MONS_GLOWING_SHAPESHIFTER)
- mons_add_ench(&menv[id], ENCH_GLOWING_SHAPESHIFTER);
+ menv[id].add_ench(ENCH_GLOWING_SHAPESHIFTER);
if (mon_type == MONS_GIANT_BAT || mon_type == MONS_UNSEEN_HORROR
|| mon_type == MONS_GIANT_BLOWFLY)
@@ -549,7 +545,7 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
if (monster_can_submerge(mon_type, grd[fx][fy])
&& !one_chance_in(5))
- mons_add_ench( &menv[id], ENCH_SUBMERGED );
+ menv[id].add_ench(ENCH_SUBMERGED);
menv[id].flags |= MF_JUST_SUMMONED;
@@ -597,9 +593,9 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
menv[id].behaviour = BEH_WANDER;
}
- // dur should always be ENCH_ABJ_xx
- if (dur >= ENCH_ABJ_I && dur <= ENCH_ABJ_VI)
- mons_add_ench(&menv[id], dur );
+ // dur should always be 1-6 for monsters that can be abjured.
+ if (dur >= 1 && dur <= 6)
+ menv[id].add_ench( mon_enchant(ENCH_ABJ, dur) );
menv[id].foe = target;
@@ -1266,7 +1262,7 @@ int mons_place( int mon_type, char behaviour, int target, bool summoned,
if (behaviour == BEH_CHARMED)
{
creation->attitude = ATT_HOSTILE;
- mons_add_ench(creation, ENCH_CHARM);
+ creation->add_ench(ENCH_CHARM);
}
// make summoned being aware of player's presence
@@ -1358,8 +1354,8 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
struct monsters *const creation = &menv[summd];
// dur should always be ENCH_ABJ_xx
- if (dur >= ENCH_ABJ_I && dur <= ENCH_ABJ_VI)
- mons_add_ench(creation, dur );
+ if (dur >= 1 && dur <= 6)
+ creation->add_ench( mon_enchant(ENCH_ABJ, dur) );
// look at special cases: CHARMED, FRIENDLY, HOSTILE, GOD_GIFT
// alert summoned being to player's presence
@@ -1377,7 +1373,7 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
if (beha == BEH_CHARMED)
{
creation->attitude = ATT_HOSTILE;
- mons_add_ench(creation, ENCH_CHARM);
+ creation->add_ench(ENCH_CHARM);
}
// make summoned being aware of player's presence
@@ -1385,7 +1381,7 @@ int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
}
if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3))
- mons_add_ench(creation, ENCH_INVIS);
+ creation->add_ench(ENCH_INVIS);
}
// the return value is either -1 (failure of some sort)
diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/monspeak.cc
index 9d816115fd..47678b005d 100644
--- a/crawl-ref/source/monspeak.cc
+++ b/crawl-ref/source/monspeak.cc
@@ -53,7 +53,7 @@ bool mons_speaks(struct monsters *monster)
const char *m_name = ptr_monam(monster, DESC_CAP_THE);
strcpy(info, m_name);
- if (mons_has_ench(monster, ENCH_INVIS))
+ if (monster->has_ench(ENCH_INVIS))
return false;
// invisible monster tries to remain unnoticed
@@ -63,7 +63,7 @@ bool mons_speaks(struct monsters *monster)
if (!one_chance_in(3))
return false; // while silenced, don't bother so often
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
{
temp_rand = random2(10);
strcat(info, (temp_rand < 4) ? " gestures wildly." :
@@ -111,10 +111,10 @@ bool mons_speaks(struct monsters *monster)
} // end silenced monster
// charmed monsters aren't too expressive
- if (mons_has_ench(monster, ENCH_CHARM))
+ if (monster->has_ench(ENCH_CHARM))
return false;
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
{
if (mons_holiness( monster ) == MH_DEMONIC
&& monster->type != MONS_IMP)
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 92066944ea..66bb45a775 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -294,9 +294,9 @@ static void place_monster_corpse(const monsters *monster)
if (corpse_class == MONS_DRACONIAN)
corpse_class = draco_subspecies(monster);
- if (mons_has_ench(monster, ENCH_SHAPESHIFTER))
+ if (monster->has_ench(ENCH_SHAPESHIFTER))
corpse_class = MONS_SHAPESHIFTER;
- else if (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER))
+ else if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER))
corpse_class = MONS_GLOWING_SHAPESHIFTER;
if (mons_weight(corpse_class) == 0
@@ -384,8 +384,11 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
if (you.prev_targ == monster_killed)
you.prev_targ = MHITNOT;
- const bool pet_kill = (MON_KILL(killer) && ((i >= 0 && i < 200)
- && mons_friendly(&menv[i])));
+ const bool pet_kill =
+ (MON_KILL(killer)
+ && (i == ANON_FRIENDLY_MONSTER ||
+ ((i >= 0 && i < 200)
+ && mons_friendly(&menv[i]))));
if (monster->type == MONS_GIANT_SPORE
|| monster->type == MONS_BALL_LIGHTNING)
@@ -588,11 +591,11 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
if (!testbits(monster->flags, MF_CREATED_FRIENDLY) && pet_kill)
{
bool notice = false;
-
+ const bool anon = (i == ANON_FRIENDLY_MONSTER);
gain_exp(exper_value( monster ) / 2 + 1);
int targ_holy = mons_holiness(monster),
- attacker_holy = mons_holiness(&menv[i]);
+ attacker_holy = anon? MH_NATURAL : mons_holiness(&menv[i]);
if (attacker_holy == MH_UNDEAD)
{
@@ -603,7 +606,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
}
else if (you.religion == GOD_VEHUMET
|| you.religion == GOD_MAKHLEB
- || testbits( menv[i].flags, MF_GOD_GIFT ))
+ || (!anon && testbits( menv[i].flags, MF_GOD_GIFT )))
{
// Yes, we are splitting undead pets from the others
// as a way to focus Necomancy vs Summoning (ignoring
@@ -757,7 +760,7 @@ void monster_die(monsters *monster, char killer, int i, bool silent)
you.kills.record_kill(monster, killer, pet_kill);
- if (mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI))
+ if (monster->has_ench(ENCH_ABJ))
{
if (mons_weight(mons_species(monster->type)))
{
@@ -878,11 +881,7 @@ static bool jelly_divide(struct monsters * parent)
child->foe = parent->foe;
child->attitude = parent->attitude;
child->colour = parent->colour;
-
- // duplicate enchantments
- for ( int i = 0; i < NUM_MON_ENCHANTS; ++i )
- child->enchantment[i] = parent->enchantment[i];
-
+ child->enchantments = parent->enchantments;
child->x = parent->x + jex;
child->y = parent->y + jey;
@@ -1009,21 +1008,21 @@ bool monster_polymorph( struct monsters *monster, int targetc, int power )
return (player_messaged);
}
- // If old monster is visible to the player, and is interesting,
- // then note why the interesting monster went away.
- if (player_monster_visible(monster) && mons_near(monster)
+ // If old monster is visible to the player, and is interesting,
+ // then note why the interesting monster went away.
+ if (player_monster_visible(monster) && mons_near(monster)
&& MONST_INTERESTING(monster))
{
- take_note(Note(NOTE_POLY_MONSTER, monster->type, 0,
- ptr_monam(monster, DESC_NOCAP_A, true)));
- }
+ take_note(Note(NOTE_POLY_MONSTER, monster->type, 0,
+ ptr_monam(monster, DESC_NOCAP_A, true)));
+ }
// messaging: {dlb}
bool invis = (mons_class_flag( targetc, M_INVIS )
- || mons_has_ench( monster, ENCH_INVIS )) &&
+ || monster->has_ench(ENCH_INVIS)) &&
(!player_see_invis());
- if (mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER ))
+ if (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER))
strcat( str_polymon, " changes into " );
else if (targetc == MONS_PULSATING_LUMP)
strcat( str_polymon, " degenerates into " );
@@ -1052,22 +1051,18 @@ bool monster_polymorph( struct monsters *monster, int targetc, int power )
monster->type = targetc;
monster->number = 250;
- int abj = mons_has_ench( monster, ENCH_ABJ_I, ENCH_ABJ_VI );
- int shifter = mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
- ENCH_SHAPESHIFTER );
+ mon_enchant abj = monster->get_ench(ENCH_ABJ);
+ mon_enchant shifter = monster->get_ench(ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER);
// Note: define_monster() will clear out all enchantments! -- bwr
define_monster( monster_index(monster) );
- // put back important enchantments:
- if (abj != ENCH_NONE)
- mons_add_ench( monster, abj );
-
- if (shifter != ENCH_NONE)
- mons_add_ench( monster, shifter );
+ monster->add_ench(abj);
+ monster->add_ench(shifter);
if (mons_class_flag( monster->type, M_INVIS ))
- mons_add_ench( monster, ENCH_INVIS );
+ monster->add_ench(ENCH_INVIS);
monster->hit_points = monster->max_hit_points
* ((old_hp * 100) / old_hp_max) / 100
@@ -1402,7 +1397,7 @@ void behaviour_event( struct monsters *mon, int event, int src,
case ME_CORNERED:
// just set behaviour.. foe doesn't change.
- if (mon->behaviour != BEH_CORNERED && !mons_has_ench(mon,ENCH_FEAR))
+ if (mon->behaviour != BEH_CORNERED && !mon->has_ench(ENCH_FEAR))
simple_monster_message(mon, " turns to fight!");
mon->behaviour = BEH_CORNERED;
@@ -1430,7 +1425,7 @@ void behaviour_event( struct monsters *mon, int event, int src,
// now, break charms if appropriate
if (breakCharm)
- mons_del_ench( mon, ENCH_CHARM );
+ mon->del_ench(ENCH_CHARM);
// do any resultant foe or state changes
handle_behaviour( mon );
@@ -1453,11 +1448,11 @@ static void handle_behaviour(struct monsters *mon)
bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1);
bool isHealthy = (mon->hit_points > mon->max_hit_points / 2);
bool isSmart = (mons_intel(mon->type) > I_ANIMAL);
- bool isScared = mons_has_ench(mon, ENCH_FEAR);
+ bool isScared = mon->has_ench(ENCH_FEAR);
bool isMobile = !mons_is_stationary(mon);
// check for confusion -- early out.
- if (mons_has_ench(mon, ENCH_CONFUSION))
+ if (mon->has_ench(ENCH_CONFUSION))
{
mon->target_x = 10 + random2(GXM - 10);
mon->target_y = 10 + random2(GYM - 10);
@@ -1821,20 +1816,8 @@ bool simple_monster_message(struct monsters *monster, const char *event,
return (false);
} // end simple_monster_message()
-// used to adjust time durations in handle_enchantment() for monster speed
-static inline int mod_speed( int val, int speed )
-{
- return (speed ? (val * 10) / speed : val);
-}
-
static bool handle_enchantment(struct monsters *monster)
{
- bool died = false;
- int grid;
- int poisonval;
- int dam;
- int tmp;
-
// Yes, this is the speed we want. This function will be called in
// two circumstances: (1) the monster can move and has enough energy,
// and (2) the monster cannot move (speed == 0) and the monster loop
@@ -1864,336 +1847,8 @@ static bool handle_enchantment(struct monsters *monster)
//
// -- bwr
const int speed = (monster->speed == 0) ? you.time_taken : monster->speed;
-
- for (int p = 0; p < NUM_MON_ENCHANTS && !died; p++)
- {
- switch (monster->enchantment[p])
- {
- case ENCH_SLOW:
- if (random2(250) <= mod_speed( monster->hit_dice + 10, speed ))
- mons_del_ench(monster, ENCH_SLOW);
- break;
-
- case ENCH_HASTE:
- if (random2(1000) < mod_speed( 25, speed ))
- mons_del_ench(monster, ENCH_HASTE);
- break;
-
- case ENCH_FEAR:
- if (random2(150) <= mod_speed( monster->hit_dice + 5, speed ))
- mons_del_ench(monster, ENCH_FEAR);
- break;
-
- case ENCH_PARALYSIS:
- if (random2(120) < mod_speed( monster->hit_dice + 5, speed ))
- mons_del_ench(monster, ENCH_PARALYSIS);
- break;
-
- case ENCH_CONFUSION:
- if (random2(120) < mod_speed( monster->hit_dice + 5, speed ))
- {
- // don't delete perma-confusion
- if (!mons_class_flag(monster->type, M_CONFUSED))
- mons_del_ench(monster, ENCH_CONFUSION);
- }
- break;
-
- case ENCH_INVIS:
- if (random2(1000) < mod_speed( 25, speed ))
- {
- // don't delete perma-invis
- if (!mons_class_flag( monster->type, M_INVIS ))
- mons_del_ench(monster, ENCH_INVIS);
- }
- break;
-
- case ENCH_SUBMERGED:
- // not even air elementals unsubmerge into clouds
- if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
- break;
-
- // Air elementals are a special case, as their
- // submerging in air isn't up to choice. -- bwr
- if (monster->type == MONS_AIR_ELEMENTAL)
- {
- heal_monster( monster, 1, one_chance_in(5) );
-
- if (one_chance_in(5))
- mons_del_ench( monster, ENCH_SUBMERGED );
-
- break;
- }
-
- // Now we handle the others:
- grid = grd[monster->x][monster->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(monster->type, grid))
- mons_del_ench( monster, ENCH_SUBMERGED ); // forced to surface
- else if (monster->hit_points <= monster->max_hit_points / 2)
- break;
- else if (((monster->type == MONS_ELECTRICAL_EEL
- || monster->type == MONS_LAVA_SNAKE)
- && (random2(1000) < mod_speed( 20, speed )
- || (mons_near(monster)
- && monster->hit_points == monster->max_hit_points
- && !one_chance_in(10))))
- || random2(2000) < mod_speed(10, speed)
- || (mons_near(monster)
- && monster->hit_points == monster->max_hit_points
- && !one_chance_in(5)))
- {
- mons_del_ench( monster, ENCH_SUBMERGED );
- }
- break;
-
- case ENCH_POISON_I:
- case ENCH_POISON_II:
- case ENCH_POISON_III:
- case ENCH_POISON_IV:
- case ENCH_YOUR_POISON_I:
- case ENCH_YOUR_POISON_II:
- case ENCH_YOUR_POISON_III:
- case ENCH_YOUR_POISON_IV:
- poisonval = monster->enchantment[p] - ENCH_POISON_I;
-
- if (poisonval < 0 || poisonval > 3)
- poisonval = monster->enchantment[p] - ENCH_YOUR_POISON_I;
-
- dam = (poisonval >= 3) ? 1 : 0;
-
- if (coinflip())
- dam += roll_dice( 1, poisonval + 2 );
-
- if (mons_res_poison(monster) < 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 / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0);
-
- if (dam > 0)
- {
- hurt_monster( monster, dam );
-
-#if DEBUG_DIAGNOSTICS
- // for debugging, we don't have this silent.
- simple_monster_message( monster, " takes poison damage.",
- MSGCH_DIAGNOSTICS );
- snprintf( info, INFO_SIZE, "poison damage: %d", dam );
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- if (monster->hit_points < 1)
- {
- monster_die(monster,
- ((monster->enchantment[p] < ENCH_POISON_I)
- ? KILL_YOU : KILL_MISC), 0);
- died = true;
- }
- }
-
- // chance to get over poison (1 in 8, modified for speed)
- if (random2(1000) < mod_speed( 125, speed ))
- {
- if (monster->enchantment[p] == ENCH_POISON_I)
- mons_del_ench(monster, ENCH_POISON_I);
- else if (monster->enchantment[p] == ENCH_YOUR_POISON_I)
- mons_del_ench(monster, ENCH_YOUR_POISON_I);
- else
- monster->enchantment[p]--;
- }
- break;
-
- case ENCH_YOUR_ROT_I:
- if (random2(1000) < mod_speed( 250, speed ))
- mons_del_ench(monster, ENCH_YOUR_ROT_I);
- else if (monster->hit_points > 1
- && random2(1000) < mod_speed( 333, speed ))
- {
- hurt_monster(monster, 1);
- }
- break;
-
- //jmf: FIXME: if (undead) make_small_rot_cloud();
- case ENCH_YOUR_ROT_II:
- case ENCH_YOUR_ROT_III:
- case ENCH_YOUR_ROT_IV:
- if (monster->hit_points > 1
- && random2(1000) < mod_speed( 333, speed ))
- {
- hurt_monster(monster, 1);
- }
-
- if (random2(1000) < mod_speed( 250, speed ))
- monster->enchantment[p]--;
- break;
-
- case ENCH_BACKLIGHT_I:
- if (random2(1000) < mod_speed( 100, speed ))
- mons_del_ench( monster, ENCH_BACKLIGHT_I );
- break;
-
- case ENCH_BACKLIGHT_II:
- case ENCH_BACKLIGHT_III:
- case ENCH_BACKLIGHT_IV:
- if (random2(1000) < mod_speed( 200, speed ))
- monster->enchantment[p]--;
- break;
-
- // assumption: mons_res_fire has already been checked
- case ENCH_STICKY_FLAME_I:
- case ENCH_STICKY_FLAME_II:
- case ENCH_STICKY_FLAME_III:
- case ENCH_STICKY_FLAME_IV:
- case ENCH_YOUR_STICKY_FLAME_I:
- case ENCH_YOUR_STICKY_FLAME_II:
- case ENCH_YOUR_STICKY_FLAME_III:
- case ENCH_YOUR_STICKY_FLAME_IV:
- dam = roll_dice( 2, 4 ) - 1;
-
- if (mons_res_fire( monster ) < 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 / speed) + ((random2(speed) < (dam % speed)) ? 1 : 0);
-
- if (dam > 0)
- {
- hurt_monster( monster, dam );
- simple_monster_message(monster, " burns!");
-
-#if DEBUG_DIAGNOSTICS
- snprintf( info, INFO_SIZE, "sticky flame damage: %d", dam );
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- if (monster->hit_points < 1)
- {
- monster_die(monster,
- ((monster->enchantment[p] < ENCH_STICKY_FLAME_I)
- ? KILL_YOU : KILL_MISC), 0);
- died = true;
- }
- }
-
- // chance to get over sticky flame (1 in 5, modified for speed)
- if (random2(1000) < mod_speed( 200, speed ))
- {
- if (monster->enchantment[p] == ENCH_STICKY_FLAME_I)
- mons_del_ench( monster, ENCH_STICKY_FLAME_I );
- else if (monster->enchantment[p] == ENCH_YOUR_STICKY_FLAME_I)
- mons_del_ench( monster, ENCH_YOUR_STICKY_FLAME_I );
- else
- monster->enchantment[p]--;
- }
- break;
-
- case ENCH_SHORT_LIVED:
- // This should only be used for ball lightning -- bwr
- if (random2(1000) < mod_speed( 200, speed ))
- monster->hit_points = -1;
- break;
-
- // 19 is taken by summoning:
- // If these are changed, must also change abjuration
- case ENCH_ABJ_I:
- case ENCH_ABJ_II:
- case ENCH_ABJ_III:
- case ENCH_ABJ_IV:
- if (random2(1000) < mod_speed( 100, speed ))
- monster->enchantment[p]--;
-
- if (monster->enchantment[p] < ENCH_ABJ_I)
- {
- monster->enchantment[p] = ENCH_ABJ_I;
- monster_die(monster, KILL_RESET, 0);
- died = true;
- }
- break;
-
- case ENCH_ABJ_V:
- if (random2(1000) < mod_speed( 20, speed ))
- monster->enchantment[p] = ENCH_ABJ_IV;
- break;
-
- case ENCH_ABJ_VI:
- if (random2(1000) < mod_speed( 10, speed ))
- monster->enchantment[p] = ENCH_ABJ_V;
- break;
-
- case ENCH_CHARM:
- if (random2(500) <= mod_speed( monster->hit_dice + 10, speed ))
- mons_del_ench(monster, ENCH_CHARM);
- break;
-
- case ENCH_GLOWING_SHAPESHIFTER: // this ench never runs out
- // number of actions is fine for shapeshifters
- if (monster->type == MONS_GLOWING_SHAPESHIFTER
- || random2(1000) < mod_speed( 250, speed ))
- {
- monster_polymorph(monster, RANDOM_MONSTER, 0);
- }
- break;
-
- case ENCH_SHAPESHIFTER: // this ench never runs out
- if (monster->type == MONS_SHAPESHIFTER
- || random2(1000) < mod_speed( 1000 / ((15 * monster->hit_dice) / 5), speed ))
- {
- monster_polymorph(monster, RANDOM_MONSTER, 0);
- }
- break;
-
- case ENCH_TP_I:
- mons_del_ench( monster, ENCH_TP_I );
- monster_teleport( monster, true );
- break;
-
- case ENCH_TP_II:
- case ENCH_TP_III:
- case ENCH_TP_IV:
- tmp = mod_speed( 1000, speed );
-
- if (tmp < 1000 && random2(1000) < tmp)
- monster->enchantment[p]--;
- else if (monster->enchantment[p] - tmp / 1000 >= ENCH_TP_I)
- {
- monster->enchantment[p] -= tmp / 1000;
- tmp %= 1000;
-
- if (random2(1000) < tmp)
- {
- if (monster->enchantment[p] > ENCH_TP_I)
- monster->enchantment[p]--;
- else
- {
- mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV );
- monster_teleport( monster, true );
- }
- }
- }
- else
- {
- mons_del_ench( monster, ENCH_TP_I, ENCH_TP_IV );
- monster_teleport( monster, true );
- }
- break;
-
- case ENCH_SLEEP_WARY:
- if (random2(1000) < mod_speed( 50, speed ))
- mons_del_ench(monster, ENCH_SLEEP_WARY);
- break;
- }
- }
-
- return (died);
+ monster->apply_enchantments(speed);
+ return (!monster->alive());
} // end handle_enchantment()
//---------------------------------------------------------------
@@ -2277,7 +1932,7 @@ static void handle_nearby_ability(struct monsters *monster)
{
if (!mons_near( monster )
|| monster->behaviour == BEH_SLEEP
- || mons_has_ench( monster, ENCH_SUBMERGED ))
+ || monster->has_ench(ENCH_SUBMERGED))
{
return;
}
@@ -2332,7 +1987,7 @@ static void handle_nearby_ability(struct monsters *monster)
// XXX: We're being a bit player-centric here right now...
// really we should replace the grid_distance() check
// with one that checks for unaligned monsters as well. -- bwr
- if (mons_has_ench( monster, ENCH_SUBMERGED))
+ if (monster->has_ench(ENCH_SUBMERGED))
{
if (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
|| grd[monster->x][monster->y] == DNGN_BLUE_FOUNTAIN
@@ -2343,7 +1998,7 @@ static void handle_nearby_ability(struct monsters *monster)
|| (monster->hit_points > monster->max_hit_points / 2
&& coinflip()))))
{
- mons_del_ench( monster, ENCH_SUBMERGED );
+ monster->del_ench(ENCH_SUBMERGED);
}
}
else if (monster_can_submerge(monster->type,
@@ -2359,13 +2014,13 @@ static void handle_nearby_ability(struct monsters *monster)
|| monster->hit_points <= monster->max_hit_points / 2)
|| env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
- mons_add_ench( monster, ENCH_SUBMERGED );
+ monster->add_ench(ENCH_SUBMERGED);
}
break;
case MONS_AIR_ELEMENTAL:
if (one_chance_in(5))
- mons_add_ench( monster, ENCH_SUBMERGED );
+ monster->add_ench(ENCH_SUBMERGED);
break;
case MONS_PANDEMONIUM_DEMON:
@@ -2394,7 +2049,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
if (!mons_near( monster )
|| monster->behaviour == BEH_SLEEP
- || mons_has_ench( monster, ENCH_SUBMERGED ))
+ || monster->has_ench(ENCH_SUBMERGED))
{
return (false);
}
@@ -2458,7 +2113,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
break;
case MONS_LAVA_SNAKE:
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
if (!mons_player_visible( monster ))
@@ -2493,7 +2148,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
break;
case MONS_ELECTRICAL_EEL:
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
if (!mons_player_visible( monster ))
@@ -2531,7 +2186,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
case MONS_ACID_BLOB:
case MONS_OKLOB_PLANT:
case MONS_YELLOW_DRACONIAN:
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
if (!mons_player_visible( monster ))
@@ -2547,7 +2202,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
break;
// deliberate fall through
case MONS_FIEND:
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
// friendly fiends won't use torment, preferring hellfire
@@ -2610,7 +2265,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
if (!mons_player_visible( monster ))
break;
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
if (!mons_near(monster))
@@ -2664,7 +2319,7 @@ static bool handle_special_ability(struct monsters *monster, bolt & beem)
if (!mons_player_visible( monster ))
break;
- if (mons_has_ench(monster, ENCH_CONFUSION))
+ if (monster->has_ench(ENCH_CONFUSION))
break;
if ((monster->type != MONS_HELL_HOUND && random2(13) < 3)
@@ -2786,7 +2441,7 @@ static bool handle_reaching(struct monsters *monster)
if (mons_aligned(monster_index(monster), monster->foe))
return (false);
- if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ if (monster->has_ench(ENCH_SUBMERGED))
return (false);
if (wpn != NON_ITEM && get_weapon_brand( mitm[wpn] ) == SPWPN_REACHING )
@@ -2837,9 +2492,9 @@ static bool handle_reaching(struct monsters *monster)
static bool handle_scroll(struct monsters *monster)
{
// yes, there is a logic to this ordering {dlb}:
- if (mons_has_ench(monster, ENCH_CONFUSION)
+ if (monster->has_ench(ENCH_CONFUSION)
|| monster->behaviour == BEH_SLEEP
- || mons_has_ench( monster, ENCH_SUBMERGED ))
+ || monster->has_ench(ENCH_SUBMERGED))
{
return (false);
}
@@ -2855,7 +2510,7 @@ static bool handle_scroll(struct monsters *monster)
switch (mitm[monster->inv[MSLOT_SCROLL]].sub_type)
{
case SCR_TELEPORTATION:
- if (!mons_has_ench(monster, ENCH_TP_I, ENCH_TP_IV))
+ if (!monster->has_ench(ENCH_TP))
{
if (monster->behaviour == BEH_FLEE)
{
@@ -2883,7 +2538,7 @@ static bool handle_scroll(struct monsters *monster)
if (mons_near(monster))
{
simple_monster_message(monster, " reads a scroll.");
- create_monster( MONS_ABOMINATION_SMALL, ENCH_ABJ_II,
+ create_monster( MONS_ABOMINATION_SMALL, 2,
SAME_ATTITUDE(monster), monster->x, monster->y,
monster->foe, 250 );
read = true;
@@ -2916,7 +2571,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem)
return (false);
else if (!mons_near(monster))
return (false);
- else if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ else if (monster->has_ench(ENCH_SUBMERGED))
return (false);
else if (monster->inv[MSLOT_WAND] == NON_ITEM
|| mitm[monster->inv[MSLOT_WAND]].plus <= 0)
@@ -2980,7 +2635,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem)
// these are wands that monsters will aim at themselves {dlb}:
case WAND_HASTING:
- if (!mons_has_ench(monster, ENCH_HASTE))
+ if (!monster->has_ench(ENCH_HASTE))
{
beem.target_x = monster->x;
beem.target_y = monster->y;
@@ -3002,8 +2657,8 @@ static bool handle_wand(struct monsters *monster, bolt &beem)
return (false);
case WAND_INVISIBILITY:
- if (!mons_has_ench( monster, ENCH_INVIS )
- && !mons_has_ench( monster, ENCH_SUBMERGED )
+ if (!monster->has_ench(ENCH_INVIS)
+ && !monster->has_ench(ENCH_SUBMERGED)
&& (!mons_friendly(monster) || player_see_invis(false)))
{
beem.target_x = monster->x;
@@ -3017,7 +2672,7 @@ static bool handle_wand(struct monsters *monster, bolt &beem)
case WAND_TELEPORTATION:
if (monster->hit_points <= monster->max_hit_points / 2)
{
- if (!mons_has_ench(monster, ENCH_TP_I, ENCH_TP_IV)
+ if (!monster->has_ench(ENCH_TP)
&& !one_chance_in(20))
{
beem.target_x = monster->x;
@@ -3144,19 +2799,19 @@ static bool handle_spell( monsters *monster, bolt & beem )
if (monster->behaviour == BEH_SLEEP
|| (!mons_class_flag(monster->type, M_SPELLCASTER)
&& draco_breath == MS_NO_SPELL)
- || mons_has_ench( monster, ENCH_SUBMERGED ))
+ || monster->has_ench(ENCH_SUBMERGED))
{
return (false);
}
if ((mons_class_flag(monster->type, M_ACTUAL_SPELLS)
|| mons_class_flag(monster->type, M_PRIEST))
- && (mons_has_ench(monster, ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER)))
+ && (monster->has_ench(ENCH_GLOWING_SHAPESHIFTER, ENCH_SHAPESHIFTER)))
{
return (false); //jmf: shapeshiftes don't get spells, just
// physical powers.
}
- else if (mons_has_ench(monster, ENCH_CONFUSION)
+ else if (monster->has_ench(ENCH_CONFUSION)
&& !mons_class_flag(monster->type, M_CONFUSED))
{
return (false);
@@ -3467,7 +3122,7 @@ static bool handle_spell( monsters *monster, bolt & beem )
break;
case MONS_VAPOUR:
- mons_add_ench( monster, ENCH_SUBMERGED );
+ monster->add_ench(ENCH_SUBMERGED);
break;
case MONS_BRAIN_WORM:
@@ -3537,9 +3192,9 @@ static bool handle_spell( monsters *monster, bolt & beem )
static bool handle_throw(struct monsters *monster, bolt & beem)
{
// yes, there is a logic to this ordering {dlb}:
- if (mons_has_ench(monster, ENCH_CONFUSION)
+ if (monster->has_ench(ENCH_CONFUSION)
|| monster->behaviour == BEH_SLEEP
- || mons_has_ench( monster, ENCH_SUBMERGED ))
+ || monster->has_ench(ENCH_SUBMERGED))
{
return (false);
}
@@ -3603,8 +3258,8 @@ static bool handle_throw(struct monsters *monster, bolt & beem)
static bool handle_monster_spell(monsters *monster, bolt &beem)
{
// shapeshifters don't get spells
- if (!mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
- ENCH_SHAPESHIFTER )
+ if (!monster->has_ench( ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER )
|| !mons_class_flag( monster->type, M_ACTUAL_SPELLS ))
{
if (handle_spell(monster, beem))
@@ -3677,7 +3332,7 @@ static void handle_monster_move(int i, monsters *monster)
if (monster->speed == 0)
{
if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
- && !mons_has_ench( monster, ENCH_SUBMERGED ))
+ && !monster->has_ench(ENCH_SUBMERGED))
{
mons_in_cloud( monster );
}
@@ -3691,11 +3346,11 @@ static void handle_monster_move(int i, monsters *monster)
monster->foe_memory--;
if (monster->type == MONS_GLOWING_SHAPESHIFTER)
- mons_add_ench( monster, ENCH_GLOWING_SHAPESHIFTER );
+ monster->add_ench(ENCH_GLOWING_SHAPESHIFTER);
// otherwise there are potential problems with summonings
if (monster->type == MONS_SHAPESHIFTER)
- mons_add_ench( monster, ENCH_SHAPESHIFTER );
+ monster->add_ench(ENCH_SHAPESHIFTER);
// We reset batty monsters from wander to seek here, instead
// of in handle_behaviour() since that will be called with
@@ -3717,7 +3372,7 @@ static void handle_monster_move(int i, monsters *monster)
if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
- if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ if (monster->has_ench(ENCH_SUBMERGED))
break;
if (monster->type == -1)
@@ -3746,7 +3401,7 @@ static void handle_monster_move(int i, monsters *monster)
if (monster_can_submerge(monster->type, grd[monster->x][monster->y])
&& env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
- mons_add_ench( monster, ENCH_SUBMERGED );
+ monster->add_ench(ENCH_SUBMERGED);
}
if (monster->speed >= 100)
@@ -3779,7 +3434,7 @@ static void handle_monster_move(int i, monsters *monster)
if (mons_is_confused( monster )
|| (monster->type == MONS_AIR_ELEMENTAL
- && mons_has_ench( monster, ENCH_SUBMERGED )))
+ && monster->has_ench(ENCH_SUBMERGED)))
{
std::vector<coord_def> moves;
@@ -4036,7 +3691,7 @@ static bool handle_pickup(struct monsters *monster)
bool monsterNearby = mons_near(monster);
int item = NON_ITEM;
- if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ if (monster->has_ench(ENCH_SUBMERGED))
return (false);
if (monster->behaviour == BEH_SLEEP)
@@ -5191,7 +4846,8 @@ static void mons_in_cloud(struct monsters *monster)
if (mons_res_poison(monster) > 0)
return;
- poison_monster(monster, (env.cloud[wc].type == CLOUD_POISON));
+ poison_monster(monster,
+ env.cloud[wc].type == CLOUD_POISON? KC_YOU : KC_OTHER);
// If the monster got poisoned, wake it up.
wake = true;
@@ -5230,7 +4886,8 @@ static void mons_in_cloud(struct monsters *monster)
|| monster->type == MONS_DEATH_DRAKE)
return;
- poison_monster(monster, (env.cloud[wc].type == CLOUD_MIASMA));
+ poison_monster(monster,
+ (env.cloud[wc].type == CLOUD_MIASMA? KC_YOU : KC_OTHER));
if (monster->max_hit_points > 4 && coinflip())
monster->max_hit_points--;
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 2294ce549c..a7f85242c4 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -296,7 +296,7 @@ void mons_trap(struct monsters *monster)
}
if (apply_poison)
- poison_monster( monster, false );
+ poison_monster( monster, KC_OTHER );
// generate "fallen" projectile, where appropriate: {dlb}
if (random2(10) < 7)
@@ -400,7 +400,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
}
}
- create_monster( mons, ENCH_ABJ_V, SAME_ATTITUDE(monster),
+ create_monster( mons, 5, SAME_ATTITUDE(monster),
monster->x, monster->y, monster->foe, 250 );
}
return;
@@ -417,7 +417,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
- create_monster( RANDOM_MONSTER, ENCH_ABJ_V, SAME_ATTITUDE(monster),
+ create_monster( RANDOM_MONSTER, 5, SAME_ATTITUDE(monster),
monster->x, monster->y, monster->foe, 250 );
}
return;
@@ -427,7 +427,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
- create_monster( MONS_RAKSHASA_FAKE, ENCH_ABJ_III,
+ create_monster( MONS_RAKSHASA_FAKE, 3,
SAME_ATTITUDE(monster), monster->x, monster->y,
monster->foe, 250 );
}
@@ -443,10 +443,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 10 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
+ duration = cap_int(2 + monster->hit_dice / 10, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_COMMON), duration,
@@ -463,10 +460,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
case MS_SUMMON_DEMON_LESSER: // class 5 demons
sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
+ duration = cap_int(2 + monster->hit_dice / 5, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_LESSER), duration,
@@ -478,9 +472,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
case MS_SUMMON_UFETUBUS:
sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 5 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
+ duration = cap_int(2 + monster->hit_dice / 5, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
@@ -490,7 +482,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
return;
case MS_SUMMON_BEAST: // Geryon
- create_monster( MONS_BEAST, ENCH_ABJ_IV, SAME_ATTITUDE(monster),
+ create_monster( MONS_BEAST, 4, SAME_ATTITUDE(monster),
monster->x, monster->y, monster->foe, 250 );
return;
@@ -504,10 +496,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 4 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
+ duration = cap_int(2 + monster->hit_dice / 5, 6);
for (int i = 0; i < sumcount2; ++i)
create_monster(MONS_WANDERING_MUSHROOM, duration,
SAME_ATTITUDE(monster),
@@ -526,10 +515,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 4 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
+ duration = cap_int(2 + monster->hit_dice / 5, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
do
@@ -539,7 +525,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
while (mons_class_holiness(summonik) != MH_UNDEAD);
create_monster(summonik, duration, SAME_ATTITUDE(monster),
- you.x_pos, you.y_pos, monster->foe, 250);
+ monster->x, monster->y, monster->foe, 250);
}
return;
@@ -562,10 +548,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
sumcount2 = 1 + random2( monster->hit_dice / 10 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
+ duration = cap_int(2 + monster->hit_dice / 10, 6);
for (sumcount = 0; sumcount < sumcount2; sumcount++)
{
create_monster( summon_any_demon(DEMON_GREATER), duration,
@@ -585,9 +568,7 @@ void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
+ duration = cap_int(2 + monster->hit_dice / 10, 6);
{
std::vector<int> monsters;
@@ -776,13 +757,13 @@ void monster_teleport(struct monsters *monster, bool instan, bool silent)
{
if (!instan)
{
- if (mons_del_ench(monster, ENCH_TP_I, ENCH_TP_IV))
+ if (monster->del_ench(ENCH_TP))
{
if (!silent)
simple_monster_message(monster, " seems more stable.");
}
else
- mons_add_ench(monster, (coinflip() ? ENCH_TP_III : ENCH_TP_IV ));
+ monster->add_ench( mon_enchant(ENCH_TP, coinflip()? 3 : 4) );
return;
}
@@ -1880,8 +1861,6 @@ static unsigned char monster_abjuration(int pow, bool test)
for (int ab = 0; ab < MAX_MONSTERS && abjure_str; ab++)
{
- int abjLevel;
-
monster = &menv[ab];
if (monster->type == -1 || !mons_near(monster))
@@ -1890,8 +1869,8 @@ static unsigned char monster_abjuration(int pow, bool test)
if (!mons_friendly(monster))
continue;
- abjLevel = mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
- if (abjLevel == ENCH_NONE)
+ mon_enchant abjLevel = monster->get_ench(ENCH_ABJ);
+ if (abjLevel.ench == ENCH_NONE)
continue;
result++;
@@ -1899,15 +1878,14 @@ static unsigned char monster_abjuration(int pow, bool test)
if (test)
continue;
- abjLevel -= abjure_str;
+ abjLevel.degree -= abjure_str;
- if (abjLevel < ENCH_ABJ_I)
+ if (abjLevel.degree <= 0)
monster_die(monster, KILL_RESET, 0);
else
{
simple_monster_message(monster, " shudders.");
- mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
- mons_add_ench(monster, abjLevel);
+ monster->update_ench(abjLevel);
}
if (!(abjure_str = div_rand_round(abjure_str, 2)))
@@ -1930,7 +1908,7 @@ bool silver_statue_effects(monsters *mons)
create_monster( summon_any_demon((coinflip() ? DEMON_COMMON
: DEMON_LESSER)),
- ENCH_ABJ_V, BEH_HOSTILE,
+ 5, BEH_HOSTILE,
you.x_pos, you.y_pos,
MHITYOU, 250 );
return (true);
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 2de57145b7..462a38abae 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -2053,8 +2053,8 @@ int player_see_invis(bool calc_unid)
// to find if the square the monster is in is visible see mons_near().
bool player_monster_visible( const monsters *mon )
{
- if (mons_has_ench( mon, ENCH_SUBMERGED )
- || (mons_has_ench( mon, ENCH_INVIS ) && !player_see_invis()))
+ if (mon->has_ench(ENCH_SUBMERGED)
+ || (mon->has_ench(ENCH_INVIS) && !player_see_invis()))
{
return (false);
}
@@ -5203,3 +5203,8 @@ god_type player::deity() const
{
return (religion);
}
+
+kill_category player::kill_alignment() const
+{
+ return (KC_YOU);
+}
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index ca56d3888b..1d4f48e51d 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -965,23 +965,23 @@ void Xom_acts(bool niceness, int sever, bool force_sever)
dancing_weapon(100, true); // nasty, but fun
else
{
- create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster(MONS_NEQOXEC + random2(5), 3,
BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
if (one_chance_in(3))
- create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster(MONS_NEQOXEC + random2(5), 3,
BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
if (one_chance_in(4))
- create_monster(MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster(MONS_NEQOXEC + random2(5), 3,
BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
if (one_chance_in(3))
- create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III,
+ create_monster(MONS_HELLION + random2(10), 3,
BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
if (one_chance_in(4))
- create_monster(MONS_HELLION + random2(10), ENCH_ABJ_III,
+ create_monster(MONS_HELLION + random2(10), 3,
BEH_HOSTILE, you.x_pos, you.y_pos, MHITNOT, 250);
}
@@ -1061,31 +1061,31 @@ void Xom_acts(bool niceness, int sever, bool force_sever)
(temp_rand == 1) ? "Xom grants you some temporary aid."
: "Xom opens a gate.");
- create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster( MONS_NEQOXEC + random2(5), 3,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
- create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster( MONS_NEQOXEC + random2(5), 3,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
if (random2( you.experience_level ) >= 8)
{
- create_monster( MONS_NEQOXEC + random2(5), ENCH_ABJ_III,
+ create_monster( MONS_NEQOXEC + random2(5), 3,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
}
if (random2( you.experience_level ) >= 8)
{
- create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III,
+ create_monster( MONS_HELLION + random2(10), 3,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
}
if (random2( you.experience_level ) >= 8)
{
- create_monster( MONS_HELLION + random2(10), ENCH_ABJ_III,
+ create_monster( MONS_HELLION + random2(10), 3,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
}
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 81abfc781b..f4697c7e52 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -654,30 +654,18 @@ void abjuration(int pow)
{
monster = &menv[ab];
- int abjLevel;
-
if (monster->type == -1 || !mons_near(monster))
continue;
if (mons_friendly(monster))
continue;
- abjLevel = mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
- if (abjLevel != ENCH_NONE)
- {
- abjLevel -= 1 + (random2(pow) / 8);
-
- if (abjLevel < ENCH_ABJ_I)
- {
- mons_add_ench(monster, ENCH_ABJ_I);
- monster_die(monster, KILL_RESET, 0);
- }
- else
- {
- simple_monster_message(monster, " shudders.");
- mons_add_ench(monster, abjLevel);
- }
- }
+ mon_enchant abj = monster->get_ench(ENCH_ABJ);
+ if (abj.ench != ENCH_NONE)
+ monster->lose_ench_levels(abj, 1 + (random2(pow) / 8));
+
+ if (monster->has_ench(ENCH_ABJ))
+ simple_monster_message(monster, " shudders.");
}
} // end abjuration()
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 457bbd72e9..6975c80d32 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -749,7 +749,7 @@ void turn_undead(int pow)
continue;
}
- if (!mons_add_ench(monster, ENCH_FEAR))
+ if (!monster->add_ench(ENCH_FEAR))
continue;
simple_monster_message( monster, " is repelled!" );
@@ -800,7 +800,7 @@ void holy_word(int pow, bool silent)
if (monster->speed_increment >= 25)
monster->speed_increment -= 20;
- mons_add_ench(monster, ENCH_FEAR);
+ monster->add_ench(ENCH_FEAR);
} // end "if mons_holiness"
} // end "for tu"
} // end holy_word()
@@ -837,12 +837,12 @@ void cast_toxic_radiance(void)
if (monster->type != -1 && mons_near(monster))
{
- if (!mons_has_ench(monster, ENCH_INVIS))
+ if (!monster->has_ench(ENCH_INVIS))
{
- poison_monster(monster, true);
+ poison_monster(monster, KC_YOU);
if (coinflip()) // 50-50 chance for a "double hit" {dlb}
- poison_monster(monster, true);
+ poison_monster(monster, KC_YOU);
}
else if (player_see_invis())
@@ -920,7 +920,7 @@ void cast_refrigeration(int pow)
//jmf: "slow snakes" finally available
if (mons_class_flag( monster->type, M_COLD_BLOOD ) && coinflip())
- mons_add_ench(monster, ENCH_SLOW);
+ monster->add_ench(ENCH_SLOW);
}
}
}
@@ -1157,7 +1157,7 @@ char burn_freeze(int pow, char flavour)
if (mons_class_flag( monster->type, M_COLD_BLOOD )
&& coinflip())
{
- mons_add_ench(monster, ENCH_SLOW);
+ monster->add_ench(ENCH_SLOW);
}
const int cold_res = mons_res_cold( monster );
@@ -1189,10 +1189,7 @@ int summon_elemental(int pow, int restricted_type,
int targ_x;
int targ_y;
- int numsc = ENCH_ABJ_II + (random2(pow) / 5);
-
- if (numsc > ENCH_ABJ_VI)
- numsc = ENCH_ABJ_VI;
+ int numsc = cap_int(2 + (random2(pow) / 5), 6);
for (;;)
{
@@ -1356,7 +1353,7 @@ void summon_small_mammals(int pow)
break;
}
- create_monster( thing_called, ENCH_ABJ_III, BEH_FRIENDLY,
+ create_monster( thing_called, 3, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 );
}
} // end summon_small_mammals()
@@ -1371,7 +1368,7 @@ void summon_scorpions(int pow)
{
if (random2(pow) <= 3)
{
- if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_HOSTILE,
+ if (create_monster( MONS_SCORPION, 3, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
mpr("A scorpion appears. It doesn't look very happy.");
@@ -1379,7 +1376,7 @@ void summon_scorpions(int pow)
}
else
{
- if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_FRIENDLY,
+ if (create_monster( MONS_SCORPION, 3, BEH_FRIENDLY,
you.x_pos, you.y_pos,
you.pet_target, 250 ) != -1)
{
@@ -1391,12 +1388,9 @@ void summon_scorpions(int pow)
void summon_ice_beast_etc(int pow, int ibc, bool divine_gift)
{
- int numsc = ENCH_ABJ_II + (random2(pow) / 4);
+ int numsc = cap_int(2 + (random2(pow) / 4), 6);
int beha = divine_gift? BEH_GOD_GIFT : BEH_FRIENDLY;
- if (numsc > ENCH_ABJ_VI)
- numsc = ENCH_ABJ_VI;
-
switch (ibc)
{
case MONS_ICE_BEAST:
@@ -1504,7 +1498,7 @@ bool summon_swarm( int pow, bool unfriendly, bool god_gift )
else if (!unfriendly && random2(pow) > 7)
behaviour = BEH_FRIENDLY;
- if (create_monster( thing_called, ENCH_ABJ_III, behaviour,
+ if (create_monster( thing_called, 3, behaviour,
you.x_pos, you.y_pos, MHITYOU, 250 ))
{
summoned = true;
@@ -1534,7 +1528,7 @@ void summon_undead(int pow)
if (random2(pow) < 6)
{
- if (create_monster( thing_called, ENCH_ABJ_V, BEH_HOSTILE,
+ if (create_monster( thing_called, 5, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
mpr("You sense a hostile presence.");
@@ -1542,7 +1536,7 @@ void summon_undead(int pow)
}
else
{
- if (create_monster( thing_called, ENCH_ABJ_V, BEH_FRIENDLY,
+ if (create_monster( thing_called, 5, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 ) != -1)
{
mpr("An insubstantial figure forms in the air.");
@@ -1588,7 +1582,7 @@ void summon_things( int pow )
while (big_things > 0)
{
- create_monster( MONS_TENTACLED_MONSTROSITY, ENCH_ABJ_VI,
+ create_monster( MONS_TENTACLED_MONSTROSITY, 6,
BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 );
big_things--;
@@ -1596,7 +1590,7 @@ void summon_things( int pow )
while (numsc > 0)
{
- create_monster( MONS_ABOMINATION_LARGE, ENCH_ABJ_VI, BEH_FRIENDLY,
+ create_monster( MONS_ABOMINATION_LARGE, 6, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 );
numsc--;
}
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index ecf1d28b04..b5a19d385c 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -401,7 +401,7 @@ void simulacrum(int power)
for (int i = 0; i < max_num; i++)
{
- if (create_monster( MONS_SIMULACRUM_SMALL, ENCH_ABJ_VI,
+ if (create_monster( MONS_SIMULACRUM_SMALL, 6,
BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, mons_type ) != -1)
{
@@ -428,12 +428,9 @@ void simulacrum(int power)
void dancing_weapon(int pow, bool force_hostile)
{
- int numsc = ENCH_ABJ_II + (random2(pow) / 5);
+ int numsc = cap_int(2 + (random2(pow) / 5), 6);
char str_pass[ ITEMNAME_SIZE ];
- if (numsc > ENCH_ABJ_VI)
- numsc = ENCH_ABJ_VI;
-
int i;
int summs = 0;
char behavi = BEH_FRIENDLY;
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 341bc90502..1575e8cc12 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -616,7 +616,7 @@ void cast_summon_butterflies(int pow)
for (int scount = 1; scount < num; scount++)
{
- create_monster( MONS_BUTTERFLY, ENCH_ABJ_III, BEH_FRIENDLY,
+ create_monster( MONS_BUTTERFLY, 3, BEH_FRIENDLY,
you.x_pos, you.y_pos, MHITYOU, 250 );
}
}
@@ -654,22 +654,16 @@ void cast_summon_large_mammal(int pow)
}
}
- create_monster( mon, ENCH_ABJ_III, BEH_FRIENDLY, you.x_pos, you.y_pos,
+ create_monster( mon, 3, BEH_FRIENDLY, you.x_pos, you.y_pos,
you.pet_target, 250 );
}
void cast_sticks_to_snakes(int pow)
{
int mon, i, behaviour;
-
int how_many = 0;
-
int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4;
-
- int dur = ENCH_ABJ_III + random2(pow) / 20;
- if (dur > ENCH_ABJ_V)
- dur = ENCH_ABJ_V;
-
+ int dur = cap_int(3 + random2(pow) / 20, 5);
const int weapon = you.equip[EQ_WEAPON];
if (weapon == -1)
@@ -790,7 +784,7 @@ void cast_summon_dragon(int pow)
// a very high level spell so it might be okay). -- bwr
happy = (random2(pow) > 5);
- if (create_monster( MONS_DRAGON, ENCH_ABJ_III,
+ if (create_monster( MONS_DRAGON, 3,
(happy ? BEH_FRIENDLY : BEH_HOSTILE),
you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
{
@@ -844,7 +838,7 @@ void cast_conjure_ball_lightning( int pow )
if (mon != -1)
{
- mons_add_ench( &menv[mon], ENCH_SHORT_LIVED );
+ menv[mon].add_ench(ENCH_SHORT_LIVED);
summoned = true;
}
}
@@ -869,13 +863,13 @@ static int sleep_monsters(int x, int y, int pow, int garbage)
//jmf: now that sleep == hibernation:
if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip()) return 0;
- if (mons_has_ench( &menv[mnstr], ENCH_SLEEP_WARY )) return 0;
+ if (menv[mnstr].has_ench(ENCH_SLEEP_WARY)) return 0;
menv[mnstr].behaviour = BEH_SLEEP;
- mons_add_ench( &menv[mnstr], ENCH_SLEEP_WARY );
+ menv[mnstr].add_ench(ENCH_SLEEP_WARY);
if (mons_class_flag( menv[mnstr].type, M_COLD_BLOOD ) && coinflip())
- mons_add_ench( &menv[mnstr], ENCH_SLOW );
+ menv[mnstr].add_ench(ENCH_SLOW);
return 1;
} // end sleep_monsters()
@@ -919,7 +913,7 @@ static int tame_beast_monsters(int x, int y, int pow, int garbage)
if (random2(100) < random2(pow / 10))
monster->attitude = ATT_FRIENDLY; // permanent, right?
else
- mons_add_ench(monster, ENCH_CHARM);
+ monster->add_ench(ENCH_CHARM);
return 1;
} // end tame_beast_monsters()
@@ -1036,15 +1030,10 @@ static int ignite_poison_monsters(int x, int y, int pow, int garbage)
int strength = 0;
// first check for player poison:
- int ench = mons_has_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
- if (ench != ENCH_NONE)
- strength += ench - ENCH_YOUR_POISON_I + 1;
-
- // ... now monster poison:
- ench = mons_has_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
- if (ench != ENCH_NONE)
- strength += ench - ENCH_POISON_I + 1;
-
+ mon_enchant ench = mon->get_ench(ENCH_POISON);
+ if (ench.ench != ENCH_NONE)
+ strength += ench.degree;
+
// strength is now the sum of both poison types (although only
// one should actually be present at a given time):
dam_dice.num += strength;
@@ -1062,9 +1051,7 @@ static int ignite_poison_monsters(int x, int y, int pow, int garbage)
if (!player_hurt_monster( mon_index, damage ))
{
// Monster survived, remove any poison.
- mons_del_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
- mons_del_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
-
+ mon->del_ench(ENCH_POISON);
behaviour_event( mon, ME_ALERT );
}
@@ -1720,7 +1707,7 @@ static int intoxicate_monsters(int x, int y, int pow, int garbage)
if (mons_res_poison(&menv[mon]) > 0)
return 0;
- mons_add_ench(&menv[mon], ENCH_CONFUSION);
+ menv[mon].add_ench(ENCH_CONFUSION);
return 1;
} // end intoxicate_monsters()
@@ -1782,15 +1769,15 @@ static int glamour_monsters(int x, int y, int pow, int garbage)
switch (random2(6))
{
case 0:
- mons_add_ench(&menv[mon], ENCH_FEAR);
+ menv[mon].add_ench(ENCH_FEAR);
break;
case 1:
case 4:
- mons_add_ench(&menv[mon], ENCH_CONFUSION);
+ menv[mon].add_ench(ENCH_CONFUSION);
break;
case 2:
case 5:
- mons_add_ench(&menv[mon], ENCH_CHARM);
+ menv[mon].add_ench(ENCH_CHARM);
break;
case 3:
menv[mon].behaviour = BEH_SLEEP;
@@ -1874,22 +1861,23 @@ bool backlight_monsters(int x, int y, int pow, int garbage)
break;
}
- int lvl = mons_has_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV );
+ mon_enchant bklt = menv[mon].get_ench(ENCH_BACKLIGHT);
+ int lvl = bklt.degree;
- if (lvl == ENCH_NONE)
+ if (lvl == 0)
simple_monster_message( &menv[mon], " is outlined in light." );
- else if (lvl == ENCH_BACKLIGHT_IV)
+ else if (lvl == 4)
simple_monster_message( &menv[mon], " glows brighter for a moment." );
else
{
// remove old level
- mons_del_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_III, true );
+ menv[mon].del_ench(ENCH_BACKLIGHT, true);
simple_monster_message( &menv[mon], " glows brighter." );
}
// this enchantment wipes out invisibility (neat)
- mons_del_ench( &menv[mon], ENCH_INVIS );
- mons_add_ench( &menv[mon], ENCH_BACKLIGHT_IV );
+ menv[mon].del_ench(ENCH_INVIS);
+ menv[mon].add_ench(ENCH_BACKLIGHT);
return (true);
} // end backlight_monsters()
@@ -2220,17 +2208,9 @@ static int rot_living(int x, int y, int pow, int message)
return 0;
ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
+ ench = 1 + (ench >= 20) + (ench >= 35) + (ench >= 50);
- if (ench >= 50)
- ench = ENCH_YOUR_ROT_IV;
- else if (ench >= 35)
- ench = ENCH_YOUR_ROT_III;
- else if (ench >= 20)
- ench = ENCH_YOUR_ROT_II;
- else
- ench = ENCH_YOUR_ROT_I;
-
- mons_add_ench(&menv[mon], ench);
+ menv[mon].add_ench( mon_enchant(ENCH_ROT, ench) );
return 1;
} // end rot_living()
@@ -2286,17 +2266,9 @@ static int rot_undead(int x, int y, int pow, int garbage)
}
ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
+ ench = 1 + (ench >= 20) + (ench >= 35) + (ench >= 50);
- if (ench >= 50)
- ench = ENCH_YOUR_ROT_IV;
- else if (ench >= 35)
- ench = ENCH_YOUR_ROT_III;
- else if (ench >= 20)
- ench = ENCH_YOUR_ROT_II;
- else
- ench = ENCH_YOUR_ROT_I;
-
- mons_add_ench(&menv[mon], ench);
+ menv[mon].add_ench( mon_enchant(ENCH_ROT, ench) );
return 1;
} // end rot_undead()
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 87f7318d8c..d9c6690a3a 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -1465,7 +1465,7 @@ int your_spells( int spc2, int powc, bool allow_fail )
if (dem_hor == BEH_CHARMED)
mpr("You don't feel so good about this...");
- create_monster( summon_any_demon(DEMON_GREATER), ENCH_ABJ_V, dem_hor,
+ create_monster( summon_any_demon(DEMON_GREATER), 5, dem_hor,
you.x_pos, you.y_pos, MHITYOU, 250 );
break;
@@ -1671,7 +1671,7 @@ int your_spells( int spc2, int powc, bool allow_fail )
{
mpr( "Wisps of shadow whirl around you..." );
const int which_mons =
- create_monster( RANDOM_MONSTER, ENCH_ABJ_II, BEH_FRIENDLY,
+ create_monster( RANDOM_MONSTER, 2, BEH_FRIENDLY,
you.x_pos, you.y_pos, you.pet_target, 250 );
if (which_mons != -1 && which_mons != NON_MONSTER)
menv[which_mons].flags |= MF_HARD_RESET;
@@ -2287,7 +2287,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
break;
case 5:
mpr("Space twists in upon itself!");
- create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE,
+ create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 );
break;
}
@@ -2319,7 +2319,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
for (loopj = 0; loopj < 2 + random2(3); loopj++)
{
- create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III,
+ create_monster( MONS_SPATIAL_VORTEX, 3,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
}
@@ -2411,13 +2411,13 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
case 3:
mpr("Space twists in upon itself!");
- create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III, BEH_HOSTILE,
+ create_monster( MONS_SPATIAL_VORTEX, 3, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 );
break;
case 4:
case 5:
- if (create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ if (create_monster( summon_any_demon(DEMON_LESSER), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 ) != -1)
{
@@ -2434,7 +2434,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
for (loopj = 0; loopj < 2 + random2(3); loopj++)
{
- create_monster( MONS_SPATIAL_VORTEX, ENCH_ABJ_III,
+ create_monster( MONS_SPATIAL_VORTEX, 3,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
}
@@ -2442,7 +2442,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
case 1:
case 2:
- if (create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_V,
+ if (create_monster( summon_any_demon(DEMON_COMMON), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250) != -1)
{
@@ -2454,24 +2454,24 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
case 4:
case 5:
mpr("A chorus of chattering voices calls out to you!");
- create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ create_monster( summon_any_demon(DEMON_LESSER), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
- create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ create_monster( summon_any_demon(DEMON_LESSER), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
if (coinflip())
{
- create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ create_monster( summon_any_demon(DEMON_LESSER), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
}
if (coinflip())
{
- create_monster( summon_any_demon(DEMON_LESSER), ENCH_ABJ_V,
+ create_monster( summon_any_demon(DEMON_LESSER), 5,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
}
@@ -2502,17 +2502,17 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
case 2:
mpr("Something turns its malign attention towards you...");
- create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ create_monster( summon_any_demon(DEMON_COMMON), 3,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250 );
- create_monster( summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ create_monster( summon_any_demon(DEMON_COMMON), 3,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250);
if (coinflip())
{
- create_monster(summon_any_demon(DEMON_COMMON), ENCH_ABJ_III,
+ create_monster(summon_any_demon(DEMON_COMMON), 3,
BEH_HOSTILE, you.x_pos, you.y_pos,
MHITYOU, 250);
}
@@ -2711,18 +2711,18 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
case 0:
mpr("Flickering shadows surround you.");
- create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ create_monster( MONS_SHADOW, 2, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 );
if (coinflip())
{
- create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ create_monster( MONS_SHADOW, 2, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 );
}
if (coinflip())
{
- create_monster( MONS_SHADOW, ENCH_ABJ_II, BEH_HOSTILE,
+ create_monster( MONS_SHADOW, 2, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250 );
}
break;
@@ -2783,7 +2783,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
break;
case 4:
- if (create_monster( MONS_SOUL_EATER, ENCH_ABJ_IV, BEH_HOSTILE,
+ if (create_monster( MONS_SOUL_EATER, 4, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250) != -1)
{
mpr("Something reaches out for you...");
@@ -2791,7 +2791,7 @@ bool miscast_effect( unsigned int sp_type, int mag_pow, int mag_fail,
break;
case 5:
- if (create_monster( MONS_REAPER, ENCH_ABJ_IV, BEH_HOSTILE,
+ if (create_monster( MONS_REAPER, 4, BEH_HOSTILE,
you.x_pos, you.y_pos, MHITYOU, 250) != -1)
{
mpr("Death has come for you...");
diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h
index fb55be530e..9c958361a1 100644
--- a/crawl-ref/source/stuff.h
+++ b/crawl-ref/source/stuff.h
@@ -107,8 +107,12 @@ inline bool testbits(unsigned long flags, unsigned long test)
return ((flags & test) == test);
}
-bool is_trap_square(int x, int y);
+inline int cap_int(int val, int cap)
+{
+ return (val > cap? cap : val);
+}
+bool is_trap_square(int x, int y);
void zap_los_monsters();
#endif
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index ebf7587c2c..9b1125d44c 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1409,6 +1409,22 @@ static void tag_construct_level_items(struct tagHeader &th)
marshall_item(th, mitm[i]);
}
+static void marshall_mon_enchant(tagHeader &th, const mon_enchant &me)
+{
+ marshallShort(th, me.ench);
+ marshallShort(th, me.degree);
+ marshallShort(th, me.who);
+}
+
+static mon_enchant unmarshall_mon_enchant(tagHeader &th)
+{
+ mon_enchant me;
+ me.ench = static_cast<enchant_type>( unmarshallShort(th) );
+ me.degree = unmarshallShort(th);
+ me.who = static_cast<kill_category>( unmarshallShort(th) );
+ return (me);
+}
+
static void marshall_monster(tagHeader &th, const monsters &m)
{
marshallByte(th, m.ac);
@@ -1423,8 +1439,12 @@ static void marshall_monster(tagHeader &th, const monsters &m)
marshallByte(th, m.target_y);
marshallLong(th, m.flags);
- for (int j = 0; j < NUM_MON_ENCHANTS; j++)
- marshallByte(th, m.enchantment[j]);
+ marshallShort(th, m.enchantments.size());
+ for (mon_enchant_list::const_iterator i = m.enchantments.begin();
+ i != m.enchantments.end(); ++i)
+ {
+ marshall_mon_enchant(th, *i);
+ }
marshallShort(th, m.type);
marshallShort(th, m.hit_points);
@@ -1457,8 +1477,6 @@ static void tag_construct_level_monsters(struct tagHeader &th)
// how many monsters?
marshallShort(th, MAX_MONSTERS);
- // how many monster enchantments?
- marshallByte(th, NUM_MON_ENCHANTS);
// how many monster inventory slots?
marshallByte(th, NUM_MONSTER_SLOTS);
@@ -1574,8 +1592,9 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
m.target_y = unmarshallByte(th);
m.flags = unmarshallLong(th);
- for (int j = 0; j < NUM_MON_ENCHANTS; j++)
- m.enchantment[j] = unmarshallByte(th);
+ const int nenchs = unmarshallShort(th);
+ for (int i = 0; i < nenchs; ++i)
+ m.enchantments.insert( unmarshall_mon_enchant(th) );
m.type = unmarshallShort(th);
m.hit_points = unmarshallShort(th);
@@ -1599,7 +1618,7 @@ static void unmarshall_monster(tagHeader &th, monsters &m)
static void tag_read_level_monsters(struct tagHeader &th, char minorVersion)
{
int i;
- int count, ecount, icount;
+ int count, icount;
// how many mons_alloc?
count = unmarshallByte(th);
@@ -1608,8 +1627,6 @@ static void tag_read_level_monsters(struct tagHeader &th, char minorVersion)
// how many monsters?
count = unmarshallShort(th);
- // how many monster enchantments?
- ecount = unmarshallByte(th);
// how many monster inventory slots?
icount = unmarshallByte(th);
@@ -1675,7 +1692,7 @@ void tag_missing_level_attitude()
new_beh = BEH_SEEK;
break;
case 7: // old BEH_ENSLAVED
- if (!mons_has_ench(&menv[i], ENCH_CHARM))
+ if (!menv[i].has_ench(ENCH_CHARM))
isFriendly = true;
break;
default:
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index cd5d8fcaa1..e7b444efa1 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -729,7 +729,7 @@ bool check_awaken(int mons_aw)
if (mon_holy == MH_NATURAL)
{
// monster is "hibernating"... reduce chance of waking
- if (mons_has_ench( monster, ENCH_SLEEP_WARY ))
+ if (monster->has_ench(ENCH_SLEEP_WARY))
mons_perc -= 10;
}
else // unnatural creature