summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc46
-rw-r--r--crawl-ref/source/direct.cc3
-rw-r--r--crawl-ref/source/dungeon.cc7
-rw-r--r--crawl-ref/source/enum.h3
-rw-r--r--crawl-ref/source/externs.h4
-rw-r--r--crawl-ref/source/makeitem.cc32
-rw-r--r--crawl-ref/source/misc.cc7
-rw-r--r--crawl-ref/source/mon-data.h24
-rw-r--r--crawl-ref/source/mon-pick.cc14
-rw-r--r--crawl-ref/source/mon-util.cc6
-rw-r--r--crawl-ref/source/monplace.cc6
-rw-r--r--crawl-ref/source/monstuff.cc107
-rw-r--r--crawl-ref/source/output.cc6
-rw-r--r--crawl-ref/source/player.cc68
-rw-r--r--crawl-ref/source/player.h2
-rw-r--r--crawl-ref/source/spells4.cc7
-rw-r--r--crawl-ref/source/tags.cc10
-rw-r--r--crawl-ref/source/view.cc9
18 files changed, 349 insertions, 12 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 636a86d41d..09f70c8742 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -648,6 +648,12 @@ static void handle_wizard_command( void )
case 'H':
you.rotting = 0;
you.duration[DUR_POISONING] = 0;
+ if (you.duration[DUR_BEHELD])
+ {
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
+ you.duration[DUR_CONF] = 0;
you.disease = 0;
inc_hp( 10, true );
set_hp( you.hp_max, false );
@@ -2458,6 +2464,12 @@ static void decrement_durations()
decrement_a_duration( DUR_SURE_BLADE,
"The bond with your blade fades away." );
+ if ( decrement_a_duration( DUR_BEHELD, "You break out of your daze.",
+ -1, 0, NULL, MSGCH_RECOVERY ))
+ {
+ you.beheld_by.clear();
+ }
+
dec_slow_player();
dec_haste_player();
@@ -3602,6 +3614,34 @@ static void move_player(int move_x, int move_y)
}
} // end of if you.duration[DUR_CONF]
+ const int targ_x = you.x_pos + move_x;
+ const int targ_y = you.y_pos + move_y;
+ const dungeon_feature_type targ_grid = grd[ targ_x ][ targ_y ];
+ const unsigned short targ_monst = mgrd[ targ_x ][ targ_y ];
+ const bool targ_solid = grid_is_solid(targ_grid);
+
+ // cannot move away from mermaid but you CAN fight neighbouring squares
+ if (you.duration[DUR_BEHELD] && !you.duration[DUR_CONF]
+ && (targ_monst == NON_MONSTER || mons_is_submerged(&menv[targ_monst])))
+ {
+ for (unsigned int i = 0; i < you.beheld_by.size(); i++)
+ {
+ coord_def pos = menv[you.beheld_by[i]].pos();
+ int olddist = distance(you.x_pos, you.y_pos, pos.x, pos.y);
+ int newdist = distance(you.x_pos + move_x, you.y_pos + move_y, pos.x, pos.y);
+
+ if (olddist < newdist)
+ {
+ mprf("You cannot move away from %s!",
+ (menv[you.beheld_by[i]]).name(DESC_NOCAP_THE, true).c_str());
+
+ move_x = 0;
+ move_y = 0;
+ return;
+ }
+ }
+ } // end of beholding check
+
if (you.running.check_stop_running())
{
move_x = 0;
@@ -3611,12 +3651,6 @@ static void move_player(int move_x, int move_y)
return;
}
- const int targ_x = you.x_pos + move_x;
- const int targ_y = you.y_pos + move_y;
- const dungeon_feature_type targ_grid = grd[ targ_x ][ targ_y ];
- const unsigned short targ_monst = mgrd[ targ_x ][ targ_y ];
- const bool targ_solid = grid_is_solid(targ_grid);
-
if (targ_monst != NON_MONSTER && !mons_is_submerged(&menv[targ_monst]))
{
struct monsters *mon = &menv[targ_monst];
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 5c98b25623..4315930792 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -1844,6 +1844,9 @@ static void describe_monster(const monsters *mon)
text += ".";
print_formatted_paragraph(text, get_number_of_cols());
+ if (player_beheld_by(mon))
+ mpr("You are beheld by her song.", MSGCH_EXAMINE);
+
if (mon->type == MONS_HYDRA)
{
mprf(MSGCH_EXAMINE, "It has %d head%s.", mon->number,
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 14233e9b1d..cc9c4f4f46 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -2546,6 +2546,13 @@ static void place_aquatic_monsters(int level_number, char level_type)
swimming_things[i] = MONS_BIG_FISH + random2(4);
if (player_in_branch( BRANCH_SWAMP ) && !one_chance_in(3))
swimming_things[i] = MONS_SWAMP_WORM;
+ else if (player_in_branch( BRANCH_SHOALS ))
+ {
+ if (one_chance_in(3))
+ swimming_things[i] = MONS_MERFOLK;
+ else if (one_chance_in(5))
+ swimming_things[i] = MONS_MERMAID;
+ }
}
if (level_number >= 25 && one_chance_in(5))
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 01048e2340..b2895d7eaa 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -983,6 +983,7 @@ enum duration_type
DUR_CONF,
DUR_PARALYSIS,
DUR_SLOW,
+ DUR_BEHELD,
DUR_HASTE,
DUR_MIGHT,
DUR_LEVITATION,
@@ -1557,6 +1558,8 @@ enum monster_type // (int) menv[].type
MONS_BLACK_BEAR, // 189
MONS_SIMULACRUM_SMALL,
MONS_SIMULACRUM_LARGE,
+ MONS_MERFOLK,
+ MONS_MERMAID, // 193
//jmf: end new monsters
MONS_WHITE_IMP = 220, // 220
MONS_LEMURE,
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index cd145c41be..ade001aaee 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -493,11 +493,13 @@ class player : public actor
{
public:
bool turn_is_over; // flag signaling that player has performed a timed action
-
+
// If true, player is headed to the Abyss.
bool banished;
std::string banished_by;
+ std::vector<int> beheld_by; // monsters beholding player
+
bool just_autoprayed; // autopray just kicked in
unsigned char prev_targ;
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index d251b071e7..75e6e33508 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -3420,6 +3420,34 @@ static item_make_species_type give_weapon(monsters *mon, int level,
}
break;
+ case MONS_MERMAID:
+ if (one_chance_in(3))
+ {
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = WPN_SPEAR;
+ }
+ break;
+
+ case MONS_MERFOLK:
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ // 1/3 each for trident, spears and javelins
+ if (one_chance_in(3))
+ item.sub_type = WPN_TRIDENT;
+ else if (coinflip())
+ {
+ item.sub_type = WPN_SPEAR;
+ iquan = 1 + random2(3);
+ }
+ else
+ {
+ item.base_type = OBJ_MISSILES;
+ item.sub_type = MI_JAVELIN;
+ iquan = 3 + random2(6);
+ }
+ break;
+
case MONS_CENTAUR:
case MONS_CENTAUR_WARRIOR:
item_race = MAKE_ITEM_NO_RACE;
@@ -3672,6 +3700,9 @@ static item_make_species_type give_weapon(monsters *mon, int level,
return (item_race);
}
+ if (iquan > 1 && !force_item)
+ mitm[thing_created].quantity = iquan;
+
give_monster_item(mon, thing_created, force_item);
if (give_aux_melee && (i.base_type != OBJ_WEAPONS || is_range_weapon(i)))
@@ -3751,6 +3782,7 @@ static void give_ammo(monsters *mon, int level,
case MONS_DRACONIAN_KNIGHT:
case MONS_GNOLL:
case MONS_HILL_GIANT:
+ case MONS_MERFOLK:
if (!one_chance_in(20))
break;
// fall through
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 8fa092b0a0..8351616c1c 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1243,6 +1243,13 @@ void down_stairs( int old_level, dungeon_feature_type force_stair,
new_level();
+ // clear list of beholding monsters
+ if (you.duration[DUR_BEHELD])
+ {
+ you.beheld_by.clear();
+ you.duration[DUR_BEHELD] = 0;
+ }
+
viewwindow(1, true);
if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index cd585b36b9..b021392e7d 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -3985,6 +3985,30 @@
},
{
+ MONS_MERFOLK, 'm', LIGHTBLUE, "merfolk fighter",
+ M_HUMANOID | M_WARM_BLOOD | M_AMPHIBIOUS,
+ MR_RES_POISON | MR_RES_COLD,
+ 500, 10, MONS_MERFOLK, MONS_MERFOLK, MH_NATURAL, -3,
+ { {AT_HIT, AF_PLAIN, 14}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { 8, 2, 4, 0 },
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+}
+,
+
+{
+ MONS_MERMAID, 'm', LIGHTCYAN, "mermaid",
+ M_SPELLCASTER | M_HUMANOID | M_WARM_BLOOD | M_AMPHIBIOUS,
+ MR_RES_POISON | MR_RES_COLD,
+ 500, 10, MONS_MERMAID, MONS_MERMAID, MH_NATURAL, -5,
+ { {AT_HIT, AF_PLAIN, 10}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0}, {AT_NONE, AF_PLAIN, 0} },
+ { 8, 2, 4, 0 },
+ 4, 12, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_SHOUT, I_HIGH,
+ MONUSE_WEAPONS_ARMOUR, SIZE_MEDIUM
+}
+,
+
+{
MONS_GIANT_NEWT, 'l', LIGHTGREEN, "giant newt",
M_COLD_BLOOD | M_AMPHIBIOUS,
MR_NO_FLAGS,
diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc
index cf4f03fcd4..d7989c10c2 100644
--- a/crawl-ref/source/mon-pick.cc
+++ b/crawl-ref/source/mon-pick.cc
@@ -2029,6 +2029,8 @@ int mons_shoals_level(int mcls)
case MONS_GIANT_BAT:
break;
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_CENTAUR:
case MONS_ETTIN:
case MONS_SHEEP:
@@ -2069,8 +2071,12 @@ int mons_shoals_rare(int mcls)
case MONS_ETTIN:
case MONS_SHEEP:
+ case MONS_MERFOLK:
return 50;
+ case MONS_MERMAID:
+ return 40;
+
case MONS_HIPPOGRIFF:
case MONS_GIANT_BAT:
case MONS_BUTTERFLY:
@@ -2112,6 +2118,8 @@ int mons_swamp_level(int mcls)
case MONS_SWAMP_DRAKE:
case MONS_WORM:
case MONS_SWAMP_WORM:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
mlev++;
break;
@@ -2189,6 +2197,7 @@ int mons_swamp_rare(int mcls)
return 61;
case MONS_SLIME_CREATURE:
+ case MONS_MERFOLK:
return 54;
case MONS_SNAKE:
@@ -2216,6 +2225,7 @@ int mons_swamp_rare(int mcls)
case MONS_KOMODO_DRAGON:
case MONS_VERY_UGLY_THING:
case MONS_VAPOUR:
+ case MONS_MERMAID:
return 15;
case MONS_PHANTOM:
@@ -2669,6 +2679,8 @@ int mons_standard_level(int mcls)
case MONS_DEEP_ELF_MASTER_ARCHER:
return 33;
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_ELECTRICAL_EEL:
case MONS_GIANT_GOLDFISH:
@@ -2691,6 +2703,8 @@ int mons_standard_rare(int mcls)
{
// "another lava thing" has no stats! (GDL)
// case MONS_ANOTHER_LAVA_THING:
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_ELECTRICAL_EEL:
case MONS_GIANT_GOLDFISH:
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 764de91b12..8428a4f0a7 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -488,6 +488,11 @@ bool mons_is_humanoid( int mc )
case 'T': // trolls
return (true);
+ case 'm': // merfolk
+ if (mc == MONS_MERFOLK || mc == MONS_MERMAID)
+ return (true);
+ return (false);
+
case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
if (mc != MONS_GARGOYLE
&& mc != MONS_METAL_GARGOYLE
@@ -2169,6 +2174,7 @@ const char *mons_pronoun(monster_type mon_type, pronoun_type variant)
case MONS_EROLCHA:
case MONS_ERICA:
case MONS_TIAMAT:
+ case MONS_MERMAID:
gender = GENDER_FEMALE;
break;
default:
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 3327b51253..067b825e38 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -104,7 +104,9 @@ bool monster_habitable_grid(int monster_class, int actual_grid, int flies,
// And water elementals are native to the water but happy on land
// as well.
- || (monster_class == MONS_WATER_ELEMENTAL
+ || ((monster_class == MONS_WATER_ELEMENTAL
+ || monster_class == MONS_MERFOLK
+ || monster_class == MONS_MERMAID)
&& grid_compatible(DNGN_FLOOR, actual_grid)));
}
@@ -113,6 +115,8 @@ bool monster_can_submerge(int monster_class, int grid)
{
switch (monster_class)
{
+ case MONS_MERFOLK:
+ case MONS_MERMAID:
case MONS_BIG_FISH:
case MONS_GIANT_GOLDFISH:
case MONS_ELECTRICAL_EEL:
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:
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index a6aac29f88..27b9a16a17 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -541,6 +541,12 @@ void print_stats(void)
textcolor( RED ); // no different levels
cprintf( "Conf " );
}
+
+ if (you.duration[DUR_BEHELD])
+ {
+ textcolor( RED ); // no different levels
+ cprintf( "Bhld " );
+ }
if (you.duration[DUR_LIQUID_FLAMES])
{
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 674e2df54c..02266afb2a 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -2324,7 +2324,7 @@ int player_see_invis(bool calc_unid)
// This does NOT do line of sight! It checks the monster's visibility
// with repect to the players perception, but doesn't do walls or range...
-// to find if the square the monster is in is visible see mons_near().
+// to find if the square the monster is in los see mons_near().
bool player_monster_visible( const monsters *mon )
{
if (mon->has_ench(ENCH_SUBMERGED)
@@ -2336,6 +2336,69 @@ bool player_monster_visible( const monsters *mon )
return (true);
}
+// returns true if player is beheld by a given monster
+bool player_beheld_by( const monsters *mon )
+{
+ if (!you.duration[DUR_BEHELD])
+ return false;
+
+ // can this monster even behold you?
+ if (mon->type != MONS_MERMAID)
+ return false;
+
+#ifdef DEBUG_DIAGNOSTICS
+ mprf(MSGCH_DIAGNOSTICS, "beheld_by.size: %d, DUR_BEHELD: %d, current mon: %d",
+ you.beheld_by.size(), you.duration[DUR_BEHELD],
+ monster_index(mon));
+#endif
+
+ if (you.beheld_by.empty()) // shouldn't happen
+ {
+ you.duration[DUR_BEHELD] = 0;
+ return false;
+ }
+
+ for (unsigned int i = 0; i < you.beheld_by.size(); i++)
+ {
+ unsigned int which_mon = you.beheld_by[i];
+ if (monster_index(mon) == which_mon)
+ return true;
+ }
+
+ return false;
+}
+
+// removes a monster from the list of beholders
+// if force == true (e.g. monster dead) or one of
+// several cases is met
+void update_beholders(const monsters *mon, bool force)
+{
+ if (!player_beheld_by(mon)) // not in list?
+ return;
+
+ // is an update even necessary?
+ if (force || !mons_near(mon) || mons_friendly(mon) || mon->submerged()
+ || mon->has_ench(ENCH_CONFUSION) || mons_is_paralysed(mon) || mon->asleep()
+ || silenced(you.x_pos, you.y_pos) || silenced(mon->x, mon->y))
+ {
+ const std::vector<int> help = you.beheld_by;
+ you.beheld_by.clear();
+
+ for (unsigned int i = 0; i < help.size(); i++)
+ {
+ unsigned int which_mon = help[i];
+ if (monster_index(mon) != which_mon)
+ you.beheld_by.push_back(i);
+ }
+
+ if (you.beheld_by.empty())
+ {
+ mpr("You are no longer entranced.", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ }
+ }
+}
+
int player_sust_abil(bool calc_unid)
{
int sa = 0;
@@ -3362,6 +3425,9 @@ void display_char_status()
if (you.duration[DUR_CONF])
mpr( "You are confused." );
+ if (you.duration[DUR_BEHELD])
+ mpr( "You are beheld." );
+
if (you.duration[DUR_PARALYSIS])
mpr( "You are paralysed." );
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index 390ce4e505..95e35193f9 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -263,6 +263,8 @@ int slaying_bonus(char which_affected);
int player_see_invis(bool calc_unid = true);
bool player_monster_visible( const monsters *mon );
+bool player_beheld_by( const monsters *mon );
+void update_beholders( const monsters *mon, bool force = false);
/* ***********************************************************************
* called from: acr - decks - it_use2 - ouch
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index f7dde163dc..2358498568 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1232,6 +1232,13 @@ void cast_silence(int pow)
if (you.duration[DUR_SILENCE] > 100)
you.duration[DUR_SILENCE] = 100;
+
+ if (you.duration[DUR_BEHELD])
+ {
+ mpr("You break out of your daze!", MSGCH_RECOVERY);
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
} // end cast_silence()
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index e4631d3f6d..818da4051c 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -928,6 +928,11 @@ static void tag_construct_you(struct tagHeader &th)
marshallShort(th, you.transit_stair);
marshallByte(th, you.entering_level);
+
+ // list of currently beholding monsters (usually empty)
+ marshallByte(th, you.beheld_by.size());
+ for (unsigned int k = 0; k < you.beheld_by.size(); k++)
+ marshallByte(th, you.beheld_by[k]);
}
static void tag_construct_you_items(struct tagHeader &th)
@@ -1263,6 +1268,11 @@ static void tag_read_you(struct tagHeader &th, char minorVersion)
you.transit_stair = static_cast<dungeon_feature_type>(unmarshallShort(th));
you.entering_level = unmarshallByte(th);
+
+ // list of currently beholding monsters (usually empty)
+ count_c = unmarshallByte(th);
+ for (i = 0; i < count_c; i++)
+ you.beheld_by.push_back(unmarshallByte(th));
}
static void tag_read_you_items(struct tagHeader &th, char minorVersion)
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 80612fda71..c7018aa032 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -1359,6 +1359,15 @@ bool noisy( int loudness, int nois_x, int nois_y, const char *msg )
you.check_awaken(dist - player_distance);
+ if (loudness >= 20 && you.duration[DUR_BEHELD])
+ {
+ mprf("For a moment, you cannot hear the mermaid%s!",
+ you.beheld_by.size() == 1? "" : "s");
+ mpr("You break out of your daze!", MSGCH_DURATION);
+ you.duration[DUR_BEHELD] = 0;
+ you.beheld_by.clear();
+ }
+
ret = true;
}