/* * File: behold.cc * Summary: player methods dealing with mesmerisation. */ #include "AppHdr.h" #include "player.h" #include "coord.h" #include "debug.h" #include "env.h" #include "fprop.h" #include "mon-util.h" #include "monster.h" #include "random.h" #include "state.h" #include "stuff.h" #include "areas.h" // Add a monster to the list of beholders. void player::add_beholder(const monsters* mon) { if (is_sanctuary(you.pos())) { if (you.can_see(mon)) { mprf("%s's singing sounds muted, and has no effect on you.", mon->name(DESC_CAP_THE).c_str()); } else { mpr("The melody is strangely muted, and has no effect on you."); } return; } if (!duration[DUR_MESMERISED]) { you.set_duration(DUR_MESMERISED, 7, 12); beholders.push_back(mon->mindex()); mprf(MSGCH_WARN, "You are mesmerised by %s!", mon->name(DESC_NOCAP_THE).c_str()); } else { you.increase_duration(DUR_MESMERISED, 5, 12); if (!beheld_by(mon)) beholders.push_back(mon->mindex()); } } // Whether player is mesmerised. bool player::beheld() const { ASSERT(duration[DUR_MESMERISED] > 0 == !beholders.empty()); return (duration[DUR_MESMERISED] > 0); } // Whether player is mesmerised by the given monster. bool player::beheld_by(const monsters* mon) const { for (unsigned int i = 0; i < beholders.size(); i++) if (beholders[i] == mon->mindex()) return (true); return (false); } // Checks whether a beholder keeps you from moving to // target, and returns one if it exists. monsters* player::get_beholder(const coord_def &target) const { for (unsigned int i = 0; i < beholders.size(); i++) { monsters *mon = &menv[beholders[i]]; const int olddist = grid_distance(pos(), mon->pos()); const int newdist = grid_distance(target, mon->pos()); if (olddist < newdist) return (mon); } return (NULL); } monsters* player::get_any_beholder() const { if (beholders.size() > 0) return (&menv[beholders[0]]); else return (NULL); } // Removes a monster from the list of beholders if present. void player::remove_beholder(const monsters *mon) { for (unsigned int i = 0; i < beholders.size(); i++) if (beholders[i] == mon->mindex()) { beholders.erase(beholders.begin() + i); _removed_beholder(); return; } } // Clear the list of beholders. Doesn't message. void player::clear_beholders() { beholders.clear(); duration[DUR_MESMERISED] = 0; } // Possibly end mesmerisation if a loud noise happened. void player::beholders_check_noise(int loudness) { if (loudness >= 20 && beheld()) { mprf("For a moment, you cannot hear the mermaid%s!", beholders.size() > 1 ? "s" : ""); clear_beholders(); _removed_beholder(); } } static void _removed_beholder_msg(const monsters* mon) { if (!mon->alive() || mons_genus(mon->type) != MONS_MERMAID || mon->submerged() || !you.see_cell(mon->pos())) { return; } if (is_sanctuary(you.pos()) && !mons_is_fleeing(mon)) { if (you.can_see(mon)) { mprf("%s's singing becomes strangely muted.", mon->name(DESC_CAP_THE).c_str()); } else mpr("Something's singing becomes strangely muted."); return; } if (you.can_see(mon)) { if (silenced(you.pos()) || silenced(mon->pos())) { mprf("You can no longer hear %s's singing!", mon->name(DESC_NOCAP_THE).c_str()); return; } mprf("%s stops singing.", mon->name(DESC_CAP_THE).c_str()); return; } mpr("Something stops singing."); } // Update all beholders' status after changes. void player::update_beholders() { if (!beheld()) return; bool removed = false; for (int i = beholders.size() - 1; i >= 0; i--) { const monsters* mon = &menv[beholders[i]]; if (!_possible_beholder(mon)) { beholders.erase(beholders.begin() + i); removed = true; _removed_beholder_msg(mon); } } if (removed) _removed_beholder(); } // Update a single beholder. void player::update_beholder(const monsters *mon) { if (_possible_beholder(mon)) return; for (unsigned int i = 0; i < beholders.size(); i++) if (beholders[i] == mon->mindex()) { beholders.erase(beholders.begin() + i); _removed_beholder_msg(mon); _removed_beholder(); return; } } // Helper function that resets the duration and messages if the player // is no longer mesmerised. void player::_removed_beholder() { if (beholders.empty()) { duration[DUR_MESMERISED] = 0; mpr(coinflip() ? "You break out of your daze!" : "You are no longer entranced.", MSGCH_DURATION); } } // Helper function that checks whether the given monster is a possible // beholder. bool player::_possible_beholder(const monsters *mon) const { if (crawl_state.arena) return (false); return (!silenced(pos()) && !silenced(mon->pos()) && see_cell(mon->pos()) && mon->see_cell(pos()) && mon->alive() && mons_genus(mon->type) == MONS_MERMAID && !mon->submerged() && !mon->confused() && !mon->asleep() && !mon->cannot_move() && !mon->wont_attack() && !mon->pacified() && !mon->berserk() && !mons_is_fleeing(mon) && !is_sanctuary(you.pos())); }