/** * @file * @brief player methods dealing with mesmerisation. **/ #include "AppHdr.h" #include "player.h" #include "coord.h" #include "env.h" #include "fprop.h" #include "mon-util.h" #include "monster.h" #include "state.h" #include "areas.h" // Add a monster to the list of fearmongers. bool player::add_fearmonger(const monster* mon) { if (is_sanctuary(pos())) { if (can_see(mon)) { mprf("%s's aura of fear is muted, and has no effect on you.", mon->name(DESC_THE).c_str()); } else mpr("The fearful aura is strangely muted, and has no effect on you."); return false; } if (!duration[DUR_AFRAID]) { set_duration(DUR_AFRAID, 7, 12); fearmongers.push_back(mon->mindex()); mprf(MSGCH_WARN, "You are terrified of %s!", mon->name(DESC_THE).c_str()); } else { increase_duration(DUR_AFRAID, 5, 12); if (!afraid_of(mon)) fearmongers.push_back(mon->mindex()); } return true; } // Whether player is afraid. bool player::afraid() const { ASSERT(duration[DUR_AFRAID] > 0 == !fearmongers.empty()); return duration[DUR_AFRAID] > 0; } // Whether player is afraid of the given monster. bool player::afraid_of(const monster* mon) const { for (unsigned int i = 0; i < fearmongers.size(); i++) if (fearmongers[i] == mon->mindex()) return true; return false; } // Checks whether a fearmonger keeps you from moving to // target, and returns one if it exists. monster* player::get_fearmonger(const coord_def &target) const { for (unsigned int i = 0; i < fearmongers.size(); i++) { monster* mon = &menv[fearmongers[i]]; const int olddist = grid_distance(pos(), mon->pos()); const int newdist = grid_distance(target, mon->pos()); if (olddist > newdist) return mon; } return NULL; } monster* player::get_any_fearmonger() const { if (!fearmongers.empty()) return &menv[fearmongers[0]]; else return NULL; } // Removes a monster from the list of fearmongers if present. void player::remove_fearmonger(const monster* mon) { for (unsigned int i = 0; i < fearmongers.size(); i++) if (fearmongers[i] == mon->mindex()) { fearmongers.erase(fearmongers.begin() + i); _removed_fearmonger(); return; } } // Clear the list of fearmongers. Doesn't message. void player::clear_fearmongers() { fearmongers.clear(); duration[DUR_AFRAID] = 0; } // Possibly end fear if a loud noise happened. void player::fearmongers_check_noise(int loudness, bool axe) { if (axe) return; if (loudness >= 20 && beheld()) { mpr("For a moment, your terror fades away!"); clear_fearmongers(); _removed_fearmonger(); } } static void _removed_fearmonger_msg(const monster* mon) { return; } // Update all fearmongers' status after changes. void player::update_fearmongers() { if (!afraid()) return; bool removed = false; for (int i = fearmongers.size() - 1; i >= 0; i--) { const monster* mon = &menv[fearmongers[i]]; if (!_possible_fearmonger(mon)) { fearmongers.erase(fearmongers.begin() + i); removed = true; // If that was the last one, clear the duration before // printing any subsequent messages, or a --more-- can // crash (#6547). _removed_fearmonger(true); _removed_fearmonger_msg(mon); } } if (removed) _removed_fearmonger(); } // Update a single fearmonger. void player::update_fearmonger(const monster* mon) { if (_possible_fearmonger(mon)) return; for (unsigned int i = 0; i < fearmongers.size(); i++) if (fearmongers[i] == mon->mindex()) { fearmongers.erase(fearmongers.begin() + i); // Do this dance to clear the duration before printing messages // (#8844), but still print all messages in the right order. _removed_fearmonger(true); _removed_fearmonger_msg(mon); _removed_fearmonger(); return; } } // Helper function that resets the duration and messages if the player // is no longer afraid. void player::_removed_fearmonger(bool quiet) { if (fearmongers.empty()) { duration[DUR_AFRAID] = 0; if (!quiet) mprf(MSGCH_DURATION, "You are no longer terrified."); } } // Helper function that checks whether the given monster is a possible // fearmonger. bool player::_possible_fearmonger(const monster* mon) const { if (crawl_state.game_is_arena()) return false; return mon->alive() && !silenced(pos()) && !silenced(mon->pos()) && see_cell(mon->pos()) && mon->see_cell(pos()) && !mon->submerged() && !mon->confused() && !mon->asleep() && !mon->cannot_move() && !mon->wont_attack() && !mon->pacified() && !mon->berserk_or_insane() && !mons_is_fleeing(mon) && !is_sanctuary(pos()); }