summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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