summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/directn.cc2
-rw-r--r--crawl-ref/source/enum.h36
-rw-r--r--crawl-ref/source/fight.cc26
-rw-r--r--crawl-ref/source/mon-data.h35
-rw-r--r--crawl-ref/source/mon-pick.cc4
-rw-r--r--crawl-ref/source/mon-util.cc8
-rw-r--r--crawl-ref/source/mon-util.h11
-rw-r--r--crawl-ref/source/monplace.cc15
-rw-r--r--crawl-ref/source/monplace.h3
-rw-r--r--crawl-ref/source/ouch.cc79
-rw-r--r--crawl-ref/source/ouch.h2
11 files changed, 137 insertions, 84 deletions
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index ba3f2df750..16725bf3ed 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -2797,7 +2797,7 @@ static void _describe_monster(const monsters *mon)
{
// special case: batty monsters get set to BEH_WANDER as
// part of their special behaviour.
- if (!testbits(mon->flags, MF_BATTY))
+ if (!mons_is_batty(mon))
{
mprf(MSGCH_EXAMINE, "%s doesn't appear to have noticed you.",
mon->pronoun(PRONOUN_CAP).c_str());
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 9ab78972e6..b15edfa7da 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -248,6 +248,7 @@ enum beam_type // beam[].flavour
BEAM_POTION_RANDOM,
BEAM_TORMENT_DAMAGE, // Pseudo-beam for damage flavour.
+ BEAM_STEAL_FOOD, // Pseudo-beam for harpyes stealing food.
BEAM_LINE_OF_SIGHT // only used for checking monster LOS
};
@@ -1739,6 +1740,7 @@ enum monster_type // (int) menv[].type
MONS_MERMAID,
MONS_SIREN, // 195
MONS_FLAMING_CORPSE,
+ MONS_HARPY, // 197
//jmf: end new monsters
MONS_WHITE_IMP = 220, // 220
MONS_LEMURE,
@@ -2003,31 +2005,31 @@ enum mon_flight_type
enum monster_flag_type
{
MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
- MF_BATTY = 0x02, // flutters like a bat
- MF_JUST_SUMMONED = 0x04, // monster skips next available action
- MF_TAKING_STAIRS = 0x08, // is following player through stairs
+ MF_JUST_SUMMONED = 0x02, // monster skips next available action
+ MF_TAKING_STAIRS = 0x04, // is following player through stairs
+ MF_INTERESTING = 0x08, // Player finds monster interesting
- MF_INTERESTING = 0x10, // Player finds monster interesting
- MF_SEEN = 0x20, // Player has already seen monster
- MF_DIVINE_PROTECTION = 0x40, // Monster has divine protection.
-
- MF_KNOWN_MIMIC = 0x80, // Mimic that has taken a swing at the PC,
+ MF_SEEN = 0x10, // Player has already seen monster
+ MF_DIVINE_PROTECTION = 0x20, // Monster has divine protection.
+ MF_KNOWN_MIMIC = 0x40, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
- MF_BANISHED = 0x100, // Monster that has been banished.
- MF_HARD_RESET = 0x200, // Summoned, should not drop gear on reset
- MF_WAS_NEUTRAL = 0x400, // mirror to CREATED_FRIENDLY for neutrals
- MF_ATT_CHANGE_ATTEMPT = 0x800, // Saw player and attitude changed (or
+ MF_BANISHED = 0x80, // Monster that has been banished.
+
+ MF_HARD_RESET = 0x100, // Summoned, should not drop gear on reset
+ MF_WAS_NEUTRAL = 0x200, // mirror to CREATED_FRIENDLY for neutrals
+ MF_ATT_CHANGE_ATTEMPT = 0x400, // Saw player and attitude changed (or
// not); currently used for holy beings
// (good god worshippers -> neutral)
// and orcs (Beogh worshippers -> friendly)
- MF_WAS_IN_VIEW = 0x1000, // Was in view during previous turn
- MF_BAND_MEMBER = 0x2000, // Created as a member of a band
- MF_GOT_HALF_XP = 0x4000, // Player already got half xp value earlier
- MF_HONORARY_UNDEAD = 0x8000, // Consider this monster to have MH_UNDEAD
+ MF_WAS_IN_VIEW = 0x800, // Was in view during previous turn.
+
+ MF_BAND_MEMBER = 0x1000, // Created as a member of a band
+ MF_GOT_HALF_XP = 0x2000, // Player already got half xp value earlier
+ MF_HONORARY_UNDEAD = 0x4000, // Consider this monster to have MH_UNDEAD
// holiness, regardless of its actual type;
// currently used for abominations created
// via Twisted Resurrection
- MF_ENSLAVED_SOUL = 0x10000 // An undead monster soul enslaved by
+ MF_ENSLAVED_SOUL = 0x8000 // An undead monster soul enslaved by
// Yredelemnul's power, or the natural
// monster from whom the soul is taken
};
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index a47588edb9..c3a7af0c45 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -2179,7 +2179,7 @@ static bool _can_clone(const actor *defender, coord_def *pos, int *midx)
return (false);
}
- return (true);
+ return (true);
}
static bool _do_clone(monsters* orig, coord_def pos, int midx)
@@ -2321,7 +2321,7 @@ void melee_attack::chaos_affects_defender()
ASSERT(can_poly);
beam.flavour = BEAM_POLYMORPH;
break;
-
+
case CHAOS_POLY_UP:
ASSERT(can_poly);
ASSERT(defender->atype() == ACT_MONSTER);
@@ -2329,7 +2329,7 @@ void melee_attack::chaos_affects_defender()
obvious_effect = you.can_see(defender);
monster_polymorph(def, RANDOM_MONSTER, PPT_MORE, true);
break;
-
+
case CHAOS_MAKE_SHIFTER:
ASSERT(can_poly);
ASSERT(!is_shifter);
@@ -2341,11 +2341,11 @@ void melee_attack::chaos_affects_defender()
// Immediately polymorph monster, just to make the effect obvious.
monster_polymorph(def, RANDOM_MONSTER, PPT_SAME, true);
break;
-
+
case CHAOS_HEAL:
beam.flavour = BEAM_HEALING;
break;
-
+
case CHAOS_HASTE:
beam.flavour = BEAM_HASTE;
break;
@@ -4194,6 +4194,22 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
case AF_CHAOS:
chaos_affects_defender();
break;
+
+ case AF_STEAL_FOOD:
+ // Monsters don't carry food.
+ if (defender->atype() != ACT_PLAYER)
+ break;
+
+ // Only use this attack sometimes.
+ if (!one_chance_in(3))
+ break;
+
+ if (expose_player_to_element(BEAM_STEAL_FOOD, 10) && needs_message)
+ {
+ mprf("%s steals some of your food!",
+ atk_name(DESC_CAP_THE).c_str());
+ }
+ break;
}
}
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 35a30cade6..2964d3971e 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -169,20 +169,29 @@ static inline mon_energy_usage MISSILE_ENERGY(int ae)
static monsterentry mondata[] = {
// monster 250: The Thing That Should Not Be(tm)
-// do not remove, or seekmonster will crash on unknown mc request
-// it is also a good prototype for new monsters
+// NOTE: Do not remove, or seekmonster will crash on unknown mc request!
+// It is also a good prototype for new monsters.
{
+ // id, glyph, colour, name
MONS_PROGRAM_BUG, 'B', LIGHTRED, "program bug",
+ // monster flags
M_NO_EXP_GAIN,
+ // resistance flags
MR_NO_FLAGS,
+ // mass, xp modifier, genus, species, holiness, magic resistance
0, 10, MONS_PROGRAM_BUG, MONS_PROGRAM_BUG, MH_NATURAL, -3,
+ // up to four attacks
{ AT_NO_ATK, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+ // hit points
{ 0, 0, 0, 0 },
+ // AC, EV, spells, corpse type, zombie size, shout type, intelligence
0, 0, MST_NO_SPELLS, CE_CONTAMINATED, Z_NOZOMBIE, S_SILENT, I_PLANT,
+ // habitat, speed, energy usage, use type, body size
HT_LAND, 0, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_HUGE
},
-// real monsters begin here {dlb}:
+// Real monsters begin here {dlb}:
+
// insects ('a')
{
MONS_GIANT_COCKROACH, 'a', BROWN, "giant cockroach",
@@ -220,7 +229,7 @@ static monsterentry mondata[] = {
// batty monsters ('b')
{
MONS_GIANT_BAT, 'b', LIGHTGREY, "giant bat",
- M_FLIES | M_SENSE_INVIS | M_WARM_BLOOD,
+ M_FLIES | M_SENSE_INVIS | M_WARM_BLOOD | M_BATTY,
MR_NO_FLAGS,
150, 4, MONS_GIANT_BAT, MONS_GIANT_BAT, MH_NATURAL, -1,
{ {AT_HIT, AF_PLAIN, 1}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -985,7 +994,7 @@ static monsterentry mondata[] = {
},
{
- MONS_MERMAID, 'm', LIGHTCYAN, "cyan",
+ MONS_MERMAID, 'm', CYAN, "mermaid",
M_SPELLCASTER | M_WARM_BLOOD | M_SPEAKS,
MR_RES_POISON | MR_RES_COLD,
500, 10, MONS_MERMAID, MONS_MERMAID, MH_NATURAL, -5,
@@ -1488,7 +1497,7 @@ static monsterentry mondata[] = {
// small abominations ('x')
{
MONS_UNSEEN_HORROR, 'x', MAGENTA, "unseen horror",
- M_SEE_INVIS | M_INVIS,
+ M_SEE_INVIS | M_INVIS | M_BATTY,
MR_NO_FLAGS,
0, 12, MONS_UNSEEN_HORROR, MONS_UNSEEN_HORROR, MH_NATURAL, -3,
{ {AT_HIT, AF_PLAIN, 12}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -1533,7 +1542,7 @@ static monsterentry mondata[] = {
{
MONS_GIANT_BLOWFLY, 'y', LIGHTGREY, "giant blowfly",
- M_FLIES,
+ M_FLIES | M_BATTY,
MR_VUL_POISON,
200, 10, MONS_GIANT_BLOWFLY, MONS_GIANT_BLOWFLY, MH_NATURAL, -3,
{ {AT_BITE, AF_PLAIN, 13}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
@@ -2146,6 +2155,18 @@ static monsterentry mondata[] = {
HT_LAND, 13, DEFAULT_ENERGY, MONUSE_OPEN_DOORS, SIZE_BIG
},
+{
+ MONS_HARPY, 'H', GREEN, "harpy",
+ M_FLIES | M_WARM_BLOOD | M_BATTY,
+ MR_NO_FLAGS,
+ 1000, 10, MONS_HARPY, MONS_HARPY, MH_NATURAL, -3,
+ { {AT_BITE, AF_PLAIN, 10}, {AT_CLAW, AF_PLAIN, 8},
+ {AT_CLAW, AF_STEAL_FOOD, 5}, AT_NO_ATK },
+ { 7, 3, 5, 0 },
+ 2, 10, MST_NO_SPELLS, CE_CONTAMINATED, Z_BIG, S_SCREECH, I_ANIMAL,
+ HT_LAND, 30, DEFAULT_ENERGY, MONUSE_NOTHING, SIZE_MEDIUM
+},
+
// ice beast ('I')
{
MONS_ICE_BEAST, 'I', WHITE, "ice beast",
diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc
index 3ba5edfdbe..940bd6f1f9 100644
--- a/crawl-ref/source/mon-pick.cc
+++ b/crawl-ref/source/mon-pick.cc
@@ -738,6 +738,7 @@ int mons_standard_level(int mcls)
case MONS_SKELETON_SMALL:
case MONS_SPINY_WORM:
case MONS_VERY_UGLY_THING:
+ case MONS_HARPY:
return 20;
case MONS_BOULDER_BEETLE:
@@ -1015,6 +1016,7 @@ int mons_standard_rare(int mcls)
case MONS_STORM_DRAGON:
case MONS_VERY_UGLY_THING:
case MONS_WIZARD:
+ case MONS_HARPY:
return 20;
case MONS_BORING_BEETLE:
@@ -1713,6 +1715,7 @@ int mons_shoals_level(int mcls)
case MONS_CENTAUR_WARRIOR:
case MONS_CYCLOPS: // will have a sheep band
+ case MONS_HARPY:
mlev += 3;
break;
@@ -1762,6 +1765,7 @@ int mons_shoals_rare(int mcls)
case MONS_STONE_GIANT:
case MONS_YAKTAUR_CAPTAIN:
+ case MONS_HARPY:
return 10;
case MONS_OKLOB_PLANT:
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 0cb418ffc1..3e6cf8ceec 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -1024,7 +1024,7 @@ mon_attack_def mons_attack_spec(const monsters *mon, int attk_number)
if (attk.type == AT_RANDOM)
attk.type = static_cast<mon_attack_type>(random_range(AT_HIT,
- AT_BUTT));
+ AT_BUTT));
if (attk.flavour == AF_KLOWN)
{
@@ -2470,7 +2470,7 @@ bool mons_is_lurking(const monsters *m)
bool mons_is_batty(const monsters *m)
{
- return testbits(m->flags, MF_BATTY);
+ return mons_class_flag(m->type, M_BATTY);
}
bool mons_was_seen(const monsters *m)
@@ -4803,7 +4803,7 @@ std::string monsters::hand_name(bool plural, bool *can_plural) const
// Reduce the chance of a random-shaped monster having hands.
if (rand && coinflip())
return (hand_name(plural, can_plural));
-
+
str = "hand";
}
@@ -4918,7 +4918,7 @@ std::string monsters::foot_name(bool plural, bool *can_plural) const
// Reduce the chance of a random-shaped monster having feet.
if (rand && coinflip())
return (foot_name(plural, can_plural));
-
+
return (plural ? "feet" : "foot");
}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index add15efa74..b7536dee3f 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -81,7 +81,8 @@ enum mon_attack_flavour
AF_DISTORT,
AF_RAGE,
AF_NAPALM,
- AF_CHAOS
+ AF_CHAOS,
+ AF_STEAL_FOOD
};
// properties of the monster class (other than resists/vulnerabilities)
@@ -201,7 +202,7 @@ enum mon_resist_flags
MR_VUL_FIRE = (1<< 9),
MR_VUL_COLD = (1<<10),
- // melee armour resists/vulnerabilities
+ // Melee armour resists/vulnerabilities.
// XXX: how to do combos (bludgeon/slice, bludgeon/pierce)
MR_RES_PIERCE = (1<<11),
MR_RES_SLICE = (1<<12),
@@ -211,9 +212,9 @@ enum mon_resist_flags
MR_VUL_SLICE = (1<<15),
MR_VUL_BLUDGEON = (1<<16),
- // immune to stickiness of sticky flame.
- MR_RES_STICKY_FLAME = (1 << 17),
- MR_RES_STEAM = (1 << 18)
+ // Immune to stickiness of sticky flame.
+ MR_RES_STICKY_FLAME = (1<<17),
+ MR_RES_STEAM = (1<<18)
};
enum shout_type
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 754b4cb5e1..487bbd6704 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -892,12 +892,6 @@ static int _place_monster_aux( const mgen_data &mg,
if (mg.cls == MONS_GLOWING_SHAPESHIFTER)
menv[id].add_ench(ENCH_GLOWING_SHAPESHIFTER);
- if (mg.cls == MONS_GIANT_BAT || mg.cls == MONS_UNSEEN_HORROR
- || mg.cls == MONS_GIANT_BLOWFLY)
- {
- menv[id].flags |= MF_BATTY;
- }
-
if (monster_can_submerge(&menv[id], grd(fpos)) && !one_chance_in(5))
menv[id].add_ench(ENCH_SUBMERGED);
@@ -957,7 +951,7 @@ static int _place_monster_aux( const mgen_data &mg,
menv[id].foe = mg.foe;
- // Initialise pandemonium demons
+ // Initialise pandemonium demons.
if (menv[id].type == MONS_PANDEMONIUM_DEMON)
{
ghost_demon ghost;
@@ -1464,6 +1458,10 @@ static band_type _choose_band( int mon_type, int power, int &band_size )
band = BAND_DEATH_YAKS;
band_size = 3 + random2(3);
break;
+ case MONS_HARPY:
+ band = BAND_HARPYES;
+ band_size = 2 + random2(3);
+ break;
// Journey -- Added Draconian Packs
case MONS_WHITE_DRACONIAN:
@@ -1570,6 +1568,9 @@ static monster_type _band_member(band_type band, int power)
mon_type = MONS_YAK;
break;
+ case BAND_HARPYES:
+ mon_type = MONS_HARPY;
+
case BAND_UGLY_THINGS:
mon_type = ((power > 21 && one_chance_in(4)) ?
MONS_VERY_UGLY_THING : MONS_UGLY_THING);
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index bbb1c80ce4..1cc3422cd2 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -62,7 +62,8 @@ enum band_type
BAND_BLINK_FROGS,
BAND_SKELETAL_WARRIORS,
BAND_DRACONIAN, // 45
- BAND_PANDEMONIUM_DEMON, // 46
+ BAND_PANDEMONIUM_DEMON,
+ BAND_HARPYES, // 47
NUM_BANDS // always last
};
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 6cdfe1c2fb..436d24a82f 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -428,6 +428,7 @@ static int _get_target_class(beam_type flavour)
break;
case BEAM_SPORE:
+ case BEAM_STEAL_FOOD:
target_class = OBJ_FOOD;
break;
@@ -441,13 +442,13 @@ static int _get_target_class(beam_type flavour)
// XXX: These expose functions could use being reworked into a real system...
// the usage and implementation is currently very hacky.
// Handles the destruction of inventory items from the elements.
-static void _expose_invent_to_element(beam_type flavour, int strength)
+static bool _expose_invent_to_element(beam_type flavour, int strength)
{
int num_dest = 0;
const int target_class = _get_target_class( flavour );
if (target_class == OBJ_UNASSIGNED)
- return;
+ return (false);
// Currently we test against each stack (and item in the stack)
// independently at strength%... perhaps we don't want that either
@@ -458,13 +459,15 @@ static void _expose_invent_to_element(beam_type flavour, int strength)
if (!is_valid_item(you.inv[i]))
continue;
- if (is_valid_item(you.inv[i])
- && (you.inv[i].base_type == target_class
- || target_class == OBJ_FOOD
- && you.inv[i].base_type == OBJ_CORPSES))
+ if (you.inv[i].base_type == target_class
+ || target_class == OBJ_FOOD
+ && you.inv[i].base_type == OBJ_CORPSES)
{
- if (player_item_conserve() && !one_chance_in(10))
+ if (flavour != BEAM_STEAL_FOOD
+ && player_item_conserve() && !one_chance_in(10))
+ {
continue;
+ }
for (int j = 0; j < you.inv[i].quantity; ++j)
{
@@ -484,36 +487,38 @@ static void _expose_invent_to_element(beam_type flavour, int strength)
}
}
- if (num_dest > 0)
+ if (!num_dest)
+ return (false);
+
+ switch (target_class)
{
- switch (target_class)
- {
- case OBJ_SCROLLS:
- mprf("%s you are carrying %s fire!",
- (num_dest > 1) ? "Some of the scrolls" : "A scroll",
- (num_dest > 1) ? "catch" : "catches" );
- break;
-
- case OBJ_POTIONS:
- mprf("%s you are carrying %s and %s!",
- (num_dest > 1) ? "Some of the potions" : "A potion",
- (num_dest > 1) ? "freeze" : "freezes",
- (num_dest > 1) ? "shatter" : "shatters" );
- break;
-
- case OBJ_FOOD:
- mpr("Some of your food is covered with spores!");
- break;
+ case OBJ_SCROLLS:
+ mprf("%s you are carrying %s fire!",
+ (num_dest > 1) ? "Some of the scrolls" : "A scroll",
+ (num_dest > 1) ? "catch" : "catches" );
+ break;
- default:
- mprf("%s you are carrying %s destroyed!",
- (num_dest > 1) ? "Some items" : "An item",
- (num_dest > 1) ? "were" : "was" );
- break;
- }
+ case OBJ_POTIONS:
+ mprf("%s you are carrying %s and %s!",
+ (num_dest > 1) ? "Some of the potions" : "A potion",
+ (num_dest > 1) ? "freeze" : "freezes",
+ (num_dest > 1) ? "shatter" : "shatters" );
+ break;
- xom_is_stimulated((num_dest > 1) ? 32 : 16);
+ case OBJ_FOOD:
+ if (flavour == BEAM_SPORE)
+ mpr("Some of your food is covered with spores!");
+ break;
+
+ default:
+ mprf("%s you are carrying %s destroyed!",
+ (num_dest > 1) ? "Some items" : "An item",
+ (num_dest > 1) ? "were" : "was" );
+ break;
}
+
+ xom_is_stimulated((num_dest > 1) ? 32 : 16);
+ return (true);
}
void expose_items_to_element(beam_type flavour, const coord_def& where,
@@ -588,7 +593,7 @@ void expose_items_to_element(beam_type flavour, const coord_def& where,
// This function now calls _expose_invent_to_element() if strength > 0.
//
// XXX: This function is far from perfect and a work in progress.
-void expose_player_to_element(beam_type flavour, int strength)
+bool expose_player_to_element(beam_type flavour, int strength)
{
// Note that BEAM_TELEPORT is sent here when the player
// blinks or teleports.
@@ -601,8 +606,10 @@ void expose_player_to_element(beam_type flavour, int strength)
remove_condensation_shield();
}
- if (strength > 0)
- _expose_invent_to_element( flavour, strength );
+ if (strength <= 0)
+ return (false);
+
+ return (_expose_invent_to_element( flavour, strength ));
}
void lose_level()
diff --git a/crawl-ref/source/ouch.h b/crawl-ref/source/ouch.h
index a61101902d..3bcb532387 100644
--- a/crawl-ref/source/ouch.h
+++ b/crawl-ref/source/ouch.h
@@ -75,6 +75,6 @@ void drain_exp(bool announce_full = true);
void expose_items_to_element(beam_type flavour, const coord_def& where,
int strength = 0);
-void expose_player_to_element(beam_type flavour, int strength = 0);
+bool expose_player_to_element(beam_type flavour, int strength = 0);
#endif