summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/godabil.cc
diff options
context:
space:
mode:
authorAdam Borowski <kilobyte@angband.pl>2009-10-22 11:05:44 +0200
committerAdam Borowski <kilobyte@angband.pl>2009-10-22 11:44:33 +0200
commitc15a9271c743a96caeb958e945d9e1a8b69c5ece (patch)
treeac440f775d2bc2b5f1505c0c55dae6ee394ec130 /crawl-ref/source/godabil.cc
parent052fcd7f52e68aeb93a15a164f02301c8e5436e1 (diff)
downloadcrawl-ref-c15a9271c743a96caeb958e945d9e1a8b69c5ece.tar.gz
crawl-ref-c15a9271c743a96caeb958e945d9e1a8b69c5ece.zip
Yank some god invocations from religion.cc into godabil.cc
Diffstat (limited to 'crawl-ref/source/godabil.cc')
-rw-r--r--crawl-ref/source/godabil.cc499
1 files changed, 499 insertions, 0 deletions
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<int>(you.your_level),
+ static_cast<int>(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));
+}