diff options
author | Nicholas Feinberg <pleasingfung@gmail.com> | 2014-06-18 21:32:02 -0700 |
---|---|---|
committer | Nicholas Feinberg <pleasingfung@gmail.com> | 2014-06-18 21:32:02 -0700 |
commit | c530747fc02029b177cd1216f9145b12847b1b62 (patch) | |
tree | 59187bf64248f4b60ff3c879f6427403582b55fe /crawl-ref/source/religion.cc | |
parent | 46ce0616d57d90a693cfe757f59fa6ce3097453d (diff) | |
download | crawl-ref-c530747fc02029b177cd1216f9145b12847b1b62.tar.gz crawl-ref-c530747fc02029b177cd1216f9145b12847b1b62.zip |
Refactor Beogh/TSO blessing code
Diffstat (limited to 'crawl-ref/source/religion.cc')
-rw-r--r-- | crawl-ref/source/religion.cc | 433 |
1 files changed, 246 insertions, 187 deletions
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 22199d51de..d2264704fc 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -1670,27 +1670,33 @@ static int _upgrade_weapon_type(int old_type, bool has_shield, bool highlevel) } } -static bool _blessing_wpn(monster* mon) -{ - // Pick a monster's weapon. - const int weapon = mon->inv[MSLOT_WEAPON]; - const int alt_weapon = mon->inv[MSLOT_ALT_WEAPON]; - if (weapon == NON_ITEM && alt_weapon == NON_ITEM - || mon->type == MONS_DANCING_WEAPON) +/** + * Attempt to bless a follower's weapon. + * + * @param[in] mon The follower whose weapon should be blessed. + * @return The type of blessing; may be empty. + */ +static string _bless_weapon(monster* mon, bool improve_type = false) +{ + if (mon->type == MONS_DANCING_WEAPON) { - return false; + dprf("Can't bless a dancing weapon's weapon!"); + return ""; } - int slot; - - do - slot = (coinflip()) ? weapon : alt_weapon; - while (slot == NON_ITEM); + item_def* wpn_ptr = mon->weapon(); + if (wpn_ptr == NULL) + { + // XXX: give an item? + dprf("Couldn't bless follower's weapon; they have none!"); + return ""; + } - item_def& wpn(mitm[slot]); + item_def& wpn = *wpn_ptr; - if (you_worship(GOD_BEOGH) + const int old_weapon_type = wpn.sub_type; + if (improve_type && !is_artefact(wpn) && x_chance_in_y(mon->hit_dice, 250) && !mon->props.exists("given beogh weapon")) @@ -1702,11 +1708,17 @@ static bool _blessing_wpn(monster* mon) } // Enchant and uncurse it. - if (!enchant_weapon(wpn, true)) - return false; + const bool enchanted = enchant_weapon(wpn, true); + + if (!enchanted && wpn.sub_type == old_weapon_type) + { + dprf("Couldn't bless follower's weapon!"); + return ""; + } + give_monster_proper_name(mon); item_set_appearance(wpn); - return true; + return "extra attack power"; } static void _upgrade_shield(item_def &sh) @@ -1729,24 +1741,31 @@ static void _upgrade_body_armour(item_def &arm) } } -static bool _blessing_AC(monster* mon) +/** + * Attempt to bless a follower's armour. + * + * @param[in] follower The follower whose armour should be blessed. + * @return The type of blessing; may be empty. + */ +static string _bless_armour(monster* mon, bool improve_type = false) { // Pick either a monster's armour or its shield. const int armour = mon->inv[MSLOT_ARMOUR]; const int shield = mon->inv[MSLOT_SHIELD]; if (armour == NON_ITEM && shield == NON_ITEM) - return false; - - int slot; - - do - slot = (coinflip()) ? armour : shield; - while (slot == NON_ITEM); + { + // XXX: give an item? + dprf("Can't improve the armour of a naked character!"); + return ""; + } + const int slot = shield == NON_ITEM || (coinflip() && armour != NON_ITEM) ? + armour : shield; item_def& arm(mitm[slot]); - if (you_worship(GOD_BEOGH) && !is_artefact(arm) + const int old_subtype = arm.sub_type; + if (improve_type && !is_artefact(arm) && x_chance_in_y(mon->hit_dice, 250)) { if (slot == shield && !mon->props.exists("given beogh shield")) @@ -1755,14 +1774,19 @@ static bool _blessing_AC(monster* mon) _upgrade_body_armour(arm); } + // And enchant or uncurse it. int ac_change; + const bool enchanted = enchant_armour(ac_change, true, arm); - // And enchant or uncurse it. - if (!enchant_armour(ac_change, true, arm)) - return false; + if (!enchanted && old_subtype == arm.sub_type) + { + dprf("Couldn't enchant follower's armour!"); + return ""; + } + give_monster_proper_name(mon); item_set_appearance(arm); - return true; + return "extra defense"; } static bool _blessing_balms(monster* mon) @@ -1932,202 +1956,237 @@ static bool _beogh_blessing_priesthood(monster* mon) return false; } -// Bless the follower indicated in follower, if any. If there isn't -// one, bless a random follower within sight of the player, if any, or, -// with decreasing chances, any follower on the level. -// Blessing can be enforced with a wizard mode command. -bool bless_follower(monster* follower, - god_type god, - bool (*suitable)(const monster* mon), - bool force) +/** + * Attempt to bless a follower with curing and/or healing. + * + * @param[in] follower The follower to heal. + * @return The type of healing that occurred; may be empty. + */ +static string _bless_with_healing(monster* follower) { - int chance = (force ? coinflip() : random2(20)); - string result; - bool blessed = false; + string blessing = ""; - // If a follower was specified, and it's suitable, pick it. - // Otherwise, pick a random follower. - if (!follower || (!force && !suitable(follower))) + // Maybe try to cure status conditions. + bool balms = false; + if (coinflip()) { - // Only Beogh blesses random followers. - if (god != GOD_BEOGH) - return false; + balms = _blessing_balms(follower); + if (balms) + blessing = "divine balms"; + else + dprf("Couldn't apply balms."); + } - if (chance > 2) - return false; + // Heal the follower. + bool healing = _blessing_healing(follower); - // Choose a random follower in LOS, preferably a named or - // priestly one (10% chance). - follower = choose_random_nearby_monster(0, suitable, true); + // Maybe heal the follower again. + if ((!healing || coinflip()) && _blessing_healing(follower)) + healing = true; - if (!follower) - { - if (coinflip()) - return false; + if (healing) + { + if (balms) + blessing += " and "; + blessing += "healing"; + } + else + dprf("Couldn't heal monster."); - // Try *again*, on the entire level (2.5% chance). - follower = choose_random_monster_on_level(0, suitable); + return blessing; +} - if (!follower) - { - // If no follower was found, attempt to send - // reinforcements. - _beogh_blessing_reinforcements(); - // Possibly send more reinforcements. - if (coinflip()) - _beogh_blessing_reinforcements(); +/** + * Print a message for a god blessing a follower. + * + * Also flash the screen, in local tiles. + * + * @param[in] follower The follower being blessed. + * @param god The god doing the blessing. + * @param message The blessing being delivered. + */ +static void _display_god_blessing(monster* follower, god_type god, + string blessing) +{ + ASSERT(follower); - _delayed_monster_done("Beogh blesses you with " - "reinforcements.", ""); + string whom = you.can_see(follower) ? follower->name(DESC_THE) + : "a follower"; - // Return true, even though the reinforcements might - // not be placed. - return true; - } - } - } - ASSERT(follower); + simple_god_message(make_stringf(" blesses %s with %s.", + whom.c_str(), blessing.c_str()).c_str(), + god); - if (chance <= 1 && god == GOD_BEOGH) // 10% chance of priesthood +#ifndef USE_TILE_LOCAL + flash_monster_colour(follower, god_colour(god), 200); +#endif +} + +/** + * Have Beogh attempt to bless the specified follower. + * + * He may choose to bless another nearby follower, if no follower is specified, + * or the follower is invalid. + * + * @param[in] follower The follower to try to bless. + * @param[in] force Whether to check follower validity. + * @return Whether a blessing occurred. + */ +static bool _beogh_bless_follower(monster* follower, bool force) +{ + // If a follower was specified, and it's suitable, pick it. + // Otherwise, pick a random follower. + // XXX: factor out into another function? + if (!follower || (!force && !is_follower(follower))) { - // Turn a monster into a priestly monster, if possible. - if (_beogh_blessing_priesthood(follower)) - { - result = "priesthood"; - blessed = true; - } - else if (force) - mpr("Couldn't promote monster to priesthood."); + if (!one_chance_in(10)) + return false; + + // Choose a random follower in LOS, preferably a named or + // priestly one. + follower = choose_random_nearby_monster(0, is_follower, true); } - // Enchant a monster's weapon or armour/shield by one point, or at - // least uncurse it, if possible (10% chance). - // This will happen if the above blessing attempts are unsuccessful. - if (chance <= 1 && !blessed) + if (!follower) { if (coinflip()) - { - if (_blessing_wpn(follower)) - { - result = "extra attack power"; - give_monster_proper_name(follower); - blessed = true; - } - else if (force) - mpr("Couldn't enchant monster's weapon."); - } - else - { - if (_blessing_AC(follower)) - { - result = "extra defence"; - give_monster_proper_name(follower); - blessed = true; - } - else if (force) - mpr("Couldn't enchant monster's armour."); - } + return false; + + // Try *again*, on the entire level (2.5% chance). + follower = choose_random_monster_on_level(0, is_follower); } - // These effects happen if no other blessing was chosen (90%), - // or if the above attempts were all unsuccessful. - if (!blessed) + if (!follower) { - switch (god) - { - case GOD_SHINING_ONE: - { - // Extend a monster's stay if it's abjurable, or extend charm - // duration. If neither is possible, deliberately fall through. - bool more_time = _tso_blessing_extend_stay(follower); - bool friendliness = false; + // If no follower was found, attempt to send + // reinforcements. + _beogh_blessing_reinforcements(); - if (!more_time || coinflip()) - friendliness = _tso_blessing_friendliness(follower); - - result = ""; - - if (friendliness) - { - result += "friendliness"; - if (more_time) - result += " and "; - } + // Possibly send more reinforcements. + if (coinflip()) + _beogh_blessing_reinforcements(); - if (more_time) - result += "more time in this world"; + _delayed_monster_done("Beogh blesses you with " + "reinforcements.", ""); - if (more_time || friendliness) - break; + // Return true, even though the reinforcements might + // not be placed. + return true; + } - if (force) - mpr("Couldn't increase monster's friendliness or time."); - } + string blessing = ""; - // Deliberate fallthrough for the healing effects. - case GOD_BEOGH: - { - // Remove harmful ailments from a monster, or heal it, if - // possible. - if (coinflip()) - { - if (_blessing_balms(follower)) - { - result = "divine balms"; - break; - } - else if (force) - mpr("Couldn't apply balms."); - } + // 10% chance of blessing to priesthood or improving equipment. + if (one_chance_in(10)) + { + if (_beogh_blessing_priesthood(follower)) + blessing = "priesthood"; + else + { + dprf("Couldn't promote monster to priesthood"); + blessing = coinflip() ? _bless_weapon(follower, true) + : _bless_armour(follower, true); + } + } - bool healing = _blessing_healing(follower); + // 90% chance of trying to heal. + if (blessing.empty()) + blessing = _bless_with_healing(follower); - if ((!healing || coinflip()) - && _blessing_healing(follower)) - { - healing = true; - } + if (blessing.empty()) + return false; - if (healing) - { - result += "healing"; - break; - } - else if (force) - mpr("Couldn't heal monster."); + _display_god_blessing(follower, GOD_BEOGH, blessing); + return true; +} - return false; - } +/** + * Attempt to increase the duration of a follower. + * + * Their summon duration, if summoned, or charm duration, if charmed. + * + * @param[in] follower The follower to bless. + * @return The type of blessing that was given; may be empty. + */ +static string _tso_bless_duration(monster* follower) +{ + // Extend a monster's stay if it's abjurable, or extend charm + // duration. If neither is possible, deliberately fall through. + const bool more_time = _tso_blessing_extend_stay(follower); + const bool friendliness = _tso_blessing_friendliness(follower); - default: - break; - } + if (!more_time && !friendliness) + { + dprf("Couldn't increase monster's friendliness or summon time."); + return ""; } - string whom = ""; - if (!follower) - whom = "you"; - else + string blessing = ""; + if (friendliness) { - if (you.can_see(follower)) - whom = follower->name(DESC_THE); - else - whom = "a follower"; + blessing += "friendliness"; + if (more_time) + blessing += " and "; } - simple_god_message( - make_stringf(" blesses %s with %s.", - whom.c_str(), result.c_str()).c_str(), - god); + if (more_time) + blessing += "more time in this world"; -#ifndef USE_TILE_LOCAL - flash_monster_colour(follower, god_colour(god), 200); -#endif + return blessing; +} + +/** + * Have The Shining One attempt to bless the specified follower. + * + * 10% chance of blessing equipment; otherwise, increase duration, or + * barring that, just heal & cure. + * + * @param[in] follower The follower to try to bless. + * @param[in] force Whether to check follower validity. + * @return Whether a blessing occurred. + */ +static bool _tso_bless_follower(monster* follower, bool force) +{ + + if (!follower || (!force && !is_follower(follower))) + return false; + + string blessing = ""; + if (one_chance_in(10)) + { + blessing = coinflip() ? _bless_weapon(follower) + : _bless_armour(follower); + } + if (blessing.empty()) + blessing = _tso_bless_duration(follower); + if (blessing.empty()) + blessing = _bless_with_healing(follower); + if (blessing.empty()) + return false; + + _display_god_blessing(follower, GOD_SHINING_ONE, blessing); return true; } +// Bless the follower indicated in follower, if any. If there isn't +// one, bless a random follower within sight of the player, if any, or, +// with decreasing chances, any follower on the level. +// Blessing can be enforced with a wizard mode command. +bool bless_follower(monster* follower, + god_type god, + bool force) +{ + switch (god) + { + case GOD_BEOGH: return _beogh_bless_follower(follower, force); + case GOD_SHINING_ONE: return _tso_bless_follower(follower, force); + default: return false; // XXX: print something here? + } +} + + static void _delayed_gift_callback(const mgen_data &mg, monster *&mon, int placed) { |