summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-03-28 19:59:33 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2009-03-28 19:59:33 +0000
commitb51dc9e9720a5cdb08d240da53948d34bb8a6c5a (patch)
tree907ba1c3a10ce86c5a2b7b06c1a1cacc0da3657f /crawl-ref
parentf7eda5bc39c5971efb204d29b2bf155eda36ce26 (diff)
downloadcrawl-ref-b51dc9e9720a5cdb08d240da53948d34bb8a6c5a.tar.gz
crawl-ref-b51dc9e9720a5cdb08d240da53948d34bb8a6c5a.zip
Xom again:
* tweak values for tension and amusement * Xom only laughs about "funny" deaths * gift_timeout rerolling after a bad act depends on its severity * replace the blink effect with position swapping git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9561 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/beam.cc4
-rw-r--r--crawl-ref/source/decks.cc69
-rw-r--r--crawl-ref/source/delay.cc31
-rw-r--r--crawl-ref/source/delay.h11
-rw-r--r--crawl-ref/source/describe.cc18
-rw-r--r--crawl-ref/source/effects.cc5
-rw-r--r--crawl-ref/source/hiscores.cc10
-rw-r--r--crawl-ref/source/item_use.cc54
-rw-r--r--crawl-ref/source/misc.cc66
-rw-r--r--crawl-ref/source/misc.h2
-rw-r--r--crawl-ref/source/mon-util.cc2
-rw-r--r--crawl-ref/source/newgame.cc2
-rw-r--r--crawl-ref/source/ouch.cc4
-rw-r--r--crawl-ref/source/xom.cc266
-rw-r--r--crawl-ref/source/xom.h2
15 files changed, 373 insertions, 173 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 68977eecb5..605c07b749 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -4827,7 +4827,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon)
return (MON_UNAFFECTED);
case BEAM_SLOW:
- // try to remove haste, if monster is hasted
+ // Try to remove haste, if monster is hasted.
if (mon->del_ench(ENCH_HASTE, true))
{
if (simple_monster_message(mon, " is no longer moving quickly."))
@@ -4835,7 +4835,7 @@ mon_resist_type bolt::apply_enchantment_to_monster(monsters* mon)
return (MON_AFFECTED);
}
- // not hasted, slow it
+ // Not hasted, slow it.
if (!mon->has_ench(ENCH_SLOW)
&& !mons_is_stationary(mon)
&& mon->add_ench(mon_enchant(ENCH_SLOW, 0, whose_kill())))
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index 2e5364414c..659c986278 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -941,7 +941,13 @@ static void _describe_cards(std::vector<card_type> cards)
desc = "No description found.";
name = uppercase_first(name);
- data << "<w>" << name << "</w>" << EOL << desc << EOL;
+ data << "<w>" << name << "</w>\n"
+ << get_linebreak_string(desc, get_number_of_cols())
+#ifdef USE_TILE
+ // For some reason we need another linebreak here, for the tiles version.
+ << EOL
+#endif
+ << EOL;
}
formatted_string fs = formatted_string::parse_string(data.str());
clrscr();
@@ -1422,66 +1428,7 @@ static void _swap_monster_card(int power, deck_rarity_type rarity)
if (!mon_to_swap)
mpr("You spin around.");
else
- {
- monsters& mon(*mon_to_swap);
- const coord_def newpos = mon.pos();
-
- // Be nice: no swapping into uninhabitable environments.
- if (!you.is_habitable(newpos) || !mon.is_habitable(you.pos()))
- {
- mpr("You spin around.");
- return;
- }
-
- const bool mon_caught = mons_is_caught(&mon);
- const bool you_caught = you.attribute[ATTR_HELD];
-
- // If it was submerged, it surfaces first.
- mon.del_ench(ENCH_SUBMERGED);
-
- // Pick the monster up.
- mgrd(newpos) = NON_MONSTER;
- mon.moveto(you.pos());
-
- // Plunk it down.
- mgrd(mon.pos()) = mon_to_swap->mindex();
-
- if (you_caught)
- {
- check_net_will_hold_monster(&mon);
- if (!mon_caught)
- you.attribute[ATTR_HELD] = 0;
- }
-
- // Move you to its previous location.
- move_player_to_grid(newpos, false, true, true, false);
-
- if (mon_caught)
- {
- if (you.body_size(PSIZE_BODY) >= SIZE_GIANT)
- {
- mpr("The net rips apart!");
- you.attribute[ATTR_HELD] = 0;
- int net = get_trapping_net(you.pos());
- if (net != NON_ITEM)
- destroy_item(net);
- }
- else
- {
- you.attribute[ATTR_HELD] = 10;
- mpr("You become entangled in the net!");
-
- // Xom thinks this is hilarious if you trap yourself this way.
- if (you_caught)
- xom_is_stimulated(16);
- else
- xom_is_stimulated(255);
- }
-
- if (!you_caught)
- mon.del_ench(ENCH_HELD, true);
- }
- }
+ swap_with_monster(mon_to_swap);
}
static void _velocity_card(int power, deck_rarity_type rarity)
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index d1f9f04bc1..7b1f8f0e85 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -676,6 +676,16 @@ bool is_vampire_feeding()
return (delay.type == DELAY_FEED_VAMPIRE);
}
+bool player_stair_delay()
+{
+ if (!you_are_delayed())
+ return (false);
+
+ const delay_queue_item &delay = you.delay_queue.front();
+ return (delay.type == DELAY_ASCENDING_STAIRS
+ || delay.type == DELAY_DESCENDING_STAIRS);
+}
+
// Check whether there are monsters who might be influenced by Recite.
// Returns 0, if no monsters found
// Returns 1, if eligible audience found
@@ -1539,10 +1549,22 @@ void armour_wear_effects(const int item_slot)
mpr("Oops, that feels deathly cold.");
learned_something_new(TUT_YOU_CURSED);
+ int amusement = 32;
+
// Cursed cloaks prevent you from removing body armour.
- const int cloak_mult = (get_armour_slot(arm) == EQ_CLOAK) ? 2 : 1;
+ if (get_armour_slot(arm) == EQ_CLOAK)
+ amusement *= 2;
+
+ if (!known_cursed)
+ {
+ amusement *= 2;
- xom_is_stimulated(32 * cloak_mult * (!known_cursed ? 2 : 1));
+ god_type god;
+ if (origin_is_god_gift(arm, &god) && god == GOD_XOM)
+ amusement *= 2;
+ }
+
+ xom_is_stimulated(amusement);
}
if (eq_slot == EQ_SHIELD)
@@ -1757,11 +1779,8 @@ static bool _should_stop_activity(const delay_queue_item &item,
delay_type curr = current_delay_action();
- if (ai == AI_SEE_MONSTER && (curr == DELAY_ASCENDING_STAIRS
- || curr == DELAY_DESCENDING_STAIRS))
- {
+ if (ai == AI_SEE_MONSTER && player_stair_delay())
return (false);
- }
if (ai == AI_FULL_HP || ai == AI_FULL_MP)
{
diff --git a/crawl-ref/source/delay.h b/crawl-ref/source/delay.h
index 81a81b1f26..d5b9363679 100644
--- a/crawl-ref/source/delay.h
+++ b/crawl-ref/source/delay.h
@@ -68,14 +68,15 @@ struct ait_hp_loss
void start_delay( delay_type type, int turns, int parm1 = 0, int parm2 = 0 );
void stop_delay( bool stop_stair_travel = false );
-bool you_are_delayed( void );
-delay_type current_delay_action( void );
-int check_recital_audience( void );
-void handle_delay( void );
+bool you_are_delayed();
+delay_type current_delay_action();
+int check_recital_audience();
+void handle_delay();
bool is_run_delay(int delay);
bool is_being_butchered(const item_def &item, bool just_first = true);
-bool is_vampire_feeding( void );
+bool is_vampire_feeding();
+bool player_stair_delay();
void stop_butcher_delay();
void handle_interrupted_swap(bool swap_if_safe = false,
bool force_unsafe = false,
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index dfb4517cf3..80d45c124e 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -81,18 +81,18 @@ static void _append_value( std::string & description, int valu, bool plussed )
int count_desc_lines(const std::string _desc, const int width)
{
- std::string desc = get_linebreak_string(_desc, width);
+ std::string desc = get_linebreak_string(_desc, width);
- int count = 0;
- for (int i = 0, size = desc.size(); i < size; i++)
- {
- const char ch = desc[i];
+ int count = 0;
+ for (int i = 0, size = desc.size(); i < size; i++)
+ {
+ const char ch = desc[i];
- if (ch == '\n' || ch == '$')
- count++;
- }
+ if (ch == '\n' || ch == '$')
+ count++;
+ }
- return count;
+ return count;
}
//---------------------------------------------------------------
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index ed5b3e8341..76477d6331 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -2270,7 +2270,7 @@ bool vitrify_area(int radius)
// This hinges on clear wall types having the same order as non-clear ones!
const int clear_plus = DNGN_CLEAR_ROCK_WALL - DNGN_ROCK_WALL;
bool something_happened = false;
- for ( radius_iterator ri(you.pos(), radius, false, false); ri; ++ri )
+ for (radius_iterator ri(you.pos(), radius, false, false); ri; ++ri)
{
const dungeon_feature_type grid = grd(*ri);
@@ -2278,8 +2278,7 @@ bool vitrify_area(int radius)
|| grid == DNGN_STONE_WALL
|| grid == DNGN_PERMAROCK_WALL )
{
- grd(*ri)
- = static_cast<dungeon_feature_type>(grid + clear_plus);
+ grd(*ri) = static_cast<dungeon_feature_type>(grid + clear_plus);
set_terrain_changed(ri->x, ri->y);
something_happened = true;
}
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index 1b5eb95249..5132af79e5 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -761,9 +761,9 @@ void scorefile_entry::init_death_cause(int dam, int dsrc,
// for death by monster
if ((death_type == KILLED_BY_MONSTER
- || death_type == KILLED_BY_BEAM
- || death_type == KILLED_BY_SPORE
- || death_type == KILLED_BY_REFLECTION)
+ || death_type == KILLED_BY_BEAM
+ || death_type == KILLED_BY_SPORE
+ || death_type == KILLED_BY_REFLECTION)
&& !invalid_monster_index(death_source)
&& menv[death_source].type != -1)
{
@@ -1110,8 +1110,8 @@ const char *scorefile_entry::damage_verb() const
// bwr: changed "blasted" since this is for melee
return (final_hp > -6) ? "Slain" :
(final_hp > -14) ? "Mangled" :
- (final_hp > -22) ? "Demolished" :
- "Annihilated";
+ (final_hp > -22) ? "Demolished"
+ : "Annihilated";
}
std::string scorefile_entry::death_source_desc() const
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 1ef169b56b..97c0a958a0 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -725,7 +725,15 @@ void wield_effects(int item_wield_2, bool showMsgs)
mpr("Space warps around you for a moment!");
if (!was_known)
- xom_is_stimulated(32);
+ {
+ // Xom loves when you ID a distortion weapon this way,
+ // and even more so if he gifted the weapon himself.
+ god_type god;
+ if (origin_is_god_gift(item, &god) && god == GOD_XOM)
+ xom_is_stimulated(255);
+ else
+ xom_is_stimulated(128);
+ }
break;
case SPWPN_SCYTHE_OF_CURSES:
@@ -748,10 +756,20 @@ void wield_effects(int item_wield_2, bool showMsgs)
if (item_cursed(item))
{
mpr("It sticks to your hand!");
- if (known_cursed || was_known && special == SPWPN_SCYTHE_OF_CURSES)
- xom_is_stimulated(32);
- else
- xom_is_stimulated(64);
+ int amusement = 16;
+ if (!known_cursed
+ && !(was_known && special == SPWPN_SCYTHE_OF_CURSES))
+ {
+ amusement *= 2;
+ god_type god;
+ if (origin_is_god_gift(item, &god) && god == GOD_XOM)
+ amusement *= 2;
+ }
+ const int wpn_skill = weapon_skill(item.base_type, item.sub_type);
+ if (wpn_skill != SK_FIGHTING && you.skills[wpn_skill] == 0)
+ amusement *= 2;
+
+ xom_is_stimulated(amusement);
}
break;
@@ -3300,10 +3318,16 @@ void jewellery_wear_effects(item_def &item)
jewellery_is_amulet(item)? "amulet" : "ring");
learned_something_new(TUT_YOU_CURSED);
- if (known_cursed || known_bad)
- xom_is_stimulated(64);
- else
- xom_is_stimulated(128);
+ int amusement = 32;
+ if (!known_cursed && !known_bad)
+ {
+ amusement *= 2;
+
+ god_type god;
+ if (origin_is_god_gift(item, &god) && god == GOD_XOM)
+ amusement *= 2;
+ }
+ xom_is_stimulated(amusement);
}
// Cursed or not, we know that since we've put the ring on.
@@ -4825,6 +4849,7 @@ void read_scroll(int slot)
bool id_the_scroll = true; // to prevent unnecessary repetition
bool tried_on_item = false; // used to modify item (?EA, ?RC, ?ID)
+ bool bad_effect = false; // for Xom: result is bad (or at least dangerous)
switch (which_scroll)
{
case SCR_PAPER:
@@ -4918,6 +4943,7 @@ void read_scroll(int slot)
// This is only naughty if you know you're doing it.
did_god_conduct(DID_UNHOLY, 10, item_type_known(scroll));
+ bad_effect = true;
break;
case SCR_IMMOLATION:
@@ -4928,6 +4954,7 @@ void read_scroll(int slot)
dec_inv_item_quantity(item_slot, 1);
immolation(10, IMMOLATION_SCROLL, you.pos(), alreadyknown, &you);
+ bad_effect = true;
break;
}
@@ -4944,6 +4971,7 @@ void read_scroll(int slot)
// Also sets wield_change.
do_curse_item( *you.weapon(), false );
learned_something_new(TUT_YOU_CURSED);
+ bad_effect = true;
}
break;
@@ -5068,6 +5096,7 @@ void read_scroll(int slot)
// Make the name before we curse it.
do_curse_item( you.inv[you.equip[affected]], false );
learned_something_new(TUT_YOU_CURSED);
+ bad_effect = true;
break;
}
@@ -5123,8 +5152,9 @@ void read_scroll(int slot)
if (!alreadyknown && dangerous)
{
// Xom loves it when you read an unknown scroll and there is a
- // dangerous monster nearby...
- xom_is_stimulated(255);
+ // dangerous monster nearby... (though not as much as potions
+ // since there are no *really* bad scrolls, merely useless ones).
+ xom_is_stimulated(bad_effect ? 128 : 64);
}
}
@@ -5257,7 +5287,7 @@ void use_randart(item_def &item, bool unmeld)
{
// Xom loves it when you use an unknown random artefact and
// there is a dangerous monster nearby...
- xom_is_stimulated(255);
+ xom_is_stimulated(128);
}
#undef unknown_proprt
}
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 36d1bd7b08..7713fd7ca3 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -3110,3 +3110,69 @@ bool is_dragonkind(const actor *act)
return (false);
}
+
+// Make the player swap positions with a given monster.
+void swap_with_monster(monsters *mon_to_swap)
+{
+ monsters& mon(*mon_to_swap);
+ ASSERT(mon.alive());
+ const coord_def newpos = mon.pos();
+
+ // Be nice: no swapping into uninhabitable environments.
+ if (!you.is_habitable(newpos) || !mon.is_habitable(you.pos()))
+ {
+ mpr("You spin around.");
+ return;
+ }
+
+ const bool mon_caught = mons_is_caught(&mon);
+ const bool you_caught = you.attribute[ATTR_HELD];
+
+ // If it was submerged, it surfaces first.
+ mon.del_ench(ENCH_SUBMERGED);
+
+ mprf("You swap places with %s.", mon.name(DESC_NOCAP_THE).c_str());
+
+ // Pick the monster up.
+ mgrd(newpos) = NON_MONSTER;
+ mon.moveto(you.pos());
+
+ // Plunk it down.
+ mgrd(mon.pos()) = mon_to_swap->mindex();
+
+ if (you_caught)
+ {
+ check_net_will_hold_monster(&mon);
+ if (!mon_caught)
+ you.attribute[ATTR_HELD] = 0;
+ }
+
+ // Move you to its previous location.
+ move_player_to_grid(newpos, false, true, true, false);
+
+ if (mon_caught)
+ {
+ if (you.body_size(PSIZE_BODY) >= SIZE_GIANT)
+ {
+ mpr("The net rips apart!");
+ you.attribute[ATTR_HELD] = 0;
+ int net = get_trapping_net(you.pos());
+ if (net != NON_ITEM)
+ destroy_item(net);
+ }
+ else
+ {
+ you.attribute[ATTR_HELD] = 10;
+ mpr("You become entangled in the net!");
+
+ // Xom thinks this is hilarious if you trap yourself this way.
+ if (you_caught)
+ xom_is_stimulated(16);
+ else
+ xom_is_stimulated(255);
+ }
+
+ if (!you_caught)
+ mon.del_ench(ENCH_HELD, true);
+ }
+}
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index ec3804ea30..400007aad5 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -116,5 +116,5 @@ bool stop_attack_prompt(const monsters *mon, bool beam_attack,
bool is_orckind(const actor *act);
bool is_dragonkind(const actor *act);
-
+void swap_with_monster(monsters *mon_to_swap);
#endif
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 3738e09ac0..1bd90804d2 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -5718,7 +5718,7 @@ void monsters::expose_to_element(beam_type flavour, int strength)
{
case BEAM_COLD:
if (mons_class_flag(this->type, M_COLD_BLOOD) && coinflip())
- add_ench(ENCH_SLOW);
+ slow_down(this, strength);
break;
default:
break;
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index 826fceb758..4f02c1060a 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -5020,7 +5020,7 @@ bool _give_items_skills()
// The new Xom also uses gift_timeout in his own special way...
// (Namely, a countdown to becoming bored.)
- you.gift_timeout = random2(40) + random2(40);
+ you.gift_timeout = std::max(5, random2(40) + random2(40));
}
else // Makhleb or Lugonu
{
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index 718f0c7a7a..d955dfdfdd 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -1079,9 +1079,7 @@ void end_game( scorefile_entry &se )
for (int i = 0; i < ENDOFPACK; i++)
{
if (you.inv[i].base_type != 0)
- {
set_ident_type( you.inv[i], ID_KNOWN_TYPE );
- }
}
if (!dump_char( morgue_name(se.death_time), !dead, true, &se ))
@@ -1147,7 +1145,7 @@ void end_game( scorefile_entry &se )
if (dead)
{
mpr("You die..."); // insert player name here? {dlb}
- xom_death_message();
+ xom_death_message((kill_method_type) se.death_type);
flush_prev_message();
viewwindow(true, false); // don't do for leaving/winning characters
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index 20da3b29b1..a080df0d70 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -14,6 +14,7 @@ REVISION("$Rev$");
#include "beam.h"
#include "branch.h"
#include "database.h"
+#include "delay.h"
#include "effects.h"
#include "it_use2.h"
#include "items.h"
@@ -38,6 +39,7 @@ REVISION("$Rev$");
#include "state.h"
#include "stuff.h"
#include "transfor.h"
+#include "traps.h"
#include "view.h"
#include "xom.h"
@@ -175,7 +177,7 @@ static void _xom_is_stimulated(int maxinterestingness,
interestingness = std::min(255, interestingness);
-#if DEBUG_RELIGION || DEBUG_GIFTS || DEBUG_XOM
+#if defined(DEBUG_RELIGION) || defined(DEBUG_GIFTS) || defined(DEBUG_XOM)
mprf(MSGCH_DIAGNOSTICS,
"Xom: gift_timeout: %d, maxinterestingness = %d, interestingness = %d",
you.gift_timeout, maxinterestingness, interestingness);
@@ -240,20 +242,26 @@ void xom_tick()
if (one_chance_in(3))
{
- if (_xom_is_bored())
- xom_acts(abs(you.piety - MAX_PIETY/2));
- else
+ const int tension = get_tension(GOD_XOM);
+ const int chance = (tension == 0 ? 1 :
+ tension <= 5 ? 2 :
+ tension <= 10 ? 3 :
+ tension <= 20 ? 4
+ : 5);
+
+ // During tension, Xom may briefly forget about being bored.
+ if (_xom_is_bored() && x_chance_in_y(chance-1, 4))
{
- const int tension = get_tension(GOD_XOM);
- const int chance = (tension == 0 ? 1 :
- tension <= 5 ? 2 :
- tension <= 10 ? 3 :
- tension <= 20 ? 4
- : 5);
-
- if (x_chance_in_y(chance, 5))
- xom_acts(abs(you.piety - MAX_PIETY/2), tension);
+ you.gift_timeout += random2(chance*20);
+#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM)
+ mprf(MSGCH_DIAGNOSTICS,
+ "tension %d (chance: %d) -> increase interest to %d",
+ tension, chance, you.gift_timeout);
+#endif
}
+
+ if (x_chance_in_y(chance, 5))
+ xom_acts(abs(you.piety - MAX_PIETY/2), tension);
}
}
@@ -293,7 +301,7 @@ static void _xom_makes_you_cast_random_spell(int sever, int tension)
god_speaks(GOD_XOM, _get_xom_speech("spell effect").c_str());
-#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
+#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_RELIGION) || defined(DEBUG_XOM)
mprf(MSGCH_DIAGNOSTICS,
"_xom_makes_you_cast_random_spell(); spell: %d, spellenum: %d",
spell, spellenum);
@@ -999,50 +1007,125 @@ static bool _xom_polymorph_nearby_monster(bool helpful)
return (rc);
}
-// Blink every monster on this level and the player.
-static bool _xom_rearrange_pieces(int sever)
+static void _confuse_monster(monsters mons, int sever)
{
- bool rc = false;
+// monsters& mons(*mon);
- // Every now and then, Xom also confuses them all.
- const bool confusem = one_chance_in(10);
+ if (!mons_class_is_confusable(mons.type))
+ return;
- // Not just every monster in sight - oh no. Every monster on this
- // level!
+ const bool was_confused = mons.confused();
+ if (mons.add_ench(mon_enchant(ENCH_CONFUSION, 0, KC_FRIENDLY,
+ random2(sever))))
+ {
+ if (was_confused)
+ simple_monster_message(&mons, " looks rather more confused.");
+ else
+ simple_monster_message(&mons, " looks rather confused.");
+ }
+}
+
+static bool _swap_monsters(monsters *m1, monsters *m2)
+{
+ monsters& mon1(*m1);
+ monsters& mon2(*m2);
+
+ const bool mon1_caught = mons_is_caught(&mon1);
+ const bool mon2_caught = mons_is_caught(&mon2);
+
+ const coord_def mon1_pos = mon1.pos();
+ const coord_def mon2_pos = mon2.pos();
+
+ if (!mon2.is_habitable(mon1_pos) || !mon1.is_habitable(mon2_pos))
+ return (false);
+
+ // Make submerged monsters unsubmerge.
+ mon1.del_ench(ENCH_SUBMERGED);
+ mon2.del_ench(ENCH_SUBMERGED);
+
+ mgrd(mon1_pos) = mon2.mindex();
+ mon1.moveto(mon2_pos);
+ mgrd(mon2_pos) = mon1.mindex();
+ mon2.moveto(mon1_pos);
+
+ if (mon1_caught && !mon2_caught)
+ {
+ check_net_will_hold_monster(&mon2);
+ mon1.del_ench(ENCH_HELD, true);
+
+ }
+ else if (mon2_caught && !mon1_caught)
+ {
+ check_net_will_hold_monster(&mon1);
+ mon2.del_ench(ENCH_HELD, true);
+ }
+
+ return (true);
+}
+
+// Swap places with a random monster and, depending on severity, also
+// between monsters. This can be pretty bad if there are a lot of hostile
+// monsters around.
+static bool _xom_rearrange_pieces(int sever)
+{
+ if (player_stair_delay())
+ return (false);
+
+ std::vector<monsters *> mons;
for (unsigned i = 0; i < MAX_MONSTERS; ++i)
{
- monsters* monster = &menv[i];
+ monsters* m = &menv[i];
- if (!monster->alive())
+ if (!m->alive())
continue;
- if (monster_blink(monster))
+ if (!see_grid(m->pos()))
+ continue;
+
+ mons.push_back(m);
+ }
+ if (mons.empty())
+ return (false);
+
+ god_speaks(GOD_XOM, _get_xom_speech("rearrange the pieces").c_str());
+
+ const int num_mons = mons.size();
+
+ // Swap places with a random monster.
+ monsters *mon = mons[random2(num_mons)];
+ swap_with_monster(mon);
+
+ // Occasionally confuse said monster.
+ if (one_chance_in(5))
+ _confuse_monster(*mon, sever);
+
+ if (num_mons > 1 && x_chance_in_y(sever,70))
+ {
+ bool did_message = false;
+ const int max_repeats = std::min(num_mons/2, 8);
+ const int repeats = std::min(random2(sever/10)+1, max_repeats);
+ for (int i = 0; i < repeats; ++i)
{
- // Only give a message once.
- if (!rc)
- god_speaks(GOD_XOM,
- _get_xom_speech("rearrange the pieces").c_str());
+ const int mon1 = random2(num_mons);
+ int mon2 = mon1;
+ while (mon1 == mon2)
+ mon2 = random2(num_mons);
- if (confusem)
+ if (_swap_monsters(mons[mon1], mons[mon2]))
{
- if (mons_class_is_confusable(monster->type)
- && monster->add_ench(mon_enchant(ENCH_CONFUSION, 0,
- KC_FRIENDLY,
- random2(sever))))
+ if (!did_message)
{
- simple_monster_message(monster, " looks rather confused.");
+ mpr("Some monsters swap places.");
+ did_message = true;
}
+ if (one_chance_in(5))
+ _confuse_monster(*mons[mon1], sever);
+ if (one_chance_in(5))
+ _confuse_monster(*mons[mon2], sever);
}
- rc = true;
}
}
-
- // If Xom blinked at least one monster, blink the player, too, and
- // then consider this act done.
- if (rc)
- random_blink(false);
-
- return (rc);
+ return (true);
}
static bool _xom_give_mutations(bool good)
@@ -1077,6 +1160,7 @@ static bool _xom_give_mutations(bool good)
return (rc);
}
+// Summons a permanent ally.
static bool _xom_send_major_ally(int sever)
{
bool rc = false;
@@ -1176,6 +1260,8 @@ static bool _xom_is_good(int sever, int tension)
done = _xom_do_potion();
else if (x_chance_in_y(3, sever))
{
+ // There are a lot less non-tension spells than tension ones,
+ // so use them more rarely.
if (tension > 0 || one_chance_in(3))
{
_xom_makes_you_cast_random_spell(sever, tension);
@@ -1197,13 +1283,13 @@ static bool _xom_is_good(int sever, int tension)
done = _xom_send_allies(sever);
else if (x_chance_in_y(8, sever))
done = _xom_polymorph_nearby_monster(true);
- else if (random2(tension) < 15 && x_chance_in_y(9, sever))
+ else if (tension > 0 && x_chance_in_y(9, sever))
+ done = _xom_rearrange_pieces(sever);
+ else if (random2(tension) < 15 && x_chance_in_y(10, sever))
{
_xom_give_item(sever);
done = true;
}
- else if (x_chance_in_y(10, sever) && (you.level_type != LEVEL_ABYSS))
- done = _xom_rearrange_pieces(sever);
else if (x_chance_in_y(11, sever) && (you.level_type != LEVEL_ABYSS))
{
// The Xom teleportation train takes you on instant teleportation
@@ -1223,7 +1309,7 @@ static bool _xom_is_good(int sever, int tension)
else if (random2(tension) < 5 && x_chance_in_y(12, sever))
{
// This can fail with radius 1, or in open areas.
- if (vitrify_area(random2avg(sever / 2, 3) + 1))
+ if (vitrify_area(random2avg(sever/4,2) + 1))
{
god_speaks(GOD_XOM, _get_xom_speech("vitrification").c_str());
done = true;
@@ -1305,8 +1391,10 @@ static void _xom_zero_miscast()
}
if (in_view[DNGN_DEEP_WATER])
+ {
messages.push_back("From the corner of your eye you spot something "
"lurking in the deep water.");
+ }
if (in_view[DNGN_ORCISH_IDOL])
{
@@ -1846,6 +1934,9 @@ static bool _xom_is_bad(int sever, int tension)
god_acting gdact(GOD_XOM);
+ // Rough estimate of how bad a Xom effect hits the player,
+ // scaled between 1 (harmless) and 5 (disastrous).
+ int badness = 1;
while (!done)
{
// Did Xom kill the player?
@@ -1863,10 +1954,14 @@ static bool _xom_is_bad(int sever, int tension)
done = true;
}
else if (x_chance_in_y(5, sever))
+ {
done = _xom_lose_stats();
+ badness = 2;
+ }
else if (x_chance_in_y(6, sever))
{
_xom_miscast(2, nasty);
+ badness = 2;
done = true;
}
else if ((!nasty || coinflip())
@@ -1883,37 +1978,66 @@ static bool _xom_is_bad(int sever, int tension)
more();
}
while (x_chance_in_y(3, 4) && !player_in_a_dangerous_place());
+ badness = player_in_a_dangerous_place() ? 3 : 1;
done = true;
}
else if (x_chance_in_y(8, sever))
+ {
done = _xom_chaos_upgrade_nearby_monster();
+ badness = 2 + coinflip();
+ }
else if (random2(tension) < 10 && x_chance_in_y(9, sever))
+ {
done = _xom_give_mutations(false);
+ badness = 3;
+ }
else if (x_chance_in_y(10, sever))
+ {
done = _xom_polymorph_nearby_monster(false);
+ badness = 3;
+ }
// It's pointless to confuse player if there's no danger nearby.
else if (tension > 0 && x_chance_in_y(11, sever))
+ {
done = _xom_player_confusion_effect(sever);
+ badness = (random2(tension) > 5 ? 2 : 1);
+ }
else if (x_chance_in_y(12, sever))
+ {
done = _xom_draining_torment_effect(sever);
+ badness = (random2(tension) > 5 ? 3 : 2);
+ }
else if (x_chance_in_y(13, sever))
+ {
done = _xom_summon_hostiles(sever);
+ badness = 3 + coinflip();
+ }
else if (x_chance_in_y(14, sever))
{
_xom_miscast(3, nasty);
+ badness = 4 + coinflip();
done = true;
}
- else if (one_chance_in(sever))
+ else if (one_chance_in(sever) && you.level_type != LEVEL_ABYSS)
{
- if (you.level_type != LEVEL_ABYSS)
- {
- god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str());
- banished(DNGN_ENTER_ABYSS, "Xom");
- done = true;
- }
+ god_speaks(GOD_XOM, _get_xom_speech("banishment").c_str());
+ banished(DNGN_ENTER_ABYSS, "Xom");
+ badness = 5;
+ done = true;
}
}
+ // If we got here because Xom was bored, reset gift timeout according
+ // to the badness of the effect.
+ if (done && _xom_is_bored())
+ {
+ const int interest = random2avg(badness*60, 2);
+ you.gift_timeout = std::min(interest, 255);
+#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM)
+ mprf(MSGCH_DIAGNOSTICS, "badness: %d, new interest: %d",
+ badness, you.gift_timeout);
+#endif
+ }
return (done);
}
@@ -2046,9 +2170,9 @@ static void _handle_accidental_death(const int orig_hp,
void xom_acts(bool niceness, int sever, int tension)
{
-#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
- mprf(MSGCH_DIAGNOSTICS, "xom_acts(%u, %d); piety: %u, interest: %u\n",
- niceness, sever, you.piety, you.gift_timeout);
+#if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_RELIGION) || defined(DEBUG_XOM)
+ mprf(MSGCH_DIAGNOSTICS, "xom_acts(%u, %d, %d); piety: %u, interest: %u\n",
+ niceness, sever, tension, you.piety, you.gift_timeout);
#endif
#ifdef WIZARD
@@ -2101,7 +2225,7 @@ void xom_acts(bool niceness, int sever, int tension)
if (tension == -1)
tension = get_tension(which_god);
-#if DEBUG_RELIGION || DEBUG_XOM || DEBUG_TENSION
+#if defined(DEBUG_RELIGION) || defined(DEBUG_XOM) || defined(DEBUG_TENSION)
mprf(MSGCH_DIAGNOSTICS, "Xom tension: %d", tension);
#endif
@@ -2123,10 +2247,6 @@ void xom_acts(bool niceness, int sever, int tension)
// Bad mojo.
while (!_xom_is_bad(sever, tension))
;
-
- // If we got here because Xom was bored, reset gift timeout.
- if (_xom_is_bored())
- you.gift_timeout = random2(40) + random2(40);
}
_handle_accidental_death(orig_hp, orig_stats, orig_mutation);
@@ -2245,10 +2365,30 @@ void xom_check_destroyed_item(const item_def& item, int cause)
true);
}
-void xom_death_message()
+static bool _death_is_funny(const kill_method_type killed_by)
+{
+ switch (killed_by)
+ {
+ // The less original deaths are boring.
+ case KILLED_BY_MONSTER:
+ case KILLED_BY_BEAM:
+ case KILLED_BY_CLOUD:
+ case KILLED_BY_FREEZING:
+ case KILLED_BY_BURNING:
+ case KILLED_BY_SELF_AIMED:
+ case KILLED_BY_SOMETHING:
+ return (false);
+ default:
+ // All others are fun (says Xom).
+ return (true);
+ }
+}
+
+void xom_death_message(const kill_method_type killed_by)
{
if (you.religion != GOD_XOM && (!you.worshipped[GOD_XOM] || coinflip()))
return;
- god_speaks(GOD_XOM, _get_xom_speech("laughter").c_str());
+ if (_death_is_funny(killed_by) || you.hp < -1 * random2(10))
+ god_speaks(GOD_XOM, _get_xom_speech("laughter").c_str());
}
diff --git a/crawl-ref/source/xom.h b/crawl-ref/source/xom.h
index 843a94bbbd..7b54f17ffa 100644
--- a/crawl-ref/source/xom.h
+++ b/crawl-ref/source/xom.h
@@ -35,5 +35,5 @@ inline void xom_acts(int sever, int tension = -1)
void xom_check_lost_item(const item_def& item);
void xom_check_destroyed_item(const item_def& item, int cause = -1);
-void xom_death_message();
+void xom_death_message(const kill_method_type killed_by);
#endif