From 4dd53d952662125a877527566e76c73754385369 Mon Sep 17 00:00:00 2001 From: Robert Vollmert Date: Fri, 6 Nov 2009 15:24:34 +0100 Subject: Collect attitude changing code. --- crawl-ref/source/attitude-change.cc | 962 ++++++++++++++++++++++++++++++++++++ crawl-ref/source/attitude-change.h | 26 + crawl-ref/source/beam.cc | 1 + crawl-ref/source/delay.cc | 1 + crawl-ref/source/fight.cc | 1 + crawl-ref/source/godabil.cc | 128 ----- crawl-ref/source/godabil.h | 4 - crawl-ref/source/makefile.obj | 1 + crawl-ref/source/monstuff.cc | 1 + crawl-ref/source/religion.cc | 737 +-------------------------- crawl-ref/source/religion.h | 2 - crawl-ref/source/spells1.cc | 3 +- crawl-ref/source/view.cc | 124 +---- crawl-ref/source/view.h | 2 - 14 files changed, 1018 insertions(+), 975 deletions(-) create mode 100644 crawl-ref/source/attitude-change.cc create mode 100644 crawl-ref/source/attitude-change.h diff --git a/crawl-ref/source/attitude-change.cc b/crawl-ref/source/attitude-change.cc new file mode 100644 index 0000000000..0f3ba57b41 --- /dev/null +++ b/crawl-ref/source/attitude-change.cc @@ -0,0 +1,962 @@ +/* + * Summary: Monster attitude changing due to religion. + */ + +#include "AppHdr.h" + +#include "attitude-change.h" + +#include + +#include "coordit.h" +#include "database.h" +#include "env.h" +#include "files.h" +#include "godabil.h" +#include "goditem.h" +#include "message.h" +#include "mon-behv.h" +#include "mon-util.h" +#include "monster.h" +#include "monstuff.h" +#include "player.h" +#include "random.h" +#include "religion.h" +#include "state.h" +#include "stuff.h" +#include "travel.h" + +void good_god_follower_attitude_change(monsters *monster) +{ + if (you.is_unholy() || crawl_state.arena) + return; + + // For followers of good gods, decide whether holy beings will be + // good neutral towards you. + if (is_good_god(you.religion) + && monster->foe == MHITYOU + && mons_is_holy(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && !mons_wont_attack(monster) + && you.visible_to(monster) && !monster->asleep() + && !mons_is_confused(monster) && !monster->paralysed()) + { + monster->flags |= MF_ATT_CHANGE_ATTEMPT; + + if (x_chance_in_y(you.piety, MAX_PIETY) && !you.penance[you.religion]) + { + const item_def* wpn = you.weapon(); + if (wpn + && wpn->base_type == OBJ_WEAPONS + && is_evil_item(*wpn) + && coinflip()) // 50% chance of conversion failing + { + msg::stream << monster->name(DESC_CAP_THE) + << " glares at your weapon." + << std::endl; + good_god_holy_fail_attitude_change(monster); + return; + } + good_god_holy_attitude_change(monster); + stop_running(); + } + else + good_god_holy_fail_attitude_change(monster); + } +} + +void beogh_follower_convert(monsters *monster, bool orc_hit) +{ + if (you.species != SP_HILL_ORC || crawl_state.arena) + return; + + // For followers of Beogh, decide whether orcs will join you. + if (you.religion == GOD_BEOGH + && monster->foe == MHITYOU + && mons_species(monster->type) == MONS_ORC + && !mons_is_summoned(monster) + && !mons_is_shapeshifter(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && !mons_friendly(monster) + && you.visible_to(monster) && !monster->asleep() + && !mons_is_confused(monster) && !monster->paralysed()) + { + monster->flags |= MF_ATT_CHANGE_ATTEMPT; + + const int hd = monster->hit_dice; + + if (you.piety >= piety_breakpoint(2) && !player_under_penance() + && random2(you.piety / 15) + random2(4 + you.experience_level / 3) + > random2(hd) + hd + random2(5)) + { + if (you.weapon() + && you.weapon()->base_type == OBJ_WEAPONS + && get_weapon_brand(*you.weapon()) == SPWPN_ORC_SLAYING + && coinflip()) // 50% chance of conversion failing + { + msg::stream << monster->name(DESC_CAP_THE) + << " flinches from your weapon." + << std::endl; + return; + } + beogh_convert_orc(monster, orc_hit); + stop_running(); + } + } +} + +void slime_convert(monsters* monster) +{ + if (you.religion == GOD_JIYVA && mons_is_slime(monster) + && !mons_is_summoned(monster) + && !mons_is_shapeshifter(monster) + && !mons_neutral(monster) + && !mons_friendly(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && you.visible_to(monster) && !monster->asleep() + && !mons_is_confused(monster) && !monster->paralysed()) + { + monster->flags |= MF_ATT_CHANGE_ATTEMPT; + if (!player_under_penance()) + { + jiyva_convert_slime(monster); + stop_running(); + } + } +} + +void feawn_neutralise(monsters* monster) +{ + if (you.religion == GOD_FEAWN + && monster->attitude == ATT_HOSTILE + && feawn_neutralises(monster) + && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) + && !player_under_penance()) + { + // We must call remove_auto_exclude before neutralizing the + // plant because remove_auto_exclude only removes exclusions + // it thinks were caused by auto-exclude, and + // auto-exclusions now check for ATT_HOSTILE. Oh, what a + // tangled web, etc. + remove_auto_exclude(monster, false); + + feawn_neutralise_plant(monster); + monster->flags |= MF_ATT_CHANGE_ATTEMPT; + + stop_running(); + } +} + +static bool _holy_beings_on_level_attitude_change() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (monster->alive() + && mons_is_holy(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Holy attitude changing: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + // If you worship a good god, you get another chance to make + // neutral and hostile holy beings good neutral. + if (is_good_god(you.religion) && !mons_wont_attack(monster)) + { + if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) + { + monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; + + success = true; + } + } + // If you don't worship a good god, you make all friendly + // and good neutral holy beings that worship a good god + // hostile. + else if (!is_good_god(you.religion) && mons_wont_attack(monster) + && is_good_god(monster->god)) + { + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + + success = true; + } + } + } + + return (success); +} + +bool holy_beings_attitude_change() +{ + return (apply_to_all_dungeons(_holy_beings_on_level_attitude_change)); +} + +static bool _evil_beings_on_level_attitude_change() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (monster->alive() + && monster->is_evil()) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Evil attitude changing: %s " + "on level %d, branch %d", + monster->name(DESC_PLAIN, true).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + // If you worship a good god, you make all friendly and good + // neutral evil and unholy beings hostile. + if (is_good_god(you.religion) && mons_wont_attack(monster)) + { + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + + success = true; + } + } + } + + return (success); +} + +bool evil_beings_attitude_change() +{ + return (apply_to_all_dungeons(_evil_beings_on_level_attitude_change)); +} + +static bool _chaotic_beings_on_level_attitude_change() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (monster->alive() + && monster->is_chaotic()) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Chaotic attitude changing: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + // If you worship Zin, you make all friendly and good neutral + // chaotic beings hostile. + if (you.religion == GOD_ZIN && mons_wont_attack(monster)) + { + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + + success = true; + } + } + } + + return (success); +} + +bool chaotic_beings_attitude_change() +{ + return (apply_to_all_dungeons(_chaotic_beings_on_level_attitude_change)); +} + +static bool _magic_users_on_level_attitude_change() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (monster->alive() + && mons_is_magic_user(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Magic user attitude changing: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + // If you worship Trog, you make all friendly and good neutral + // magic users hostile. + if (you.religion == GOD_TROG && mons_wont_attack(monster)) + { + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. + + success = true; + } + } + } + + return (success); +} + +bool magic_users_attitude_change() +{ + return (apply_to_all_dungeons(_magic_users_on_level_attitude_change)); +} + +// Make summoned (temporary) god gifts disappear on penance or when +// abandoning the god in question. If seen, only count monsters where +// the player can see the change, and output a message. +static bool _make_god_gifts_on_level_disappear(bool seen = false) +{ + const god_type god = + (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() + : GOD_NO_GOD; + int count = 0; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (is_follower(monster) + && monster->has_ench(ENCH_ABJ) + && mons_is_god_gift(monster, god)) + { + if (!seen || simple_monster_message(monster, " abandons you!")) + count++; + + // The monster disappears. + monster_die(monster, KILL_DISMISSED, NON_MONSTER); + } + } + + return (count); +} + +static bool _god_gifts_disappear_wrapper() +{ + return (_make_god_gifts_on_level_disappear()); +} + +// Make god gifts disappear on all levels, or on only the current one. +bool make_god_gifts_disappear(bool level_only) +{ + bool success = _make_god_gifts_on_level_disappear(true); + + if (level_only) + return (success); + + return (apply_to_all_dungeons(_god_gifts_disappear_wrapper) || success); +} + +// When abandoning the god in question, turn holy god gifts good +// neutral. If seen, only count monsters where the player can see the +// change, and output a message. +static bool _make_holy_god_gifts_on_level_good_neutral(bool seen = false) +{ + const god_type god = + (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() + : GOD_NO_GOD; + int count = 0; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (is_follower(monster) + && !monster->has_ench(ENCH_CHARM) + && mons_is_holy(monster) + && mons_is_god_gift(monster, god)) + { + // monster changes attitude + monster->attitude = ATT_GOOD_NEUTRAL; + + if (!seen || simple_monster_message(monster, " becomes indifferent.")) + count++; + } + } + + return (count); +} + +static bool _holy_god_gifts_good_neutral_wrapper() +{ + return (_make_holy_god_gifts_on_level_good_neutral()); +} + +// Make holy god gifts turn good neutral on all levels, or on only the +// current one. +bool make_holy_god_gifts_good_neutral(bool level_only) +{ + bool success = _make_holy_god_gifts_on_level_good_neutral(true); + + if (level_only) + return (success); + + return (apply_to_all_dungeons(_holy_god_gifts_good_neutral_wrapper) || success); +} + +// When abandoning the god in question, turn god gifts hostile. If +// seen, only count monsters where the player can see the change, and +// output a message. +static bool _make_god_gifts_on_level_hostile(bool seen = false) +{ + const god_type god = + (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() + : GOD_NO_GOD; + int count = 0; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (is_follower(monster) + && mons_is_god_gift(monster, god)) + { + // monster changes attitude and behaviour + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + + if (!seen || simple_monster_message(monster, " turns against you!")) + count++; + } + } + + return (count); +} + +static bool _god_gifts_hostile_wrapper() +{ + return (_make_god_gifts_on_level_hostile()); +} + +// Make god gifts turn hostile on all levels, or on only the current +// one. +bool make_god_gifts_hostile(bool level_only) +{ + bool success = _make_god_gifts_on_level_hostile(true); + + if (level_only) + return (success); + + return (apply_to_all_dungeons(_god_gifts_hostile_wrapper) || success); +} + +static bool _is_yred_enslaved_body_and_soul(const monsters* mon) +{ + return (mon->alive() && mons_enslaved_body_and_soul(mon)); +} + +static bool _yred_slaves_on_level_abandon_you() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (_is_yred_enslaved_body_and_soul(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Undead soul abandoning: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + yred_make_enslaved_soul(monster, true, true, true); + + success = true; + } + else if (is_yred_undead_slave(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Undead abandoning: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + monster->attitude = ATT_HOSTILE; + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY stays. + + success = true; + } + } + + return (success); +} + +static bool _beogh_followers_on_level_abandon_you() +{ + bool success = false; + + // Note that orc high priests' summons are gifts of Beogh, so we + // can't use is_orcish_follower() here. + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (mons_is_god_gift(monster, GOD_BEOGH)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Orc abandoning: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + monster->attitude = ATT_HOSTILE; + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY stays. + + success = true; + } + } + + return (success); +} + +static bool _jiyva_slimes_on_level_abandon_you() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (is_fellow_slime(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Slime abandoning: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + monster->attitude = ATT_HOSTILE; + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now WAS_NEUTRAL stays. + + success = true; + } + } + + return (success); +} + +// Upon excommunication, ex-Yredelemnulites lose all their undead +// slaves. When under penance, Yredelemnulites can lose all undead +// slaves in sight. +bool yred_slaves_abandon_you() +{ + bool reclaim = false; + int num_reclaim = 0; + int num_slaves = 0; + + if (you.religion != GOD_YREDELEMNUL) + reclaim = apply_to_all_dungeons(_yred_slaves_on_level_abandon_you); + else + { + for (radius_iterator ri(you.pos(), 9); ri; ++ri) + { + monsters *monster = monster_at(*ri); + if (monster == NULL) + continue; + + if (_is_yred_enslaved_body_and_soul(monster) + || is_yred_undead_slave(monster)) + { + num_slaves++; + + const int hd = monster->hit_dice; + + // During penance, followers get a saving throw. + if (random2((you.piety - you.penance[GOD_YREDELEMNUL]) / 18) + + random2(you.skills[SK_INVOCATIONS] - 6) + > random2(hd) + hd + random2(5)) + { + continue; + } + + + if (_is_yred_enslaved_body_and_soul(monster)) + yred_make_enslaved_soul(monster, true, true, true); + else + { + monster->attitude = ATT_HOSTILE; + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY stays. + } + + num_reclaim++; + + reclaim = true; + } + } + } + + if (reclaim) + { + if (you.religion != GOD_YREDELEMNUL) + { + simple_god_message(" reclaims all of your granted undead slaves!", + GOD_YREDELEMNUL); + } + else if (num_reclaim > 0) + { + if (num_reclaim == 1 && num_slaves > 1) + simple_god_message(" reclaims one of your granted undead slaves!"); + else if (num_reclaim == num_slaves) + simple_god_message(" reclaims your granted undead slaves!"); + else + simple_god_message(" reclaims some of your granted undead slaves!"); + } + + return (true); + } + + return (false); +} + +static bool _feawn_plants_on_level_hostile() +{ + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (monster->alive() + && mons_is_plant(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Plant hostility: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + // You can potentially turn an oklob or whatever neutral + // again by going back to Feawn. + if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) + monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; + + monster->attitude = ATT_HOSTILE; + monster->del_ench(ENCH_CHARM, true); + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now WAS_NEUTRAL stays. + } + } + + return (true); +} + +bool feawn_plants_hostile() +{ + if (apply_to_all_dungeons(_feawn_plants_on_level_hostile)) + { + mpr("The plants of the dungeon turn on you!", MSGCH_GOD); + return (true); + } + + return (false); +} + +// Upon excommunication, ex-Beoghites lose all their orcish followers, +// plus all monsters created by their priestly orcish followers. When +// under penance, Beoghites can lose all orcish followers in sight, +// subject to a few limitations. +bool beogh_followers_abandon_you() +{ + bool reconvert = false; + int num_reconvert = 0; + int num_followers = 0; + + if (you.religion != GOD_BEOGH) + { + reconvert = + apply_to_all_dungeons(_beogh_followers_on_level_abandon_you); + } + else + { + for (radius_iterator ri(you.pos(), 9); ri; ++ri) + { + monsters *monster = monster_at(*ri); + if (monster == NULL) + continue; + + // Note that orc high priests' summons are gifts of Beogh, + // so we can't use is_orcish_follower() here. + if (mons_is_god_gift(monster, GOD_BEOGH)) + { + num_followers++; + + if (you.visible_to(monster) + && !monster->asleep() + && !mons_is_confused(monster) + && !mons_cannot_act(monster)) + { + const int hd = monster->hit_dice; + + // During penance, followers get a saving throw. + if (random2((you.piety - you.penance[GOD_BEOGH]) / 18) + + random2(you.skills[SK_INVOCATIONS] - 6) + > random2(hd) + hd + random2(5)) + { + continue; + } + + monster->attitude = ATT_HOSTILE; + behaviour_event(monster, ME_ALERT, MHITYOU); + // For now CREATED_FRIENDLY stays. + + if (you.can_see(monster)) + num_reconvert++; // Only visible ones. + + reconvert = true; + } + } + } + } + + if (reconvert) // Maybe all of them are invisible. + { + simple_god_message("'s voice booms out, \"Who do you think you " + "are?\"", GOD_BEOGH); + + std::ostream& chan = msg::streams(MSGCH_MONSTER_ENCHANT); + + if (you.religion != GOD_BEOGH) + chan << "All of your followers decide to abandon you."; + else if (num_reconvert > 0) + { + if (num_reconvert == 1 && num_followers > 1) + chan << "One of your followers decides to abandon you."; + else if (num_reconvert == num_followers) + chan << "Your followers decide to abandon you."; + else + chan << "Some of your followers decide to abandon you."; + } + + chan << std::endl; + + return (true); + } + + return (false); +} + +// Upon excommunication, ex-Jiyvaites lose all their fellow slimes. +bool jiyva_slimes_abandon_you() +{ + if (apply_to_all_dungeons(_jiyva_slimes_on_level_abandon_you)) + { + std::ostream& chan = msg::streams(MSGCH_MONSTER_ENCHANT); + + chan << "All of your fellow slimes turn on you." << std::endl; + + return (true); + } + + return (false); +} + +static void _print_good_god_holy_being_speech(bool neutral, + const std::string key, + monsters *mon, + msg_channel_type channel) +{ + std::string full_key = "good_god_"; + if (!neutral) + full_key += "non"; + full_key += "neutral_holy_being_"; + full_key += key; + + std::string msg = getSpeakString(full_key); + + if (!msg.empty()) + { + msg = do_mon_str_replacements(msg, mon); + mpr(msg.c_str(), channel); + } +} + +// Holy monsters may turn good neutral when encountering followers of +// the good gods, and be made worshippers of TSO if necessary. +void good_god_holy_attitude_change(monsters *holy) +{ + ASSERT(mons_is_holy(holy)); + + if (you.can_see(holy)) // show reaction + { + _print_good_god_holy_being_speech(true, "reaction", holy, + MSGCH_FRIEND_ENCHANT); + + if (!one_chance_in(3)) + _print_good_god_holy_being_speech(true, "speech", holy, + MSGCH_TALK); + } + + holy->attitude = ATT_GOOD_NEUTRAL; + + // The monster is not really *created* neutral, but should it become + // hostile later on, it won't count as a good kill. + holy->flags |= MF_WAS_NEUTRAL; + + // If the holy being was previously worshipping a different god, + // make it worship TSO. + holy->god = GOD_SHINING_ONE; + + // Avoid immobile "followers". + behaviour_event(holy, ME_ALERT, MHITNOT); +} + +void good_god_holy_fail_attitude_change(monsters *holy) +{ + ASSERT(mons_is_holy(holy)); + + if (you.can_see(holy)) // show reaction + { + _print_good_god_holy_being_speech(false, "reaction", holy, + MSGCH_FRIEND_ENCHANT); + + if (!one_chance_in(3)) + _print_good_god_holy_being_speech(false, "speech", holy, + MSGCH_TALK); + } +} + +static void _print_converted_orc_speech(const std::string key, + monsters *mon, + msg_channel_type channel) +{ + std::string msg = getSpeakString("beogh_converted_orc_" + key); + + if (!msg.empty()) + { + msg = do_mon_str_replacements(msg, mon); + mpr(msg.c_str(), channel); + } +} + +// Orcs may turn friendly when encountering followers of Beogh, and be +// made gifts of Beogh. +void beogh_convert_orc(monsters *orc, bool emergency, + bool converted_by_follower) +{ + ASSERT(mons_species(orc->type) == MONS_ORC); + + if (you.can_see(orc)) // show reaction + { + if (emergency || !orc->alive()) + { + if (converted_by_follower) + { + _print_converted_orc_speech("reaction_battle_follower", orc, + MSGCH_FRIEND_ENCHANT); + _print_converted_orc_speech("speech_battle_follower", orc, + MSGCH_TALK); + } + else + { + _print_converted_orc_speech("reaction_battle", orc, + MSGCH_FRIEND_ENCHANT); + _print_converted_orc_speech("speech_battle", orc, MSGCH_TALK); + } + } + else + { + _print_converted_orc_speech("reaction_sight", orc, + MSGCH_FRIEND_ENCHANT); + + if (!one_chance_in(3)) + _print_converted_orc_speech("speech_sight", orc, MSGCH_TALK); + } + } + + orc->attitude = ATT_FRIENDLY; + + // The monster is not really *created* friendly, but should it + // become hostile later on, it won't count as a good kill. + orc->flags |= MF_CREATED_FRIENDLY; + + // Prevent assertion if the orc was previously worshipping a + // different god, rather than already worshipping Beogh or being an + // atheist. + orc->god = GOD_NO_GOD; + + mons_make_god_gift(orc, GOD_BEOGH); + + if (orc->is_patrolling()) + { + // Make orcs stop patrolling and forget their patrol point, + // they're supposed to follow you now. + orc->patrol_point = coord_def(0, 0); + } + + if (!orc->alive()) + orc->hit_points = std::min(random_range(1, 4), orc->max_hit_points); + + // Avoid immobile "followers". + behaviour_event(orc, ME_ALERT, MHITNOT); +} + +void feawn_neutralise_plant(monsters *plant) +{ + if (!plant + || !feawn_neutralises(plant) + || plant->attitude != ATT_HOSTILE + || testbits(plant->flags, MF_ATT_CHANGE_ATTEMPT)) + { + return; + } + + plant->attitude = ATT_GOOD_NEUTRAL; + plant->flags |= MF_WAS_NEUTRAL; +} + +void jiyva_convert_slime(monsters* slime) +{ + ASSERT(mons_is_slime(slime)); + + if (you.can_see(slime)) + { + if (mons_genus(slime->type) == MONS_GIANT_EYEBALL) + { + mprf(MSGCH_GOD, "%s stares at you suspiciously for a moment, " + "then relaxes.", + + slime->name(DESC_CAP_THE).c_str()); + } + else + { + mprf(MSGCH_GOD, "%s trembles before you.", + slime->name(DESC_CAP_THE).c_str()); + } + } + + slime->attitude = ATT_STRICT_NEUTRAL; + slime->flags |= MF_WAS_NEUTRAL; + + if (!mons_eats_items(slime)) + { + slime->add_ench(ENCH_EAT_ITEMS); + + mprf(MSGCH_MONSTER_ENCHANT, "%s looks hungrier.", + slime->name(DESC_CAP_THE).c_str()); + } + + // Prevent assertion if the slime was previously worshipping a + // different god, rather than already worshipping Jiyva or being an + // atheist. + slime->god = GOD_NO_GOD; + + mons_make_god_gift(slime, GOD_JIYVA); +} diff --git a/crawl-ref/source/attitude-change.h b/crawl-ref/source/attitude-change.h new file mode 100644 index 0000000000..784edd8131 --- /dev/null +++ b/crawl-ref/source/attitude-change.h @@ -0,0 +1,26 @@ +#ifndef ATTITUDE_CHANGE_H +#define ATTITUDE_CHANGE_H + +void good_god_follower_attitude_change(monsters *monster); +void feawn_neutralise(monsters* monster); +bool feawn_plants_hostile(); +void beogh_follower_convert(monsters *monster, bool orc_hit = false); +void slime_convert(monsters *monster); +bool holy_beings_attitude_change(); +bool evil_beings_attitude_change(); +bool chaotic_beings_attitude_change(); +bool magic_users_attitude_change(); +bool yred_slaves_abandon_you(); +bool beogh_followers_abandon_you(); +bool jiyva_slimes_abandon_you(); +bool make_god_gifts_disappear(bool level_only = true); +bool make_holy_god_gifts_good_neutral(bool level_only = true); +bool make_god_gifts_hostile(bool level_only = true); +void good_god_holy_attitude_change(monsters *holy); +void good_god_holy_fail_attitude_change(monsters *holy); +void beogh_convert_orc(monsters *orc, bool emergency, + bool converted_by_follower = false); +void jiyva_convert_slime(monsters* slime); +void feawn_neutralise_plant(monsters *plant); + +#endif diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 81500142cf..1b4426a890 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -25,6 +25,7 @@ #include "externs.h" #include "options.h" +#include "attitude-change.h" #include "cio.h" #include "cloud.h" #include "colour.h" diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index f9b887cbf5..8297f964b8 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -13,6 +13,7 @@ #include "abl-show.h" #include "artefact.h" +#include "attitude-change.h" #include "clua.h" #include "command.h" #include "coordit.h" diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 235b19ab48..3d96da7b96 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -21,6 +21,7 @@ #include "options.h" #include "artefact.h" +#include "attitude-change.h" #include "beam.h" #include "cloud.h" #include "database.h" diff --git a/crawl-ref/source/godabil.cc b/crawl-ref/source/godabil.cc index 3aec727fec..496a4c5a9c 100644 --- a/crawl-ref/source/godabil.cc +++ b/crawl-ref/source/godabil.cc @@ -308,95 +308,6 @@ void yred_make_enslaved_soul(monsters *mon, bool force_hostile, } } -static void _print_converted_orc_speech(const std::string key, - monsters *mon, - msg_channel_type channel) -{ - std::string msg = getSpeakString("beogh_converted_orc_" + key); - - if (!msg.empty()) - { - msg = do_mon_str_replacements(msg, mon); - mpr(msg.c_str(), channel); - } -} - -// Orcs may turn friendly when encountering followers of Beogh, and be -// made gifts of Beogh. -void beogh_convert_orc(monsters *orc, bool emergency, - bool converted_by_follower) -{ - ASSERT(mons_species(orc->type) == MONS_ORC); - - if (you.can_see(orc)) // show reaction - { - if (emergency || !orc->alive()) - { - if (converted_by_follower) - { - _print_converted_orc_speech("reaction_battle_follower", orc, - MSGCH_FRIEND_ENCHANT); - _print_converted_orc_speech("speech_battle_follower", orc, - MSGCH_TALK); - } - else - { - _print_converted_orc_speech("reaction_battle", orc, - MSGCH_FRIEND_ENCHANT); - _print_converted_orc_speech("speech_battle", orc, MSGCH_TALK); - } - } - else - { - _print_converted_orc_speech("reaction_sight", orc, - MSGCH_FRIEND_ENCHANT); - - if (!one_chance_in(3)) - _print_converted_orc_speech("speech_sight", orc, MSGCH_TALK); - } - } - - orc->attitude = ATT_FRIENDLY; - - // The monster is not really *created* friendly, but should it - // become hostile later on, it won't count as a good kill. - orc->flags |= MF_CREATED_FRIENDLY; - - // Prevent assertion if the orc was previously worshipping a - // different god, rather than already worshipping Beogh or being an - // atheist. - orc->god = GOD_NO_GOD; - - mons_make_god_gift(orc, GOD_BEOGH); - - if (orc->is_patrolling()) - { - // Make orcs stop patrolling and forget their patrol point, - // they're supposed to follow you now. - orc->patrol_point = coord_def(0, 0); - } - - if (!orc->alive()) - orc->hit_points = std::min(random_range(1, 4), orc->max_hit_points); - - // Avoid immobile "followers". - behaviour_event(orc, ME_ALERT, MHITNOT); -} - -void feawn_neutralise_plant(monsters *plant) -{ - if (!plant - || !feawn_neutralises(plant) - || plant->attitude != ATT_HOSTILE - || testbits(plant->flags, MF_ATT_CHANGE_ATTEMPT)) - { - return; - } - - plant->attitude = ATT_GOOD_NEUTRAL; - plant->flags |= MF_WAS_NEUTRAL; -} - // Feawn allows worshipers to walk on top of stationary plants and // fungi. bool feawn_passthrough(const monsters * target) @@ -408,45 +319,6 @@ bool feawn_passthrough(const monsters * target) || target->attitude != ATT_HOSTILE)); } -void jiyva_convert_slime(monsters* slime) -{ - ASSERT(mons_is_slime(slime)); - - if (you.can_see(slime)) - { - if (mons_genus(slime->type) == MONS_GIANT_EYEBALL) - { - mprf(MSGCH_GOD, "%s stares at you suspiciously for a moment, " - "then relaxes.", - - slime->name(DESC_CAP_THE).c_str()); - } - else - { - mprf(MSGCH_GOD, "%s trembles before you.", - slime->name(DESC_CAP_THE).c_str()); - } - } - - slime->attitude = ATT_STRICT_NEUTRAL; - slime->flags |= MF_WAS_NEUTRAL; - - if (!mons_eats_items(slime)) - { - slime->add_ench(ENCH_EAT_ITEMS); - - mprf(MSGCH_MONSTER_ENCHANT, "%s looks hungrier.", - slime->name(DESC_CAP_THE).c_str()); - } - - // Prevent assertion if the slime was previously worshipping a - // different god, rather than already worshipping Jiyva or being an - // atheist. - slime->god = GOD_NO_GOD; - - mons_make_god_gift(slime, GOD_JIYVA); -} - bool ponderousify_armour() { int item_slot = -1; diff --git a/crawl-ref/source/godabil.h b/crawl-ref/source/godabil.h index 16a2f8e376..81cd805150 100644 --- a/crawl-ref/source/godabil.h +++ b/crawl-ref/source/godabil.h @@ -18,10 +18,6 @@ bool jiyva_remove_bad_mutation(); bool beogh_water_walk(); void yred_make_enslaved_soul(monsters *mon, bool force_hostile = false, bool quiet = false, bool unrestricted = false); -void beogh_convert_orc(monsters *orc, bool emergency, - bool converted_by_follower = false); -void jiyva_convert_slime(monsters* slime); -void feawn_neutralise_plant(monsters *plant); bool feawn_passthrough(const monsters * target); bool vehumet_supports_spell(spell_type spell); diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index f9ba36d16b..1797c7bd18 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -5,6 +5,7 @@ acr.o \ actor.o \ arena.o \ artefact.o \ +attitude-change.o \ beam.o \ behold.o \ bitary.o \ diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 846373aa25..47306728ab 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -18,6 +18,7 @@ #include "arena.h" #include "artefact.h" +#include "attitude-change.h" #include "cloud.h" #include "delay.h" #include "dgnevent.h" diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 720d31d1cd..e68cdf3b7e 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -24,6 +24,7 @@ #include "abl-show.h" #include "artefact.h" +#include "attitude-change.h" #include "beam.h" #include "chardump.h" #include "database.h" @@ -415,13 +416,6 @@ const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] = } }; -static bool _holy_beings_attitude_change(); -static bool _evil_beings_attitude_change(); -static bool _chaotic_beings_attitude_change(); -static bool _magic_users_attitude_change(); -static bool _yred_slaves_abandon_you(); -static bool _beogh_followers_abandon_you(); -static bool _jiyva_slimes_abandon_you(); static void _god_smites_you(god_type god, const char *message = NULL, kill_method_type death_type = NUM_KILLBY); static bool _beogh_idol_revenge(); @@ -430,9 +424,6 @@ static bool _tso_holy_revenge(); static bool _altar_prayer(); static bool _god_likes_item(god_type god, const item_def& item); static void _dock_piety(int piety_loss, int penance); -static bool _make_god_gifts_disappear(bool level_only = true); -static bool _make_holy_god_gifts_good_neutral(bool level_only = true); -static bool _make_god_gifts_hostile(bool level_only = true); static void _print_sacrifice_message(god_type, const item_def &, piety_gain_t, bool = false); @@ -943,7 +934,7 @@ void dec_penance(god_type god, int val) // When you've worked through all your penance, you get // another chance to make hostile holy beings good neutral. if (is_good_god(you.religion)) - _holy_beings_attitude_change(); + holy_beings_attitude_change(); } else if (god == GOD_NEMELEX_XOBEH && you.penance[god] > 100) { // Nemelex' penance works actively only until 100 @@ -1050,7 +1041,7 @@ static void _inc_penance(god_type god, int val) if (you.attribute[ATTR_DIVINE_REGENERATION]) remove_regen(true); - _make_god_gifts_disappear(); // only on level + make_god_gifts_disappear(); // only on level } // Neither does Zin's divine stamina. else if (god == GOD_ZIN) @@ -1067,7 +1058,7 @@ static void _inc_penance(god_type god, int val) if (you.duration[DUR_DIVINE_SHIELD]) remove_divine_shield(); - _make_god_gifts_disappear(); // only on level + make_god_gifts_disappear(); // only on level } // Neither does Ely's divine vigour. else if (god == GOD_ELYVILON) @@ -1426,11 +1417,6 @@ bool mons_is_god_gift(const monsters *mon, god_type god) return ((mon->flags & MF_GOD_GIFT) && mon->god == god); } -static bool _is_yred_enslaved_body_and_soul(const monsters* mon) -{ - return (mon->alive() && mons_enslaved_body_and_soul(mon)); -} - bool is_undead_slave(const monsters* mon) { return (mon->alive() && mon->holiness() == MH_UNDEAD @@ -3797,7 +3783,7 @@ void gain_piety(int pgn) // When you gain a piety level, you get another chance to // make hostile holy beings good neutral. if (is_good_god(you.religion)) - _holy_beings_attitude_change(); + holy_beings_attitude_change(); } } @@ -3836,7 +3822,7 @@ void gain_piety(int pgn) // When you gain piety of more than 160, you get another chance // to make hostile holy beings good neutral. if (is_good_god(you.religion)) - _holy_beings_attitude_change(); + holy_beings_attitude_change(); } _do_god_gift(false); @@ -4419,7 +4405,7 @@ static bool _yredelemnul_retribution() god); } else if (you.religion == god && coinflip() - && _yred_slaves_abandon_you()) + && yred_slaves_abandon_you()) { ; } @@ -4649,7 +4635,7 @@ static bool _beogh_retribution() } case 4: // 25%, relatively harmless case 5: // in effect, only for penance - if (you.religion == god && _beogh_followers_abandon_you()) + if (you.religion == god && beogh_followers_abandon_you()) break; // else fall through default: // send orcs after you (3/8 to 5/8) @@ -5125,622 +5111,6 @@ bool divine_retribution(god_type god) return (did_retrib); } -static bool _holy_beings_on_level_attitude_change() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (monster->alive() - && mons_is_holy(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Holy attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - // If you worship a good god, you get another chance to make - // neutral and hostile holy beings good neutral. - if (is_good_god(you.religion) && !mons_wont_attack(monster)) - { - if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) - { - monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; - - success = true; - } - } - // If you don't worship a good god, you make all friendly - // and good neutral holy beings that worship a good god - // hostile. - else if (!is_good_god(you.religion) && mons_wont_attack(monster) - && is_good_god(monster->god)) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - - success = true; - } - } - } - - return (success); -} - -static bool _holy_beings_attitude_change() -{ - return (apply_to_all_dungeons(_holy_beings_on_level_attitude_change)); -} - -static bool _evil_beings_on_level_attitude_change() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (monster->alive() - && monster->is_evil()) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Evil attitude changing: %s " - "on level %d, branch %d", - monster->name(DESC_PLAIN, true).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - // If you worship a good god, you make all friendly and good - // neutral evil and unholy beings hostile. - if (is_good_god(you.religion) && mons_wont_attack(monster)) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - - success = true; - } - } - } - - return (success); -} - -static bool _evil_beings_attitude_change() -{ - return (apply_to_all_dungeons(_evil_beings_on_level_attitude_change)); -} - -static bool _chaotic_beings_on_level_attitude_change() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (monster->alive() - && monster->is_chaotic()) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Chaotic attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - // If you worship Zin, you make all friendly and good neutral - // chaotic beings hostile. - if (you.religion == GOD_ZIN && mons_wont_attack(monster)) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - - success = true; - } - } - } - - return (success); -} - -static bool _chaotic_beings_attitude_change() -{ - return (apply_to_all_dungeons(_chaotic_beings_on_level_attitude_change)); -} - -static bool _magic_users_on_level_attitude_change() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (monster->alive() - && mons_is_magic_user(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Magic user attitude changing: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - // If you worship Trog, you make all friendly and good neutral - // magic users hostile. - if (you.religion == GOD_TROG && mons_wont_attack(monster)) - { - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY/WAS_NEUTRAL stays. - - success = true; - } - } - } - - return (success); -} - -static bool _magic_users_attitude_change() -{ - return (apply_to_all_dungeons(_magic_users_on_level_attitude_change)); -} - -// Make summoned (temporary) god gifts disappear on penance or when -// abandoning the god in question. If seen, only count monsters where -// the player can see the change, and output a message. -static bool _make_god_gifts_on_level_disappear(bool seen = false) -{ - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - int count = 0; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (is_follower(monster) - && monster->has_ench(ENCH_ABJ) - && mons_is_god_gift(monster, god)) - { - if (!seen || simple_monster_message(monster, " abandons you!")) - count++; - - // The monster disappears. - monster_die(monster, KILL_DISMISSED, NON_MONSTER); - } - } - - return (count); -} - -static bool _god_gifts_disappear_wrapper() -{ - return (_make_god_gifts_on_level_disappear()); -} - -// Make god gifts disappear on all levels, or on only the current one. -static bool _make_god_gifts_disappear(bool level_only) -{ - bool success = _make_god_gifts_on_level_disappear(true); - - if (level_only) - return (success); - - return (apply_to_all_dungeons(_god_gifts_disappear_wrapper) || success); -} - -// When abandoning the god in question, turn holy god gifts good -// neutral. If seen, only count monsters where the player can see the -// change, and output a message. -static bool _make_holy_god_gifts_on_level_good_neutral(bool seen = false) -{ - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - int count = 0; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (is_follower(monster) - && !monster->has_ench(ENCH_CHARM) - && mons_is_holy(monster) - && mons_is_god_gift(monster, god)) - { - // monster changes attitude - monster->attitude = ATT_GOOD_NEUTRAL; - - if (!seen || simple_monster_message(monster, " becomes indifferent.")) - count++; - } - } - - return (count); -} - -static bool _holy_god_gifts_good_neutral_wrapper() -{ - return (_make_holy_god_gifts_on_level_good_neutral()); -} - -// Make holy god gifts turn good neutral on all levels, or on only the -// current one. -static bool _make_holy_god_gifts_good_neutral(bool level_only) -{ - bool success = _make_holy_god_gifts_on_level_good_neutral(true); - - if (level_only) - return (success); - - return (apply_to_all_dungeons(_holy_god_gifts_good_neutral_wrapper) || success); -} - -// When abandoning the god in question, turn god gifts hostile. If -// seen, only count monsters where the player can see the change, and -// output a message. -static bool _make_god_gifts_on_level_hostile(bool seen = false) -{ - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - int count = 0; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (is_follower(monster) - && mons_is_god_gift(monster, god)) - { - // monster changes attitude and behaviour - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - - if (!seen || simple_monster_message(monster, " turns against you!")) - count++; - } - } - - return (count); -} - -static bool _god_gifts_hostile_wrapper() -{ - return (_make_god_gifts_on_level_hostile()); -} - -// Make god gifts turn hostile on all levels, or on only the current -// one. -static bool _make_god_gifts_hostile(bool level_only) -{ - bool success = _make_god_gifts_on_level_hostile(true); - - if (level_only) - return (success); - - return (apply_to_all_dungeons(_god_gifts_hostile_wrapper) || success); -} - -static bool _yred_slaves_on_level_abandon_you() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (_is_yred_enslaved_body_and_soul(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Undead soul abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - yred_make_enslaved_soul(monster, true, true, true); - - success = true; - } - else if (is_yred_undead_slave(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Undead abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY stays. - - success = true; - } - } - - return (success); -} - -static bool _beogh_followers_on_level_abandon_you() -{ - bool success = false; - - // Note that orc high priests' summons are gifts of Beogh, so we - // can't use is_orcish_follower() here. - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (mons_is_god_gift(monster, GOD_BEOGH)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Orc abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY stays. - - success = true; - } - } - - return (success); -} - -static bool _jiyva_slimes_on_level_abandon_you() -{ - bool success = false; - - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (is_fellow_slime(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Slime abandoning: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now WAS_NEUTRAL stays. - - success = true; - } - } - - return (success); -} - -// Upon excommunication, ex-Yredelemnulites lose all their undead -// slaves. When under penance, Yredelemnulites can lose all undead -// slaves in sight. -static bool _yred_slaves_abandon_you() -{ - bool reclaim = false; - int num_reclaim = 0; - int num_slaves = 0; - - if (you.religion != GOD_YREDELEMNUL) - reclaim = apply_to_all_dungeons(_yred_slaves_on_level_abandon_you); - else - { - for (radius_iterator ri(you.pos(), 9); ri; ++ri) - { - monsters *monster = monster_at(*ri); - if (monster == NULL) - continue; - - if (_is_yred_enslaved_body_and_soul(monster) - || is_yred_undead_slave(monster)) - { - num_slaves++; - - const int hd = monster->hit_dice; - - // During penance, followers get a saving throw. - if (random2((you.piety - you.penance[GOD_YREDELEMNUL]) / 18) - + random2(you.skills[SK_INVOCATIONS] - 6) - > random2(hd) + hd + random2(5)) - { - continue; - } - - - if (_is_yred_enslaved_body_and_soul(monster)) - yred_make_enslaved_soul(monster, true, true, true); - else - { - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY stays. - } - - num_reclaim++; - - reclaim = true; - } - } - } - - if (reclaim) - { - if (you.religion != GOD_YREDELEMNUL) - { - simple_god_message(" reclaims all of your granted undead slaves!", - GOD_YREDELEMNUL); - } - else if (num_reclaim > 0) - { - if (num_reclaim == 1 && num_slaves > 1) - simple_god_message(" reclaims one of your granted undead slaves!"); - else if (num_reclaim == num_slaves) - simple_god_message(" reclaims your granted undead slaves!"); - else - simple_god_message(" reclaims some of your granted undead slaves!"); - } - - return (true); - } - - return (false); -} - -static bool _feawn_plants_on_level_hostile() -{ - for (int i = 0; i < MAX_MONSTERS; ++i) - { - monsters *monster = &menv[i]; - if (monster->alive() - && mons_is_plant(monster)) - { -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Plant hostility: %s on level %d, branch %d", - monster->name(DESC_PLAIN).c_str(), - static_cast(you.your_level), - static_cast(you.where_are_you)); -#endif - - // You can potentially turn an oklob or whatever neutral - // again by going back to Feawn. - if (testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT)) - monster->flags &= ~MF_ATT_CHANGE_ATTEMPT; - - monster->attitude = ATT_HOSTILE; - monster->del_ench(ENCH_CHARM, true); - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now WAS_NEUTRAL stays. - } - } - - return (true); -} - -static bool _feawn_plants_hostile() -{ - if (apply_to_all_dungeons(_feawn_plants_on_level_hostile)) - { - mpr("The plants of the dungeon turn on you!", MSGCH_GOD); - return (true); - } - - return (false); -} - -// Upon excommunication, ex-Beoghites lose all their orcish followers, -// plus all monsters created by their priestly orcish followers. When -// under penance, Beoghites can lose all orcish followers in sight, -// subject to a few limitations. -static bool _beogh_followers_abandon_you() -{ - bool reconvert = false; - int num_reconvert = 0; - int num_followers = 0; - - if (you.religion != GOD_BEOGH) - { - reconvert = - apply_to_all_dungeons(_beogh_followers_on_level_abandon_you); - } - else - { - for (radius_iterator ri(you.pos(), 9); ri; ++ri) - { - monsters *monster = monster_at(*ri); - if (monster == NULL) - continue; - - // Note that orc high priests' summons are gifts of Beogh, - // so we can't use is_orcish_follower() here. - if (mons_is_god_gift(monster, GOD_BEOGH)) - { - num_followers++; - - if (you.visible_to(monster) - && !monster->asleep() - && !mons_is_confused(monster) - && !mons_cannot_act(monster)) - { - const int hd = monster->hit_dice; - - // During penance, followers get a saving throw. - if (random2((you.piety - you.penance[GOD_BEOGH]) / 18) - + random2(you.skills[SK_INVOCATIONS] - 6) - > random2(hd) + hd + random2(5)) - { - continue; - } - - monster->attitude = ATT_HOSTILE; - behaviour_event(monster, ME_ALERT, MHITYOU); - // For now CREATED_FRIENDLY stays. - - if (you.can_see(monster)) - num_reconvert++; // Only visible ones. - - reconvert = true; - } - } - } - } - - if (reconvert) // Maybe all of them are invisible. - { - simple_god_message("'s voice booms out, \"Who do you think you " - "are?\"", GOD_BEOGH); - - std::ostream& chan = msg::streams(MSGCH_MONSTER_ENCHANT); - - if (you.religion != GOD_BEOGH) - chan << "All of your followers decide to abandon you."; - else if (num_reconvert > 0) - { - if (num_reconvert == 1 && num_followers > 1) - chan << "One of your followers decides to abandon you."; - else if (num_reconvert == num_followers) - chan << "Your followers decide to abandon you."; - else - chan << "Some of your followers decide to abandon you."; - } - - chan << std::endl; - - return (true); - } - - return (false); -} - -// Upon excommunication, ex-Jiyvaites lose all their fellow slimes. -static bool _jiyva_slimes_abandon_you() -{ - if (apply_to_all_dungeons(_jiyva_slimes_on_level_abandon_you)) - { - std::ostream& chan = msg::streams(MSGCH_MONSTER_ENCHANT); - - chan << "All of your fellow slimes turn on you." << std::endl; - - return (true); - } - - return (false); -} - // Currently only used when orcish idols have been destroyed. static std::string _get_beogh_speech(const std::string key) { @@ -5780,71 +5150,6 @@ static bool _beogh_idol_revenge() return (false); } -static void _print_good_god_holy_being_speech(bool neutral, - const std::string key, - monsters *mon, - msg_channel_type channel) -{ - std::string full_key = "good_god_"; - if (!neutral) - full_key += "non"; - full_key += "neutral_holy_being_"; - full_key += key; - - std::string msg = getSpeakString(full_key); - - if (!msg.empty()) - { - msg = do_mon_str_replacements(msg, mon); - mpr(msg.c_str(), channel); - } -} - -// Holy monsters may turn good neutral when encountering followers of -// the good gods, and be made worshippers of TSO if necessary. -void good_god_holy_attitude_change(monsters *holy) -{ - ASSERT(mons_is_holy(holy)); - - if (you.can_see(holy)) // show reaction - { - _print_good_god_holy_being_speech(true, "reaction", holy, - MSGCH_FRIEND_ENCHANT); - - if (!one_chance_in(3)) - _print_good_god_holy_being_speech(true, "speech", holy, - MSGCH_TALK); - } - - holy->attitude = ATT_GOOD_NEUTRAL; - - // The monster is not really *created* neutral, but should it become - // hostile later on, it won't count as a good kill. - holy->flags |= MF_WAS_NEUTRAL; - - // If the holy being was previously worshipping a different god, - // make it worship TSO. - holy->god = GOD_SHINING_ONE; - - // Avoid immobile "followers". - behaviour_event(holy, ME_ALERT, MHITNOT); -} - -void good_god_holy_fail_attitude_change(monsters *holy) -{ - ASSERT(mons_is_holy(holy)); - - if (you.can_see(holy)) // show reaction - { - _print_good_god_holy_being_speech(false, "reaction", holy, - MSGCH_FRIEND_ENCHANT); - - if (!one_chance_in(3)) - _print_good_god_holy_being_speech(false, "speech", holy, - MSGCH_TALK); - } -} - static void _tso_blasts_cleansing_flame(const char *message) { // TSO won't protect you from his own cleansing flame, and Xom is too @@ -5985,7 +5290,7 @@ void excommunication(god_type new_god) break; case GOD_YREDELEMNUL: - _yred_slaves_abandon_you(); + yred_slaves_abandon_you(); MiscastEffect(&you, -old_god, SPTYP_NECROMANCY, 5 + you.experience_level, random2avg(88, 3), @@ -6013,7 +5318,7 @@ void excommunication(god_type new_god) if (you.attribute[ATTR_DIVINE_REGENERATION]) remove_regen(true); - _make_god_gifts_hostile(false); + make_god_gifts_hostile(false); // Penance has to come before retribution to prevent "mollify" _inc_penance(old_god, 50); @@ -6021,7 +5326,7 @@ void excommunication(god_type new_god) break; case GOD_BEOGH: - _beogh_followers_abandon_you(); // friendly orcs around turn hostile + beogh_followers_abandon_you(); // friendly orcs around turn hostile // You might have lost water walking at a bad time... if (_need_water_walking()) @@ -6065,10 +5370,10 @@ void excommunication(god_type new_god) if (!is_good_god(new_god)) { _inc_penance(old_god, 50); - _make_god_gifts_hostile(false); + make_god_gifts_hostile(false); } else - _make_holy_god_gifts_good_neutral(false); + make_holy_god_gifts_good_neutral(false); break; @@ -6087,7 +5392,7 @@ void excommunication(god_type new_god) god_acting good_gdact(GOD_SHINING_ONE, true); - _make_god_gifts_hostile(false); + make_god_gifts_hostile(false); } break; @@ -6103,12 +5408,12 @@ void excommunication(god_type new_god) god_acting good_gdact(GOD_SHINING_ONE, true); - _make_god_gifts_hostile(false); + make_god_gifts_hostile(false); } break; case GOD_JIYVA: - _jiyva_slimes_abandon_you(); + jiyva_slimes_abandon_you(); if (you.duration[DUR_SLIMIFY]) you.duration[DUR_SLIMIFY] = 0; @@ -6124,7 +5429,7 @@ void excommunication(god_type new_god) _inc_penance(old_god, 30); break; case GOD_FEAWN: - _feawn_plants_hostile(); + feawn_plants_hostile(); _inc_penance(old_god, 30); divine_retribution(old_god); break; @@ -6137,7 +5442,7 @@ void excommunication(god_type new_god) // When you start worshipping a non-good god, or no god, you make // all non-hostile holy beings that worship a good god hostile. - if (!is_good_god(new_god) && _holy_beings_attitude_change()) + if (!is_good_god(new_god) && holy_beings_attitude_change()) mpr("The divine host forsakes you.", MSGCH_MONSTER_ENCHANT); // Evil hack. @@ -6921,12 +6226,12 @@ void god_pitch(god_type which_god) // you make all non-hostile chaotic beings hostile; and when you // start worshipping Trog, you make all non-hostile magic users // hostile. - if (is_good_god(you.religion) && _evil_beings_attitude_change()) + if (is_good_god(you.religion) && evil_beings_attitude_change()) mpr("Your evil allies forsake you.", MSGCH_MONSTER_ENCHANT); - if (you.religion == GOD_ZIN && _chaotic_beings_attitude_change()) + if (you.religion == GOD_ZIN && chaotic_beings_attitude_change()) mpr("Your chaotic allies forsake you.", MSGCH_MONSTER_ENCHANT); - else if (you.religion == GOD_TROG && _magic_users_attitude_change()) + else if (you.religion == GOD_TROG && magic_users_attitude_change()) mpr("Your magic-using allies forsake you.", MSGCH_MONSTER_ENCHANT); if (you.religion == GOD_ELYVILON) diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h index a34119e39f..9c5eb8b89a 100644 --- a/crawl-ref/source/religion.h +++ b/crawl-ref/source/religion.h @@ -103,8 +103,6 @@ bool divine_retribution(god_type god); bool jiyva_is_dead(); bool remove_all_jiyva_altars(); -void good_god_holy_attitude_change(monsters *holy); -void good_god_holy_fail_attitude_change(monsters *holy); bool feawn_protects(const monsters * target); bool feawn_protects_species(int mc); bool feawn_neutralises(const monsters * target); diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc index e4f451dc6b..a2ab4089cf 100644 --- a/crawl-ref/source/spells1.cc +++ b/crawl-ref/source/spells1.cc @@ -15,10 +15,10 @@ #include #include "externs.h" -#include "options.h" #include "abyss.h" #include "artefact.h" +#include "attitude-change.h" #include "beam.h" #include "cloud.h" #include "coord.h" @@ -35,6 +35,7 @@ #include "misc.h" #include "monstuff.h" #include "mon-util.h" +#include "options.h" #include "player.h" #include "religion.h" #include "skills2.h" diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 1f9155c926..3383708825 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -27,6 +27,7 @@ #include "viewmap.h" #include "showsymb.h" +#include "attitude-change.h" #include "branch.h" #include "command.h" #include "cio.h" @@ -100,127 +101,6 @@ bool is_notable_terrain(dungeon_feature_type ftype) return (get_feature_def(ftype).is_notable()); } -static void _good_god_follower_attitude_change(monsters *monster) -{ - if (you.is_unholy() || crawl_state.arena) - return; - - // For followers of good gods, decide whether holy beings will be - // good neutral towards you. - if (is_good_god(you.religion) - && monster->foe == MHITYOU - && mons_is_holy(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) - && !mons_wont_attack(monster) - && you.visible_to(monster) && !monster->asleep() - && !mons_is_confused(monster) && !monster->paralysed()) - { - monster->flags |= MF_ATT_CHANGE_ATTEMPT; - - if (x_chance_in_y(you.piety, MAX_PIETY) && !you.penance[you.religion]) - { - const item_def* wpn = you.weapon(); - if (wpn - && wpn->base_type == OBJ_WEAPONS - && is_evil_item(*wpn) - && coinflip()) // 50% chance of conversion failing - { - msg::stream << monster->name(DESC_CAP_THE) - << " glares at your weapon." - << std::endl; - good_god_holy_fail_attitude_change(monster); - return; - } - good_god_holy_attitude_change(monster); - stop_running(); - } - else - good_god_holy_fail_attitude_change(monster); - } -} - -void beogh_follower_convert(monsters *monster, bool orc_hit) -{ - if (you.species != SP_HILL_ORC || crawl_state.arena) - return; - - // For followers of Beogh, decide whether orcs will join you. - if (you.religion == GOD_BEOGH - && monster->foe == MHITYOU - && mons_species(monster->type) == MONS_ORC - && !mons_is_summoned(monster) - && !mons_is_shapeshifter(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) - && !mons_friendly(monster) - && you.visible_to(monster) && !monster->asleep() - && !mons_is_confused(monster) && !monster->paralysed()) - { - monster->flags |= MF_ATT_CHANGE_ATTEMPT; - - const int hd = monster->hit_dice; - - if (you.piety >= piety_breakpoint(2) && !player_under_penance() - && random2(you.piety / 15) + random2(4 + you.experience_level / 3) - > random2(hd) + hd + random2(5)) - { - if (you.weapon() - && you.weapon()->base_type == OBJ_WEAPONS - && get_weapon_brand(*you.weapon()) == SPWPN_ORC_SLAYING - && coinflip()) // 50% chance of conversion failing - { - msg::stream << monster->name(DESC_CAP_THE) - << " flinches from your weapon." - << std::endl; - return; - } - beogh_convert_orc(monster, orc_hit); - stop_running(); - } - } -} - -void slime_convert(monsters* monster) -{ - if (you.religion == GOD_JIYVA && mons_is_slime(monster) - && !mons_is_summoned(monster) - && !mons_is_shapeshifter(monster) - && !mons_neutral(monster) - && !mons_friendly(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) - && you.visible_to(monster) && !monster->asleep() - && !mons_is_confused(monster) && !monster->paralysed()) - { - monster->flags |= MF_ATT_CHANGE_ATTEMPT; - if (!player_under_penance()) - { - jiyva_convert_slime(monster); - stop_running(); - } - } -} - -void feawn_neutralise(monsters* monster) -{ - if (you.religion == GOD_FEAWN - && monster->attitude == ATT_HOSTILE - && feawn_neutralises(monster) - && !testbits(monster->flags, MF_ATT_CHANGE_ATTEMPT) - && !player_under_penance()) - { - // We must call remove_auto_exclude before neutralizing the - // plant because remove_auto_exclude only removes exclusions - // it thinks were caused by auto-exclude, and - // auto-exclusions now check for ATT_HOSTILE. Oh, what a - // tangled web, etc. - remove_auto_exclude(monster, false); - - feawn_neutralise_plant(monster); - monster->flags |= MF_ATT_CHANGE_ATTEMPT; - - stop_running(); - } -} - void handle_seen_interrupt(monsters* monster) { if (mons_is_unknown_mimic(monster)) @@ -541,7 +421,7 @@ void monster_grid(bool do_updates) tile_place_monster(monster->pos().x, monster->pos().y, s, true); #endif - _good_god_follower_attitude_change(monster); + good_god_follower_attitude_change(monster); beogh_follower_convert(monster); slime_convert(monster); feawn_neutralise(monster); diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index 4df53354d8..9c8445f508 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -13,8 +13,6 @@ void init_monsters_seens(); -void beogh_follower_convert(monsters *monster, bool orc_hit = false); -void slime_convert(monsters *monster); bool mons_near(const monsters *monster); bool mon_enemies_around(const monsters *monster); -- cgit v1.2.3-54-g00ecf