From c15a9271c743a96caeb958e945d9e1a8b69c5ece Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Thu, 22 Oct 2009 11:05:44 +0200 Subject: Yank some god invocations from religion.cc into godabil.cc --- crawl-ref/source/godabil.cc | 499 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 499 insertions(+) create mode 100644 crawl-ref/source/godabil.cc (limited to 'crawl-ref/source/godabil.cc') diff --git a/crawl-ref/source/godabil.cc b/crawl-ref/source/godabil.cc new file mode 100644 index 0000000000..6d24483f78 --- /dev/null +++ b/crawl-ref/source/godabil.cc @@ -0,0 +1,499 @@ +/* + * File: godabil.cc + * Summary: God-granted abilities. + */ + +#include "AppHdr.h" + +#include "cloud.h" +#include "database.h" +#include "files.h" +#include "godabil.h" +#include "invent.h" +#include "items.h" +#include "kills.h" +#include "message.h" +#include "mon-util.h" +#include "monstuff.h" +#include "mstuff2.h" +#include "mutation.h" +#include "religion.h" +#include "shopping.h" +#include "spells3.h" +#include "spl-book.h" +#include "spl-util.h" +#include "stuff.h" +#include "terrain.h" +#include "view.h" + +bool yred_injury_mirror(bool actual) +{ + return (you.religion == GOD_YREDELEMNUL && !player_under_penance() + && you.piety >= piety_breakpoint(1) + && (!actual || you.duration[DUR_PRAYER])); +} + +bool beogh_water_walk() +{ + return (you.religion == GOD_BEOGH && !player_under_penance() + && you.piety >= piety_breakpoint(4)); +} + +bool jiyva_grant_jelly(bool actual) +{ + return (you.religion == GOD_JIYVA && !player_under_penance() + && you.piety >= piety_breakpoint(2) + && (!actual || you.duration[DUR_PRAYER])); +} + +bool jiyva_remove_bad_mutation() +{ + if (!how_mutated()) + { + mpr("You have no bad mutations to be cured!"); + return (false); + } + + // Ensure that only bad mutations are removed. + if (!delete_mutation(RANDOM_BAD_MUTATION, true, false, true, true)) + { + canned_msg(MSG_NOTHING_HAPPENS); + return (false); + } + + mpr("You feel cleansed."); + return (true); +} + +bool vehumet_supports_spell(spell_type spell) +{ + if (spell_typematch(spell, SPTYP_CONJURATION | SPTYP_SUMMONING)) + return (true); + + if (spell == SPELL_SHATTER + || spell == SPELL_FRAGMENTATION + || spell == SPELL_SANDBLAST) + { + return (true); + } + + return (false); +} + +// Returns false if the invocation fails (no spellbooks in sight, etc.). +bool trog_burn_spellbooks() +{ + if (you.religion != GOD_TROG) + return (false); + + god_acting gdact; + + for (stack_iterator si(you.pos()); si; ++si) + { + if (si->base_type == OBJ_BOOKS + && si->sub_type != BOOK_MANUAL + && si->sub_type != BOOK_DESTRUCTION) + { + mpr("Burning your own feet might not be such a smart idea!"); + return (false); + } + } + + int totalpiety = 0; + + for (radius_iterator ri(you.pos(), LOS_RADIUS, true, true, true); ri; ++ri) + { + // If a grid is blocked, books lying there will be ignored. + // Allow bombing of monsters. + const unsigned short cloud = env.cgrid(*ri); + if (feat_is_solid(grd(*ri)) + || cloud != EMPTY_CLOUD && env.cloud[cloud].type != CLOUD_FIRE) + { + continue; + } + + int count = 0; + int rarity = 0; + for (stack_iterator si(*ri); si; ++si) + { + if (si->base_type != OBJ_BOOKS + || si->sub_type == BOOK_MANUAL + || si->sub_type == BOOK_DESTRUCTION) + { + continue; + } + + // Ignore {!D} inscribed books. + if (!check_warning_inscriptions(*si, OPER_DESTROY)) + { + mpr("Won't ignite {!D} inscribed book."); + continue; + } + + rarity += book_rarity(si->sub_type); + // Piety increases by 2 for books never cracked open, else 1. + // Conversely, rarity influences the duration of the pyre. + if (!item_type_known(*si)) + totalpiety += 2; + else + totalpiety++; + +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Burned book rarity: %d", rarity); +#endif + destroy_item(si.link()); + count++; + } + + if (count) + { + if (cloud != EMPTY_CLOUD) + { + // Reinforce the cloud. + mpr("The fire roars with new energy!"); + const int extra_dur = count + random2(rarity / 2); + env.cloud[cloud].decay += extra_dur * 5; + env.cloud[cloud].set_whose(KC_YOU); + continue; + } + + const int duration = std::min(4 + count + random2(rarity/2), 23); + place_cloud(CLOUD_FIRE, *ri, duration, KC_YOU); + + mprf(MSGCH_GOD, "The book%s burst%s into flames.", + count == 1 ? "" : "s", + count == 1 ? "s" : ""); + } + } + + if (!totalpiety) + { + mpr("You cannot see a spellbook to ignite!"); + return (false); + } + else + { + simple_god_message(" is delighted!", GOD_TROG); + gain_piety(totalpiety); + } + + return (true); +} + +static bool _is_yred_enslaved_soul(const monsters* mon) +{ + return (mon->alive() && mons_enslaved_soul(mon)); +} + +static bool _yred_enslaved_souls_on_level_disappear() +{ + bool success = false; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *monster = &menv[i]; + if (_is_yred_enslaved_soul(monster)) + { +#ifdef DEBUG_DIAGNOSTICS + mprf(MSGCH_DIAGNOSTICS, "Undead soul disappearing: %s on level %d, branch %d", + monster->name(DESC_PLAIN).c_str(), + static_cast(you.your_level), + static_cast(you.where_are_you)); +#endif + + simple_monster_message(monster, " is freed."); + + // The monster disappears. + monster_die(monster, KILL_DISMISSED, NON_MONSTER); + + success = true; + } + } + + return (success); +} + +static bool _yred_souls_disappear() +{ + return (apply_to_all_dungeons(_yred_enslaved_souls_on_level_disappear)); +} + +void yred_make_enslaved_soul(monsters *mon, bool force_hostile, + bool quiet, bool unrestricted) +{ + if (!unrestricted) + _yred_souls_disappear(); + + const int type = mon->type; + monster_type soul_type = mons_species(type); + const std::string whose = + you.can_see(mon) ? apostrophise(mon->name(DESC_CAP_THE)) + : mon->pronoun(PRONOUN_CAP_POSSESSIVE); + const bool twisted = + !unrestricted ? !x_chance_in_y(you.skills[SK_INVOCATIONS] * 20 / 9 + 20, + 100) + : false; + int corps = -1; + + // If the monster's held in a net, get it out. + mons_clear_trapping_net(mon); + + const monsters orig = *mon; + + if (twisted) + { + mon->type = mons_zombie_size(soul_type) == Z_BIG ? + MONS_ABOMINATION_LARGE : MONS_ABOMINATION_SMALL; + mon->base_monster = MONS_PROGRAM_BUG; + } + else + { + // Drop the monster's corpse, so that it can be properly + // re-equipped below. + corps = place_monster_corpse(mon, true, true); + } + + // Drop the monster's equipment. + monster_drop_ething(mon); + + // Recreate the monster as an abomination, or as itself before + // turning it into a spectral thing below. + define_monster(*mon); + + mon->colour = ETC_UNHOLY; + + mon->flags |= MF_CREATED_FRIENDLY; + mon->flags |= MF_ENSLAVED_SOUL; + + if (twisted) + // Mark abominations as undead. + mon->flags |= MF_HONORARY_UNDEAD; + else if (corps != -1) + { + // Turn the monster into a spectral thing, minus the usual + // adjustments for zombified monsters. + mon->type = MONS_SPECTRAL_THING; + mon->base_monster = soul_type; + + // Re-equip the spectral thing. + equip_undead(mon->pos(), corps, monster_index(mon), + mon->base_monster); + + // Destroy the monster's corpse, as it's no longer needed. + destroy_item(corps); + } + + name_zombie(mon, &orig); + + mons_make_god_gift(mon, GOD_YREDELEMNUL); + + mon->attitude = !force_hostile ? ATT_FRIENDLY : ATT_HOSTILE; + behaviour_event(mon, ME_ALERT, !force_hostile ? MHITNOT : MHITYOU); + + if (!quiet) + { + mprf("%s soul %s, and %s.", whose.c_str(), + twisted ? "becomes twisted" : "remains intact", + !force_hostile ? "is now yours" : "fights you"); + } +} + +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; +} + +// During prayer feawn allows worshipers to walk on top of stationary plants +// and fungi. +bool feawn_passthrough(const monsters * target) +{ + return (target && you.religion == GOD_FEAWN + && you.duration[DUR_PRAYER] + && mons_is_plant(target) + && mons_is_stationary(target)); +} + +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; + do + { + if (item_slot == -1) + { + item_slot = prompt_invent_item("Make which item ponderous?", + MT_INVLIST, OSEL_ENCH_ARM, true, true, false); + } + + if (prompt_failed(item_slot)) + return (false); + + item_def& arm(you.inv[item_slot]); + + if (!is_enchantable_armour(arm, true, true) + || get_armour_ego_type(arm) != SPARM_NORMAL) + { + mpr("Choose some type of armour to enchant, or Esc to abort."); + if (Options.auto_list) + more(); + + item_slot = -1; + mpr("You can't enchant that."); //does not appear + continue; + } + + //make item desc runed if desc was vanilla? + + set_item_ego_type(arm, OBJ_ARMOUR, SPARM_PONDEROUSNESS); + + you.redraw_armour_class = true; + you.redraw_evasion = true; + + simple_god_message(" says: Dude, use this wisely!"); + + return (true); + } + while (true); + + return true; +} + +static int _slouch_monsters(coord_def where, int pow, int, actor* agent) +{ + monsters* mon = monster_at(where); + if (mon == NULL) + return (0); + + int dmg = (mon->speed - player_movement_speed()); + dmg = (dmg > 0 ? dmg * dmg : 0); + + mon->hurt(agent, dmg, BEAM_MMISSILE, true); + return (1); +} + +int chronos_slouch(int pow) +{ + return (apply_area_visible(_slouch_monsters, pow)); +} -- cgit v1.2.3-54-g00ecf