summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/monstuff.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/monstuff.cc')
-rw-r--r--crawl-ref/source/monstuff.cc107
1 files changed, 104 insertions, 3 deletions
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 322cc9163c..b3a2eb4995 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -422,6 +422,8 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
if (net != NON_ITEM)
remove_item_stationary(mitm[net]);
}
+ // update list of monsters beholding player
+ update_beholders(monster, true);
const int monster_killed = monster_index(monster);
const bool death_message =
@@ -2321,6 +2323,8 @@ static void handle_nearby_ability(monsters *monster)
case MONS_LAVA_FISH:
case MONS_LAVA_SNAKE:
case MONS_SALAMANDER:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL:
@@ -2328,18 +2332,22 @@ static void handle_nearby_ability(monsters *monster)
case MONS_WATER_ELEMENTAL:
case MONS_SWAMP_WORM:
if (monster_can_submerge(monster->type, grd[monster->x][monster->y])
- && (one_chance_in(5) || (grid_distance( monster->x, monster->y,
- you.x_pos, you.y_pos ) > 1
+ && ( !player_beheld_by(monster) // no submerging if player entranced
+ && (one_chance_in(5) || (grid_distance( monster->x, monster->y,
+ you.x_pos, you.y_pos ) > 1
// FIXME This is better expressed as a
// function such as
// monster_has_ranged_attack:
&& monster->type != MONS_ELECTRICAL_EEL
&& monster->type != MONS_LAVA_SNAKE
- && !one_chance_in(20))
+ && (monster->type != MONS_MERMAID
+ || you.species == SP_MERFOLK)
+ && !one_chance_in(20)) )
|| monster->hit_points <= monster->max_hit_points / 2)
|| env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
{
monster->add_ench(ENCH_SUBMERGED);
+ update_beholders(monster);
}
break;
@@ -2668,6 +2676,87 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
}
break;
+ case MONS_MERMAID:
+ {
+ // won't sing if either of you silenced, or it's friendly or confused
+ if (monster->has_ench(ENCH_CONFUSION) || mons_friendly(monster)
+ || silenced(monster->x, monster->y) || silenced(you.x_pos, you.y_pos))
+ {
+ break;
+ }
+
+ // reduce probability because of spamminess
+ if (you.species == SP_MERFOLK && !one_chance_in(4))
+ break;
+
+ // a wounded invisible mermaid is less likely to give away her position
+ if (monster->invisible()
+ && monster->hit_points <= monster->max_hit_points / 2
+ && !one_chance_in(3))
+ {
+ break;
+ }
+
+ bool already_beheld = player_beheld_by(monster);
+
+ if (one_chance_in(5)
+ || monster->foe == MHITYOU && !already_beheld && coinflip())
+ {
+ if (player_monster_visible(monster))
+ {
+ simple_monster_message(monster,
+ make_stringf(" chants %s song.",
+ already_beheld? "her luring" : "a haunting").c_str(),
+ MSGCH_MONSTER_SPELL);
+ }
+ else
+ {
+ // if you're already beheld by an invisible mermaid she can
+ // still prolong the enchantment; otherwise you "resist"
+ if (already_beheld)
+ mpr("You hear a luring song.", MSGCH_SOUND);
+ else
+ {
+ if (one_chance_in(4)) // reduce spamminess
+ {
+ if (coinflip())
+ mpr("You hear a haunting song.", MSGCH_SOUND);
+ else
+ mpr("You hear an eerie melody.", MSGCH_SOUND);
+
+ canned_msg(MSG_YOU_RESIST); // flavour only
+ }
+ break;
+ }
+ }
+
+ // once beheld by a particular monster, cannot resist anymore
+ if (!already_beheld
+ && (you.species == SP_MERFOLK || you_resist_magic(100)))
+ {
+ canned_msg(MSG_YOU_RESIST);
+ break;
+ }
+
+ if (!you.duration[DUR_BEHELD])
+ {
+ you.duration[DUR_BEHELD] = 7;
+ you.beheld_by.push_back(monster_index(monster));
+ mpr("You are beheld!", MSGCH_WARN);
+ }
+ else
+ {
+ you.duration[DUR_BEHELD] += 5;
+ if (!already_beheld)
+ you.beheld_by.push_back(monster_index(monster));
+ }
+ used = true;
+
+ if (you.duration[DUR_BEHELD] > 12)
+ you.duration[DUR_BEHELD] = 12;
+ }
+ break;
+ }
default:
break;
}
@@ -4241,6 +4330,8 @@ static void handle_monster_move(int i, monsters *monster)
if (!monster_move(monster))
monster->speed_increment -= non_move_energy;
}
+ update_beholders(monster);
+
// reevaluate behaviour, since the monster's
// surroundings have changed (it may have moved,
// or died for that matter. Don't bother for
@@ -4306,7 +4397,15 @@ void handle_monsters(void)
// If the player got banished, discard pending monster actions.
if (you.banished)
+ {
+ // clear list of beholding monsters
+ if (you.duration[DUR_BEHELD])
+ {
+ you.beheld_by.clear();
+ you.duration[DUR_BEHELD] = 0;
+ }
break;
+ }
} // end of for loop
// Clear any summoning flags so that lower indiced
@@ -5493,6 +5592,8 @@ dungeon_feature_type monster_habitat(int which_class)
{
switch (which_class)
{
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL: