summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-30 05:56:13 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-30 05:56:13 +0000
commitfc944616f69e347423c408a9d3e3efee9140a46d (patch)
tree342a77d3a517969c7ac57c6d6bc0408dc07422c3 /crawl-ref/source
parentcc20c6d673722c6dd4ca32290d9cc66e55597f3c (diff)
downloadcrawl-ref-fc944616f69e347423c408a9d3e3efee9140a46d.tar.gz
crawl-ref-fc944616f69e347423c408a9d3e3efee9140a46d.zip
This commit breaks save file compatability.
Lots of new things that amuse/stimulate Xom, and a few things which don't amuse him as much anymore. Among the new things is a corpse turning into a skeleton while butchering it; if this is too harsh to do just for Xom's amusement (previously turning into a skeleton while butchering was an ignored case and still produced chunks of flesh) it can be changed back. Also, if a Xom worshiper draws the Blank card, Xom makes it act like a Xom card, since a plain old Blank card is boring. Keep track of which branch the Orb is in, if the player isn't carrying it. Keep track of how/why the player ended up in a particular level type (Abyss, Pan, etc). Changed most "a distortion effect" cause strings for distortion caused tranlsocation miscast effects to something more specific. Added new wizard commands 'C' to curse or uncruse an item, and 'Ctrl-A' to re-generate the Abyss. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2256 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/abl-show.cc2
-rw-r--r--crawl-ref/source/abyss.cc146
-rw-r--r--crawl-ref/source/acr.cc31
-rw-r--r--crawl-ref/source/beam.cc118
-rw-r--r--crawl-ref/source/beam.h4
-rw-r--r--crawl-ref/source/branch.cc2
-rw-r--r--crawl-ref/source/branch.h3
-rw-r--r--crawl-ref/source/command.cc6
-rw-r--r--crawl-ref/source/debug.cc9
-rw-r--r--crawl-ref/source/decks.cc84
-rw-r--r--crawl-ref/source/delay.cc77
-rw-r--r--crawl-ref/source/describe.cc2
-rw-r--r--crawl-ref/source/effects.cc38
-rw-r--r--crawl-ref/source/enum.h15
-rw-r--r--crawl-ref/source/externs.h3
-rw-r--r--crawl-ref/source/fight.cc19
-rw-r--r--crawl-ref/source/files.cc29
-rw-r--r--crawl-ref/source/food.cc1
-rw-r--r--crawl-ref/source/it_use2.cc3
-rw-r--r--crawl-ref/source/it_use3.cc1
-rw-r--r--crawl-ref/source/item_use.cc30
-rw-r--r--crawl-ref/source/itemprop.cc21
-rw-r--r--crawl-ref/source/items.cc47
-rw-r--r--crawl-ref/source/items.h3
-rw-r--r--crawl-ref/source/misc.cc141
-rw-r--r--crawl-ref/source/misc.h8
-rw-r--r--crawl-ref/source/monstuff.cc5
-rw-r--r--crawl-ref/source/mutation.cc1
-rw-r--r--crawl-ref/source/ouch.cc26
-rw-r--r--crawl-ref/source/player.cc5
-rw-r--r--crawl-ref/source/religion.cc1
-rw-r--r--crawl-ref/source/religion.h11
-rw-r--r--crawl-ref/source/skills2.cc1
-rw-r--r--crawl-ref/source/spells2.cc10
-rw-r--r--crawl-ref/source/spells3.cc13
-rw-r--r--crawl-ref/source/spells4.cc5
-rw-r--r--crawl-ref/source/spl-cast.cc1
-rw-r--r--crawl-ref/source/state.cc2
-rw-r--r--crawl-ref/source/tags.cc4
-rw-r--r--crawl-ref/source/view.cc21
-rw-r--r--crawl-ref/source/xom.cc162
-rw-r--r--crawl-ref/source/xom.h41
42 files changed, 1053 insertions, 99 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 343e2ce842..50843db6d5 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -1230,7 +1230,7 @@ static bool do_ability(const ability_def& abil)
return (false);
}
- banished(DNGN_ENTER_PANDEMONIUM);
+ banished(DNGN_ENTER_PANDEMONIUM, "self");
break;
case ABIL_CHANNELING:
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 3a6a951205..f059eb2435 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -33,6 +33,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
// public for abyss generation
void generate_abyss(void)
@@ -40,6 +41,10 @@ void generate_abyss(void)
int i, j; // loop variables
int temp_rand; // probability determination {dlb}
+#if DEBUG_ABYSS
+ mpr("generate_abyss().", MSGCH_DIAGNOSTICS);
+#endif
+
for (i = 5; i < (GXM - 5); i++)
{
for (j = 5; j < (GYM - 5); j++)
@@ -62,6 +67,10 @@ void generate_abyss(void)
static void generate_area(int gx1, int gy1, int gx2, int gy2)
{
+#if DEBUG_ABYSS
+ mpr("generate_area().", MSGCH_DIAGNOSTICS);
+#endif
+
int items_placed = 0;
const int thickness = random2(70) + 30;
int thing_created;
@@ -127,6 +136,9 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
{
thing_created = items(1, OBJ_MISCELLANY,
MISC_RUNE_OF_ZOT, true, 51, 51);
+#if DEBUG_ABYSS
+ mpr("Placing an Abyssal rune.", MSGCH_DIAGNOSTICS);
+#endif
}
else
{
@@ -143,6 +155,9 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
}
}
+ int exits_wanted = 0;
+ int altars_wanted = 0;
+
for (int i = gx1; i <= gx2; i++)
{
for (int j = gy1; j <= gy2; j++)
@@ -151,9 +166,23 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
grd[i][j] = replaced[random2(5)];
if (one_chance_in(7500)) // place an exit
+ exits_wanted++;
+
+ // Don't place exit under items
+ if (exits_wanted > 0 && igrd[i][j] == NON_ITEM)
+ {
grd[i][j] = DNGN_EXIT_ABYSS;
+ exits_wanted--;
+#if DEBUG_ABYSS
+ mpr("Placing Abyss exit.", MSGCH_DIAGNOSTICS);
+#endif
+ }
if (one_chance_in(10000)) // place an altar
+ altars_wanted++;
+
+ // Don't place altars under items.
+ if (altars_wanted > 0 && igrd[i][j] == NON_ITEM)
{
do
{
@@ -168,8 +197,103 @@ static void generate_area(int gx1, int gy1, int gx2, int gy2)
// Lugonu has a flat 50% chance of corrupting the altar
if ( coinflip() )
grd[i][j] = DNGN_ALTAR_LUGONU;
+
+ altars_wanted--;
+#if DEBUG_ABYSS
+ mpr("Placing altar.", MSGCH_DIAGNOSTICS);
+#endif
+ }
+ }
+ }
+}
+
+static int abyss_exit_nearness()
+{
+ int nearness = INFINITE_DISTANCE;
+
+ for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
+ for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
+ {
+ if (!in_bounds(x, y))
+ continue;
+
+ // HACK: Why doesn't is_terrain_known() work here?
+ if (grd[x][y] == DNGN_EXIT_ABYSS
+ && get_screen_glyph(x, y) != '\0')
+ {
+ nearness = MIN(nearness,
+ grid_distance(you.x_pos, you.y_pos,
+ x, y));
+ }
+ }
+
+ return (nearness);
+}
+
+static int abyss_rune_nearness()
+{
+ int nearness = INFINITE_DISTANCE;
+
+ for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
+ for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
+ {
+ if (!in_bounds(x, y))
+ continue;
+
+ // HACK: Why doesn't is_terrain_known() work here?
+ if (get_screen_glyph(x, y) != '\0')
+ {
+ int i = igrd[x][y];
+
+ while (i != NON_ITEM)
+ {
+ item_def& item(mitm[i]);
+ if (is_rune(item) && item.plus == RUNE_ABYSSAL)
+ nearness = MIN(nearness,
+ grid_distance(you.x_pos, you.y_pos,
+ x, y));
+ i = item.link;
+ }
}
}
+
+ return (nearness);
+}
+
+static int exit_was_near;
+static int rune_was_near;
+
+static void xom_check_nearness_setup()
+{
+ exit_was_near = abyss_exit_nearness();
+ rune_was_near = abyss_rune_nearness();
+}
+
+// If the player was almost to the exit when it disppeared, Xom is
+// exteremely amused. He's also extremely amused if the player winds
+// up right next to an exit when there wasn't one there before. The
+// same applies to Abyssal runes.
+static void xom_check_nearness()
+{
+ // Update known terrain
+ viewwindow(true, false);
+
+ int exit_is_near = abyss_exit_nearness();
+ if ((exit_was_near < INFINITE_DISTANCE &&
+ exit_is_near == INFINITE_DISTANCE)
+ || (exit_was_near == INFINITE_DISTANCE &&
+ exit_is_near < INFINITE_DISTANCE))
+ {
+ xom_is_stimulated(255);
+ }
+
+ int rune_is_near = abyss_rune_nearness();
+ if ((rune_was_near < INFINITE_DISTANCE &&
+ rune_is_near == INFINITE_DISTANCE)
+ || (rune_was_near == INFINITE_DISTANCE &&
+ rune_is_near < INFINITE_DISTANCE))
+ {
+ xom_is_stimulated(255);
}
}
@@ -184,6 +308,12 @@ static void abyss_lose_monster(monsters &mons)
void area_shift(void)
/*******************/
{
+#if DEBUG_ABYSS
+ mpr("area_shift().", MSGCH_DIAGNOSTICS);
+#endif
+
+ xom_check_nearness_setup();
+
for (unsigned int i = 0; i < MAX_MONSTERS; i++)
{
monsters &m = menv[i];
@@ -267,6 +397,8 @@ void area_shift(void)
generate_area(5, 5, (GXM - 5), (GYM - 5));
+ xom_check_nearness();
+
for (unsigned int mcount = 0; mcount < 15; mcount++)
{
mons_place( RANDOM_MONSTER, BEH_HOSTILE, MHITNOT, false, 1, 1,
@@ -290,6 +422,8 @@ void save_abyss_uniques()
void abyss_teleport( bool new_area )
/**********************************/
{
+ xom_check_nearness_setup();
+
int x, y, i, j, k;
if (!new_area)
@@ -311,11 +445,19 @@ void abyss_teleport( bool new_area )
if (i < 100)
{
+#if DEBUG_ABYSS
+ mpr("Non-new area Abyss teleport.", MSGCH_DIAGNOSTICS);
+#endif
you.moveto(x, y);
+ xom_check_nearness();
return;
}
}
+#if DEBUG_ABYSS
+ mpr("New area Abyss teleport.", MSGCH_DIAGNOSTICS);
+#endif
+
// teleport to a new area of the abyss:
init_pandemonium(); // get new monsters
@@ -343,6 +485,8 @@ void abyss_teleport( bool new_area )
UNIQ_LOST_IN_ABYSS );
}
+ xom_check_lost_item( mitm[k] );
+
destroy_item( k );
}
}
@@ -367,6 +511,8 @@ void abyss_teleport( bool new_area )
generate_area( 10, 10, (GXM - 10), (GYM - 10) );
+ xom_check_nearness();
+
grd[you.x_pos][you.y_pos] = DNGN_FLOOR;
if ( one_chance_in(5) )
grd[you.x_pos + 1][you.y_pos] = DNGN_ALTAR_LUGONU;
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 9a427e6b6f..6fa1b88ade 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -136,6 +136,7 @@
#include "tutorial.h"
#include "view.h"
#include "stash.h"
+#include "xom.h"
crawl_environment env;
player you;
@@ -588,13 +589,41 @@ static void handle_wizard_command( void )
break;
+ case 'C':
+ {
+ // this command isn't very exciting... feel free to replace
+ i = prompt_invent_item( "(Un)curse which item?", MT_INVLIST, -1 );
+ if (i == PROMPT_ABORT)
+ {
+ canned_msg( MSG_OK );
+ break;
+ }
+
+ item_def& item(you.inv[i]);
+
+ if (item_cursed(item))
+ do_uncurse_item(item);
+ else
+ do_curse_item(item);
+
+ break;
+ }
+
case 'B':
if (you.level_type != LEVEL_ABYSS)
- banished( DNGN_ENTER_ABYSS );
+ banished( DNGN_ENTER_ABYSS, "wizard command" );
else
down_stairs(you.your_level, DNGN_EXIT_ABYSS);
break;
+ case CONTROL('A'):
+ if (you.level_type == LEVEL_ABYSS)
+ abyss_teleport(true);
+ else
+ mpr("You can only abyss_teleport() inside the Abyss.");
+
+ break;
+
case 'g':
debug_add_skills();
break;
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index d78fa1cdc4..c4443068ff 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -60,6 +60,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
#define BEAM_STOP 1000 // all beams stopped by subtracting this
// from remaining range
@@ -1507,6 +1508,14 @@ void fire_beam( bolt &pbolt, item_def *item )
canned_msg(MSG_NOTHING_HAPPENS);
}
+ if (!pbolt.is_tracer && pbolt.beam_source != NON_MONSTER)
+ {
+ if (pbolt.foe_hurt == 0 && pbolt.fr_hurt > 0)
+ xom_is_stimulated(128);
+ else if (pbolt.foe_helped > 0 && pbolt.fr_helped == 0)
+ xom_is_stimulated(128);
+ }
+
// that's it!
#ifdef WIN32CONSOLE
if (!pbolt.is_tracer)
@@ -3146,6 +3155,8 @@ static int affect_player( bolt &beam )
}
else
{
+ bool nasty = true, nice = false;
+
// BEGIN enchantment beam
if (beam.flavour != BEAM_HASTE
&& beam.flavour != BEAM_INVISIBILITY
@@ -3156,6 +3167,12 @@ static int affect_player( bolt &beam )
&& you_resist_magic( beam.ench_power ))
{
canned_msg(MSG_YOU_RESIST);
+
+ // You *could* have gotten a free teleportation in the Abyss,
+ // but no, you resisted.
+ if (beam.flavour != BEAM_TELEPORT && you.level_type == LEVEL_ABYSS)
+ xom_is_stimulated(255);
+
return (range_used_on_hit(beam));
}
@@ -3213,11 +3230,15 @@ static int affect_player( bolt &beam )
potion_effect( POT_SPEED, beam.ench_power );
contaminate_player( 1 );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // haste
case BEAM_HEALING:
potion_effect( POT_HEAL_WOUNDS, beam.ench_power );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // heal (heal wounds potion eff)
case BEAM_PARALYSIS:
@@ -3234,12 +3255,20 @@ static int affect_player( bolt &beam )
potion_effect( POT_INVISIBILITY, beam.ench_power );
contaminate_player( 1 + random2(2) );
beam.obvious_effect = true;
+ nasty = false;
+ nice = true;
break; // invisibility
// 6 is used by digging
case BEAM_TELEPORT:
you_teleport();
+
+ // An enemy helping you escape while in the Abyss, or an
+ // enemy stabalizing a teleport that was about to happen.
+ if (beam.attitude == ATT_HOSTILE && you.level_type == LEVEL_ABYSS)
+ xom_is_stimulated(255);
+
beam.obvious_effect = true;
break;
@@ -3312,6 +3341,28 @@ static int affect_player( bolt &beam )
break;
} // end of switch (beam.colour)
+ if (nasty)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ {
+ beam.fr_hurt++;
+ xom_is_stimulated(128);
+ }
+ else
+ beam.foe_hurt++;
+ }
+
+ if (nice)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ beam.fr_helped++;
+ else
+ {
+ beam.foe_helped++;
+ xom_is_stimulated(128);
+ }
+ }
+
// regardless of affect, we need to know if this is a stopper
// or not - it seems all of the above are.
return (range_used_on_hit(beam));
@@ -3359,6 +3410,9 @@ static int affect_player( bolt &beam )
}
}
+ bool was_affected = false;
+ int old_hp = you.hp;
+
if (hurted < 0)
hurted = 0;
@@ -3367,10 +3421,16 @@ static int affect_player( bolt &beam )
if (beam.flavour == BEAM_MIASMA && hurted > 0)
{
if (player_res_poison() <= 0)
+ {
poison_player(1);
+ was_affected = true;
+ }
if (one_chance_in( 3 + 2 * player_prot_life() ))
+ {
potion_effect( POT_SLOWING, 5 );
+ was_affected = true;
+ }
}
// poisoning
@@ -3383,17 +3443,22 @@ static int affect_player( bolt &beam )
&& random2(100) < 90 - (3 * player_AC())))
{
poison_player( 1 + random2(3) );
+ was_affected = true;
}
}
if (beam.name.find("throwing net") != std::string::npos)
+ {
player_caught_in_net();
+ was_affected = true;
+ }
if (beam.name.find("curare") != std::string::npos)
{
if (random2(100) < 90 - (3 * player_AC()))
{
curare_hits_player( beam_ouch_agent(beam), 1 + random2(3) );
+ was_affected = true;
}
}
@@ -3403,7 +3468,10 @@ static int affect_player( bolt &beam )
|| you.experience_level < 6))
{
if (!player_equip( EQ_BODY_ARMOUR, ARM_MOTTLED_DRAGON_ARMOUR ))
+ {
you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1;
+ was_affected = true;
+ }
}
// simple cases for scroll burns
@@ -3429,6 +3497,21 @@ static int affect_player( bolt &beam )
mprf(MSGCH_DIAGNOSTICS, "Damage: %d", hurted );
#endif
+ if (hurted > 0 || old_hp < you.hp || was_affected)
+ {
+ if (beam.attitude != ATT_HOSTILE)
+ {
+ beam.fr_hurt++;
+
+ // Xom's ammusement at the player being damaged is handled
+ // elsewhere.
+ if (was_affected)
+ xom_is_stimulated(128);
+ }
+ else
+ beam.foe_hurt++;
+ }
+
beam_ouch( hurted, beam );
return (range_used_on_hit( beam ));
@@ -3462,6 +3545,24 @@ static int name_to_skill_level(const std::string& name)
return (2 * you.skills[type]);
}
+static void update_hurt_or_helped(bolt &beam, monsters *mon)
+{
+ if (beam.attitude != mons_attitude(mon))
+ {
+ if (nasty_beam(mon, beam))
+ beam.foe_hurt++;
+ else if (nice_beam(mon, beam))
+ beam.foe_helped++;
+ }
+ else
+ {
+ if (nasty_beam(mon, beam))
+ beam.fr_hurt++;
+ else if (nice_beam(mon, beam))
+ beam.fr_helped++;
+ }
+}
+
// return amount of range used up by affectation of this monster
static int affect_monster(bolt &beam, monsters *mon)
{
@@ -3513,6 +3614,7 @@ static int affect_monster(bolt &beam, monsters *mon)
"crumbles away!");
}
beam.obvious_effect = true;
+ update_hurt_or_helped(beam, mon);
mon->hit_points = 0;
monster_die(mon, beam);
return (BEAM_STOP);
@@ -3585,6 +3687,7 @@ static int affect_monster(bolt &beam, monsters *mon)
beam.msg_generated = true;
break;
default:
+ update_hurt_or_helped(beam, mon);
break;
}
return (rangeUsed);
@@ -3725,6 +3828,8 @@ static int affect_monster(bolt &beam, monsters *mon)
return (0);
}
+ update_hurt_or_helped(beam, mon);
+
// the beam hit.
if (mons_near(mon))
{
@@ -4606,6 +4711,18 @@ bool nasty_beam(monsters *mon, bolt &beam)
return (true);
}
+bool nice_beam( struct monsters *mon, struct bolt &beam )
+{
+ // haste
+ if (beam.flavour == BEAM_HASTE || beam.flavour == BEAM_HEALING
+ || beam.flavour == BEAM_INVISIBILITY)
+ {
+ return (true);
+ }
+
+ return (false);
+}
+
////////////////////////////////////////////////////////////////////////////
// bolt
@@ -4624,6 +4741,7 @@ bolt::bolt() : range(0), rangeMax(0), type(SYM_ZAP), colour(BLACK),
is_thrown(false), target_first(false), aimed_at_spot(false),
aux_source(), obvious_effect(false), effect_known(true),
fr_count(0), foe_count(0), fr_power(0), foe_power(0),
+ fr_hurt(0), foe_hurt(0), fr_helped(0), foe_helped(0),
is_tracer(false), aimed_at_feet(false), msg_generated(false),
in_explosion_phase(false), smart_monster(false),
can_see_invis(false), attitude(ATT_HOSTILE), foe_ratio(0),
diff --git a/crawl-ref/source/beam.h b/crawl-ref/source/beam.h
index 11cd0c5f6e..ee8819748b 100644
--- a/crawl-ref/source/beam.h
+++ b/crawl-ref/source/beam.h
@@ -150,6 +150,8 @@ struct bolt
bool effect_known; // did we _know_ this would happen?
int fr_count, foe_count; // # of times a friend/foe is "hit"
int fr_power, foe_power; // total levels/hit dice affected
+ int fr_hurt, foe_hurt; // # of friends/foes actually hurt
+ int fr_helped, foe_helped; // # of friends/foes actually helped
// INTERNAL use - should not usually be set outside of beam.cc
bool is_tracer; // is this a tracer?
@@ -195,7 +197,7 @@ void fire_beam( struct bolt &pbolt, item_def *item = NULL );
* called from: beam
* *********************************************************************** */
bool nasty_beam( struct monsters *mon, struct bolt &beam );
-
+bool nice_beam( struct monsters *mon, struct bolt &beam );
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/branch.cc b/crawl-ref/source/branch.cc
index f5a1a33769..b3cdc0e652 100644
--- a/crawl-ref/source/branch.cc
+++ b/crawl-ref/source/branch.cc
@@ -278,7 +278,7 @@ Branch branches[] = {
NULL, NULL,
0, '0', false },
- { BRANCH_HALL_OF_ZOT, BRANCH_MAIN_DUNGEON, 5, 27, 0, 0,
+ { BRANCH_HALL_OF_ZOT, BRANCH_MAIN_DUNGEON, 5, 27, BFLAG_HAS_ORB, 0,
DNGN_ENTER_ZOT, DNGN_RETURN_FROM_ZOT,
"Zot", "the Realm of Zot", "Zot",
NULL,
diff --git a/crawl-ref/source/branch.h b/crawl-ref/source/branch.h
index 9ddc1a1d0a..d587f56c38 100644
--- a/crawl-ref/source/branch.h
+++ b/crawl-ref/source/branch.h
@@ -18,7 +18,8 @@ enum branch_flag_type
BFLAG_NO_TELE_CONTROL = (1 << 0), // Teleport control not allowed.
BFLAG_NOT_MAPPABLE = (1 << 1), // Branch levels not mappable.
- BFLAG_NO_MAGIC_MAP = (1 << 2) // Branch levels can't be magic mapped.
+ BFLAG_NO_MAGIC_MAP = (1 << 2), // Branch levels can't be magic mapped.
+ BFLAG_HAS_ORB = (1 << 3) // Orb is on the floor in this branch
};
struct Branch
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 50b17ed9a2..5b6843726e 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -1598,9 +1598,11 @@ static void list_wizard_commands()
cols.add_formatted(0,
"a : acquirement\n"
"A : set all skills to level\n"
+ "Ctrl-A : generate new Abyss area\n"
"b : controlled blink\n"
"B : banish yourself to the Abyss\n"
"c : card effect\n"
+ "C : (un)curse item\n"
"g : add a skill\n"
"G : banish all monsters\n"
"Ctrl-G : save ghost (bones file)\n"
@@ -1618,11 +1620,11 @@ static void list_wizard_commands()
"r : change character's species\n"
"s : gain 20000 skill points\n"
"S : set skill to level\n"
- "t : tweak object properties\n"
- "T : make a trap\n",
+ "t : tweak object properties\n",
true, true);
cols.add_formatted(1,
+ "T : make a trap\n"
"v : show gold value of an item\n"
"x : gain an experience level\n"
"Ctrl-X : change experience level\n"
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 6fad244740..8ab66a40e6 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -2549,12 +2549,17 @@ void debug_card()
mpr("Unknown card.");
return;
}
-
+
+ std::string wanted = buf;
+ lowercase(wanted);
+
bool found_card = false;
for ( int i = 0; i < NUM_CARDS; ++i )
{
const card_type c = static_cast<card_type>(i);
- if ( strstr(card_name(c), buf) != NULL )
+ std::string card = card_name(c);
+ lowercase(card);
+ if ( card.find(wanted) != std::string::npos )
{
card_effect(c, DECK_RARITY_LEGENDARY);
found_card = true;
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index 313e5197a4..7a728b0f46 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -44,6 +44,7 @@
#include "transfor.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
#define VECFROM(x) (x), (x) + ARRAYSIZE(x)
#define DEFVEC(Z) static std::vector<card_type> Z(VECFROM(a_##Z))
@@ -169,7 +170,8 @@ const char* card_name(card_type card)
return "a very buggy card";
}
-static card_type choose_one_card(const item_def& item, bool message)
+static card_type choose_one_card(const item_def& item, bool message,
+ bool &was_oddity)
{
std::vector<card_type> *pdeck = NULL;
switch ( item.sub_type )
@@ -212,7 +214,8 @@ static card_type choose_one_card(const item_def& item, bool message)
{
if ( message )
mpr("This card doesn't seem to belong here.");
- pdeck = &deck_of_oddities;
+ pdeck = &deck_of_oddities;
+ was_oddity = true;
}
card_type chosen = (*pdeck)[random2(pdeck->size())];
@@ -225,6 +228,13 @@ static card_type choose_one_card(const item_def& item, bool message)
return chosen;
}
+static card_type choose_one_card(const item_def& item, bool message)
+{
+ bool garbage;
+
+ return choose_one_card(item, message, garbage);
+}
+
static bool wielding_deck()
{
if ( you.equip[EQ_WEAPON] == -1 )
@@ -449,7 +459,52 @@ void evoke_deck( item_def& deck )
// If the deck wasn't marked, draw a fair card.
if ( deck.plus2 == 0 )
{
- card_effect( choose_one_card(deck, true), deck_rarity(deck) );
+ // Could a Xom worshipper ever get a stacked deck in the first
+ // place?
+ int amusement = 64;
+ bool was_oddity = false;
+ card_type card = choose_one_card(deck, true, was_oddity);
+
+ if (!item_type_known(deck))
+ amusement *= 2;
+ // Expecting one type of card but got another, real funny.
+ else if (was_oddity)
+ amusement = 255;
+
+ if (player_in_a_dangerous_place())
+ amusement *= 2;
+
+ switch (card)
+ {
+ case CARD_XOM:
+ // Handled elswehre
+ amusement = 0;
+ break;
+
+ case CARD_BLANK:
+ // Boring
+ amusement = 0;
+ break;
+
+ case CARD_DAMNATION:
+ // Nothing happened, boring.
+ if (you.level_type != LEVEL_DUNGEON)
+ amusement = 0;
+ break;
+
+ case CARD_MINEFIELD:
+ case CARD_FAMINE:
+ case CARD_CURSE:
+ // Always hilarious.
+ amusement = 255;
+
+ default:
+ break;
+ }
+
+ card_effect(card, deck_rarity(deck) );
+
+ xom_is_stimulated(amusement);
if ( deck.sub_type != MISC_DECK_OF_PUNISHMENT )
{
@@ -458,6 +513,7 @@ void evoke_deck( item_def& deck )
if (one_chance_in(3))
brownie_points++;
}
+
}
else
{
@@ -660,7 +716,7 @@ static void damnation_card(int power, deck_rarity_type rarity)
if ( mon_to_banish == NON_MONSTER ) // banish yourself!
{
- banished(DNGN_ENTER_ABYSS);
+ banished(DNGN_ENTER_ABYSS, "drawing a card");
break; // don't banish anything else
}
else
@@ -1293,6 +1349,19 @@ void card_effect(card_type which_card, deck_rarity_type rarity)
msg::stream << "You have drawn " << card_name( which_card )
<< '.' << std::endl;
+ if (which_card == CARD_XOM && !crawl_state.is_god_acting())
+ {
+ if (you.religion == GOD_XOM)
+ {
+ // Being a self-centered diety, Xom *always* finds this
+ // maximally hilarious.
+ god_speaks(GOD_XOM, "Xom roars with laughter!");
+ you.gift_timeout = 255;
+ }
+ else if (you.penance[GOD_XOM] > 0)
+ god_speaks(GOD_XOM, "Xom laughs nastily.");
+ }
+
switch (which_card)
{
case CARD_BLANK: break;
@@ -1377,6 +1446,13 @@ void card_effect(card_type which_card, deck_rarity_type rarity)
break;
}
+ if (you.religion == GOD_XOM && which_card == CARD_BLANK)
+ {
+ god_speaks(GOD_XOM, "\"How boring, lets spice things up a little.\"");
+
+ xom_acts(abs(you.piety - 100));
+ }
+
return;
}
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index 941d82d223..326fa33151 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -42,6 +42,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
extern std::vector<SelItem> items_for_multidrop;
@@ -293,6 +294,17 @@ bool is_being_butchered(const item_def &item)
return (false);
}
+// Xom is amused by a potential food source going to waste, and is
+// more amused the hungrier you are.
+static void xom_check_corpse_waste()
+{
+ int food_need = 7000 - you.hunger;
+ if (food_need < 0)
+ food_need = 0;
+
+ xom_is_stimulated(64 + (191 * food_need / 6000));
+}
+
void handle_delay( void )
/***********************/
{
@@ -353,24 +365,41 @@ void handle_delay( void )
// Note that a monster could have raised the corpse and another
// monster could die and create a corpse with the same ID number...
// However, it would not be at the player's square like the
- // original and that's why we do it this way. Note that
- // we ignore the conversion to skeleton possibility just to
- // be nice. -- bwr
+ // original and that's why we do it this way.
if (is_valid_item( mitm[ delay.parm1 ] )
&& mitm[ delay.parm1 ].base_type == OBJ_CORPSES
&& mitm[ delay.parm1 ].x == you.x_pos
&& mitm[ delay.parm1 ].y == you.y_pos )
{
- // special < 100 is the rottenness check
- if ( (mitm[delay.parm1].special < 100) &&
- (delay.parm2 >= 100) )
+ if (mitm[ delay.parm1 ].sub_type == CORPSE_SKELETON)
{
- mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
- delay.parm2 = 99; // don't give the message twice
+ mpr("The corpse rots away into a skeleton!");
+ if (you.species == SP_GHOUL)
+ xom_check_corpse_waste();
+ else
+ xom_is_stimulated(32);
+ delay.duration = 0;
}
+ else
+ {
+ // special < 100 is the rottenness check
+ if ( (mitm[delay.parm1].special < 100) &&
+ (delay.parm2 >= 100) )
+ {
+ mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
+ delay.parm2 = 99; // don't give the message twice
+
+ if (you.species != SP_VAMPIRE
+ && you.species != SP_MUMMY
+ && you.species != SP_GHOUL)
+ {
+ xom_check_corpse_waste();
+ }
+ }
- // mark work done on the corpse in case we stop -- bwr
- mitm[ delay.parm1 ].plus2++;
+ // mark work done on the corpse in case we stop -- bwr
+ mitm[ delay.parm1 ].plus2++;
+ }
}
else
{
@@ -589,6 +618,20 @@ static void finish_delay(const delay_queue_item &delay)
const item_def &item = mitm[delay.parm1];
if (is_valid_item(item) && item.base_type == OBJ_CORPSES)
{
+
+ if (item.sub_type == CORPSE_SKELETON)
+ {
+ mpr("The corpse rots away into a skeleton just before you "
+ "finish butchering it!");
+
+ if (you.species == SP_GHOUL)
+ xom_check_corpse_waste();
+ else
+ xom_is_stimulated(64);
+
+ break;
+ }
+
mprf("You finish %s the corpse into pieces.",
(you.has_usable_claws() || you.mutation[MUT_FANGS] == 3) ?
"ripping" : "chopping");
@@ -679,7 +722,8 @@ static void armour_wear_effects(const int item_slot)
set_ident_flags(arm, ISFLAG_EQ_ARMOUR_MASK );
mprf("You finish putting on %s.", arm.name(DESC_NOCAP_YOUR).c_str());
- const equipment_type eq_slot = get_armour_slot(arm);
+ const equipment_type eq_slot = get_armour_slot(arm);
+ const bool known_cursed = item_known_cursed(arm);
if (eq_slot == EQ_BODY_ARMOUR)
{
@@ -811,7 +855,16 @@ static void armour_wear_effects(const int item_slot)
{
mpr( "Oops, that feels deathly cold." );
learned_something_new(TUT_YOU_CURSED);
- xom_is_stimulated(128);
+
+ // Cursed cloaks prevent you from removing body armour
+ int cloak_mult = 1;
+ if (get_armour_slot(arm) == EQ_CLOAK)
+ cloak_mult = 2;
+
+ if (known_cursed)
+ xom_is_stimulated(32 * cloak_mult);
+ else
+ xom_is_stimulated(64 * cloak_mult);
}
if (eq_slot == EQ_SHIELD)
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index e66dcc0a5d..2ef983478d 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -54,7 +54,7 @@
#include "stuff.h"
#include "spl-util.h"
#include "tutorial.h"
-
+#include "xom.h"
// ========================================================================
// Internal Functions
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 5a0922f7af..bc8bebd375 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -40,15 +40,16 @@
#include "ouch.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "skills2.h"
#include "spells3.h"
#include "spells4.h"
#include "spl-book.h"
#include "spl-util.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "view.h"
+#include "xom.h"
// torment_monsters is called with power 0 because torment is
// UNRESISTABLE except for being undead or having torment
@@ -158,10 +159,39 @@ void banished(dungeon_feature_type gate_type, const std::string &who)
take_note(Note(NOTE_USER_NOTE, 0, 0, what.c_str()), true);
}
- down_stairs(you.your_level, gate_type); // heh heh
+ // Now figure out how we got here.
+ if (who.find("self") != std::string::npos || who == you.your_name
+ || who == "you" || who == "You" || crawl_state.is_god_acting())
+ {
+ // down_stairs() will take care of setting things.
+ you.entry_cause = EC_UNKNOWN;
+ }
+ else if (who.find("distortion") != std::string::npos)
+ {
+ if (who.find("wield") != std::string::npos)
+ {
+ if (who.find("unknowing") != std::string::npos)
+ you.entry_cause = EC_SELF_ACCIDENT;
+ else
+ you.entry_cause = EC_SELF_RISKY;
+ }
+ else if (who.find("affixation") != std::string::npos)
+ you.entry_cause = EC_SELF_ACCIDENT;
+ else if (who.find("branding") != std::string::npos)
+ you.entry_cause = EC_SELF_RISKY;
+ else
+ you.entry_cause = EC_MONSTER;
+ }
+ else if (who == "drawing a card")
+ you.entry_cause = EC_SELF_RISKY;
+ else if (who.find("miscast") != std::string::npos)
+ you.entry_cause = EC_MISCAST;
+ else if (who == "wizard command")
+ you.entry_cause = EC_SELF_EXPLICIT;
+ else
+ you.entry_cause = EC_MONSTER;
- if (gate_type == DNGN_ENTER_ABYSS || gate_type == DNGN_ENTER_PANDEMONIUM)
- xom_is_stimulated(255);
+ down_stairs(you.your_level, gate_type, you.entry_cause); // heh heh
}
bool forget_spell(void)
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 4d9ac82043..61ddc607ce 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -171,6 +171,8 @@ enum attribute_type
ATTR_GOD_GIFT_COUNT, //jmf: added to help manage god gift giving
ATTR_DELAYED_FIREBALL, // bwr: reserve fireballs
ATTR_HELD, // caught in a net
+ ATTR_ABYSS_ENTOURAGE, // maximum number of hostile monsters in
+ // sight of the player while in the Abyss.
NUM_ATTRIBUTES
};
@@ -1340,6 +1342,19 @@ enum level_area_type // you.level_type
NUM_LEVEL_AREA_TYPES
};
+enum entry_cause_type
+{
+ EC_UNKNOWN,
+ EC_SELF_EXPLICIT,
+ EC_SELF_RISKY, // i.e., wielding an id'd distorion weapon
+ EC_SELF_ACCIDENT, // i.e., wielding an un-id'd distortion weapon
+ EC_MISCAST,
+ EC_GOD_RETRIUBTION,
+ EC_GOD_ACT, // Xom sending the player somewhere for amusement
+ EC_MONSTER,
+ NUM_ENTRY_CAUSE_TYPES
+};
+
// Can't change this order without breaking saves.
enum map_marker_type
{
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index a605bc89f1..578af53e2f 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -615,6 +615,9 @@ public:
level_area_type level_type;
std::string level_type_name;
+ entry_cause_type entry_cause;
+ god_type entry_cause_god;
+
branch_type where_are_you;
FixedVector<unsigned char, 30> branch_stairs;
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index b56720a117..7d8471429e 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -76,6 +76,7 @@
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
#define HIT_WEAK 7
#define HIT_MED 18
@@ -475,11 +476,27 @@ bool melee_attack::attack()
identify_mimic(atk);
identify_mimic(def);
+ // Xom thinks fumbles are funny...
if (attacker->fumbles_attack())
{
- xom_is_stimulated(14); // Xom thinks that is funny.
+ // ... and thinks fumbling when trying to hit yourself is just
+ // hilarious.
+ if (attacker == defender)
+ xom_is_stimulated(255);
+ else
+ xom_is_stimulated(14);
return (false);
}
+ // Non-fumbled self-attacks due to confusion are still pretty
+ // funny, though.
+ else if (attacker == defender && attacker->confused())
+ {
+ // And is still hilarious if it's the player.
+ if (attacker->atype() == ACT_PLAYER)
+ xom_is_stimulated(255);
+ else
+ xom_is_stimulated(128);
+ }
// Allow god to get offended, etc.
attacker->attacking(defender);
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 2e69a145c1..190d75cb9c 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -90,6 +90,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
void save_level(int level_saved, level_area_type lt,
branch_type where_were_you);
@@ -823,6 +824,29 @@ static void grab_followers()
}
}
+// Should be called afetr grab_followers(), so that items carried by
+// followers won't be considered lost.
+static void _xom_check_lost_items(level_area_type old_level_type)
+{
+ if (old_level_type == LEVEL_DUNGEON)
+ return;
+
+ int amusement = 0;
+
+ for (int i = 0; i < MAX_ITEMS; i++)
+ {
+ item_def& item(mitm[i]);
+
+ if (!is_valid_item(item))
+ continue;
+
+ // Item is in player intentory, so it's not lost.
+ if (item.x == -1 && item.y == -1)
+ continue;
+
+ xom_check_lost_item(item);
+ }
+}
bool load( dungeon_feature_type stair_taken, int load_mode,
level_area_type old_level_type, char old_level,
@@ -872,6 +896,8 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
save_level( old_level, LEVEL_DUNGEON, where_were_you2 );
}
+ _xom_check_lost_items(old_level_type);
+
// Try to open level savefile.
FILE *levelFile = fopen(cha_fil.c_str(), "rb");
@@ -1027,6 +1053,9 @@ bool load( dungeon_feature_type stair_taken, int load_mode,
curr_PlaceInfo.assert_validity();
}
+ if (just_created_level)
+ you.attribute[ATTR_ABYSS_ENTOURAGE] = 0;
+
return just_created_level;
} // end load()
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index bbad92c57c..97d5319e7d 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -50,6 +50,7 @@
#include "stuff.h"
#include "transfor.h"
#include "tutorial.h"
+#include "xom.h"
static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
static void eat_chunk( int chunk_effect );
diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc
index e313767cf9..02708f95fb 100644
--- a/crawl-ref/source/it_use2.cc
+++ b/crawl-ref/source/it_use2.cc
@@ -40,6 +40,7 @@
#include "spl-util.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
// From an actual potion, pow == 40 -- bwr
bool potion_effect( potion_type pot_eff, int pow )
@@ -472,7 +473,7 @@ void unwield_item(bool showMsgs)
// int effect = 9 - random2avg( you.skills[SK_TRANSLOCATIONS] * 2, 2 );
miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "a distortion effect" );
+ "distortion unwield" );
break;
// when more are added here, *must* duplicate unwielding
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index 9ee69e8f87..96b5bc1f98 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -52,6 +52,7 @@
#include "state.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
static bool ball_of_energy(void);
static bool ball_of_fixation(void);
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 212e2ea00e..18d4c1ffe5 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -61,6 +61,7 @@
#include "player.h"
#include "randart.h"
#include "religion.h"
+#include "shopping.h"
#include "skills.h"
#include "skills2.h"
#include "spells1.h"
@@ -74,6 +75,7 @@
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static bool drink_fountain();
static bool enchant_armour();
@@ -401,6 +403,8 @@ void wield_effects(int item_wield_2, bool showMsgs)
{
unsigned char i_dam = 0;
+ const bool known_cursed = item_known_cursed(you.inv[item_wield_2]);
+
// and here we finally get to the special effects of wielding {dlb}
if (you.inv[item_wield_2].base_type == OBJ_MISCELLANY)
{
@@ -593,7 +597,11 @@ void wield_effects(int item_wield_2, bool showMsgs)
break;
case SPWPN_DISTORTION:
- miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
+ if (!was_known)
+ xom_is_stimulated(128);
+ miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
+ was_known ? "distortion wield" :
+ "uknowning distortion wield");
break;
case SPWPN_SINGING_SWORD:
@@ -645,7 +653,10 @@ void wield_effects(int item_wield_2, bool showMsgs)
if (item_cursed( you.inv[item_wield_2] ))
{
mpr("It sticks to your hand!");
- xom_is_stimulated(64);
+ if (known_cursed)
+ xom_is_stimulated(32);
+ else
+ xom_is_stimulated(64);
}
}
@@ -2279,8 +2290,11 @@ void jewellery_wear_effects(item_def &item)
// Randart jewellery shouldn't auto-ID just because the
// base type is known. Somehow the player should still
// be told, preferably by message. (jpeg)
- const bool artefact = is_random_artefact( item );
- const bool identified = fully_identified( item );
+ const bool artefact = is_random_artefact( item );
+ const bool identified = fully_identified( item );
+ const bool known_cursed = item_known_cursed( item );
+ const bool known_bad = item_type_known( item )
+ && (item_value( item ) <= 2);
switch (item.sub_type)
{
@@ -2406,7 +2420,11 @@ void jewellery_wear_effects(item_def &item)
mprf("Oops, that %s feels deathly cold.",
jewellery_is_amulet(item)? "amulet" : "ring");
learned_something_new(TUT_YOU_CURSED);
- xom_is_stimulated(128);
+
+ if (known_cursed || known_bad)
+ xom_is_stimulated(64);
+ else
+ xom_is_stimulated(128);
}
// cursed or not, we know that since we've put the ring on
@@ -3268,7 +3286,7 @@ static bool affix_weapon_enchantment()
// from unwield_item
miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100,
- "a distortion effect" );
+ "distortion affixation" );
success = false;
break;
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index cd77235da0..1ed8f1cc52 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -37,6 +37,7 @@
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
// XXX: name strings in most of the following are currently unused!
@@ -445,6 +446,26 @@ bool item_known_uncursed( const item_def &item )
void do_curse_item( item_def &item )
{
+ // Xom is amused by the player's items being cursed, especially
+ // if they're worn/equipped.
+ if (!(item.flags & ISFLAG_CURSED) && item.x == -1 && item.y == -1)
+ {
+ int amusement = 64;
+
+ if (item_is_equipped(item))
+ {
+ amusement *= 2;
+
+ // Cursed cloaks prevent you from removing body armour
+ if (item.base_type == OBJ_ARMOUR
+ && get_armour_slot(item) == EQ_CLOAK)
+ {
+ amusement *= 2;
+ }
+ }
+ xom_is_stimulated(amusement);
+ }
+
item.flags |= ISFLAG_CURSED;
}
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 60bacbd15b..7d7daea1b6 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -34,6 +34,7 @@
#include "externs.h"
#include "beam.h"
+#include "branch.h"
#include "cloud.h"
#include "debug.h"
#include "delay.h"
@@ -73,6 +74,7 @@
#include "transfor.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static bool invisible_to_player( const item_def& item );
static void item_list_on_square( std::vector<const item_def*>& items,
@@ -530,6 +532,8 @@ void destroy_item_stack( int x, int y )
UNIQ_LOST_IN_ABYSS );
}
+ xom_check_lost_item( mitm[o] );
+
mitm[o].base_type = OBJ_UNASSIGNED;
mitm[o].quantity = 0;
}
@@ -944,8 +948,16 @@ static std::string origin_place_desc(const item_def &item)
bool is_rune(const item_def &item)
{
- return (item.base_type == OBJ_MISCELLANY &&
- item.sub_type == MISC_RUNE_OF_ZOT);
+ return (item.base_type == OBJ_MISCELLANY
+ && item.sub_type == MISC_RUNE_OF_ZOT);
+}
+
+bool is_unique_rune(const item_def &item)
+{
+ return (item.base_type == OBJ_MISCELLANY
+ && item.sub_type == MISC_RUNE_OF_ZOT
+ && item.plus != RUNE_DEMONIC
+ && item.plus != RUNE_ABYSSAL);
}
bool origin_describable(const item_def &item)
@@ -1473,8 +1485,12 @@ int move_item_to_player( int obj, int quant_got, bool quiet )
if (!quiet)
mpr("Now all you have to do is get back out of the dungeon!");
you.char_direction = GDT_ASCENDING;
+ xom_is_stimulated(255, XM_INTRIGUED);
}
+ if (item.base_type == OBJ_ORBS && you.level_type == LEVEL_DUNGEON)
+ unset_branch_flags(BFLAG_HAS_ORB);
+
you.turn_is_over = true;
return (retval);
@@ -1542,6 +1558,9 @@ void move_item_to_grid( int *const obj, int x, int y )
mitm[*obj].link = igrd[x][y];
igrd[x][y] = *obj;
+ if (mitm[*obj].base_type == OBJ_ORBS && you.level_type == LEVEL_DUNGEON)
+ set_branch_flags(BFLAG_HAS_ORB);
+
return;
}
@@ -3026,6 +3045,30 @@ item_def find_item_type(object_class_type base_type, std::string name)
return (item);
}
+bool item_is_equipped(const item_def &item)
+{
+ if (item.x != -1 || item.y != -1)
+ return (false);
+
+ for (int i = 0; i < NUM_EQUIP; i++)
+ {
+ if (you.equip[i] == EQ_NONE)
+ continue;
+
+ item_def& eq(you.inv[you.equip[i]]);
+
+ if (!is_valid_item(eq))
+ continue;
+
+ if (eq.slot == item.slot)
+ return (true);
+ else if (&eq == &item)
+ return (true);
+ }
+
+ return (false);
+}
+
////////////////////////////////////////////////////////////////////////
// item_def functions.
diff --git a/crawl-ref/source/items.h b/crawl-ref/source/items.h
index f223c35382..9d0b8eb93c 100644
--- a/crawl-ref/source/items.h
+++ b/crawl-ref/source/items.h
@@ -163,9 +163,12 @@ void autopickup();
int find_free_slot(const item_def &i);
bool is_rune(const item_def &item);
+bool is_unique_rune(const item_def &item);
bool need_to_autoinscribe();
void request_autoinscribe(bool do_inscribe = true);
void autoinscribe();
+bool item_is_equipped(const item_def &item);
+
#endif
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 5ad6c4a742..e09c774295 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -68,6 +68,7 @@
#include "skills2.h"
#include "spells3.h"
#include "stash.h"
+#include "state.h"
#include "stuff.h"
#include "terrain.h"
#include "transfor.h"
@@ -75,6 +76,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
// void place_chunks(int mcls, unsigned char rot_status, unsigned char chx,
// unsigned char chy, unsigned char ch_col)
@@ -466,7 +468,54 @@ static void leaving_level_now()
you.level_type_name = newtype;
}
-void up_stairs(dungeon_feature_type force_stair)
+static void set_entry_cause(entry_cause_type default_cause,
+ level_area_type old_level_type)
+{
+ ASSERT(default_cause != NUM_ENTRY_CAUSE_TYPES);
+
+ if (old_level_type == you.level_type)
+ return;
+
+ if (crawl_state.is_god_acting())
+ {
+ if (crawl_state.is_god_retribution())
+ you.entry_cause = EC_GOD_RETRIUBTION;
+ else
+ you.entry_cause = EC_GOD_ACT;
+
+ you.entry_cause_god = crawl_state.which_god_acting();
+ }
+ else if (default_cause != EC_UNKNOWN)
+ {
+ you.entry_cause = default_cause;
+ you.entry_cause_god = GOD_NO_GOD;
+ }
+ else
+ {
+ you.entry_cause = EC_SELF_EXPLICIT;
+ you.entry_cause_god = GOD_NO_GOD;
+ }
+}
+
+static int runes_in_pack()
+{
+ int num_runes = 0;
+
+ for (int i = 0; i < ENDOFPACK; i++)
+ {
+ if (is_valid_item( you.inv[i] )
+ && you.inv[i].base_type == OBJ_MISCELLANY
+ && you.inv[i].sub_type == MISC_RUNE_OF_ZOT)
+ {
+ num_runes += you.inv[i].quantity;
+ }
+ }
+
+ return num_runes;
+}
+
+void up_stairs(dungeon_feature_type force_stair,
+ entry_cause_type entry_cause)
{
dungeon_feature_type stair_find =
force_stair? force_stair : grd[you.x_pos][you.y_pos];
@@ -617,6 +666,9 @@ void up_stairs(dungeon_feature_type force_stair)
load(stair_taken, LOAD_ENTER_LEVEL, old_level_type, old_level, old_where);
+ set_entry_cause(entry_cause, old_level_type);
+ entry_cause = you.entry_cause;
+
you.turn_is_over = true;
save_game_state();
@@ -625,6 +677,16 @@ void up_stairs(dungeon_feature_type force_stair)
viewwindow(1, true);
+ // Left Zot without enough runes to get back in (probably because
+ // of dropping some runes within Zot), but need to get back in Zot
+ // to get the Orb? Zom finds that funny.
+ if (stair_find == DNGN_RETURN_FROM_ZOT
+ && runes_in_pack() < NUMBER_OF_RUNES_NEEDED
+ && (branches[BRANCH_HALL_OF_ZOT].branch_flags & BFLAG_HAS_ORB))
+ {
+ xom_is_stimulated(255, "Xom snickers loudly.", true);
+ }
+
if (you.skills[SK_TRANSLOCATIONS] > 0 && !allow_control_teleport( true ))
mpr( "You sense a powerful magical force warping space.", MSGCH_WARN );
@@ -687,7 +749,8 @@ void up_stairs(dungeon_feature_type force_stair)
}
} // end up_stairs()
-void down_stairs( int old_level, dungeon_feature_type force_stair )
+void down_stairs( int old_level, dungeon_feature_type force_stair,
+ entry_cause_type entry_cause )
{
int i;
const level_area_type old_level_type = you.level_type;
@@ -761,17 +824,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
if (stair_find == DNGN_ENTER_ZOT)
{
- int num_runes = 0;
-
- for (i = 0; i < ENDOFPACK; i++)
- {
- if (is_valid_item( you.inv[i] )
- && you.inv[i].base_type == OBJ_MISCELLANY
- && you.inv[i].sub_type == MISC_RUNE_OF_ZOT)
- {
- num_runes += you.inv[i].quantity;
- }
- }
+ int num_runes = runes_in_pack();
if (num_runes < NUMBER_OF_RUNES_NEEDED)
{
@@ -871,7 +924,8 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
if (stair_find == DNGN_EXIT_ABYSS || stair_find == DNGN_EXIT_PANDEMONIUM)
{
mpr("You pass through the gate.");
- more();
+ if (!(you.wizard && crawl_state.is_replaying_keys()))
+ more();
}
if (old_level_type != you.level_type && you.level_type == LEVEL_DUNGEON)
@@ -953,9 +1007,64 @@ void down_stairs( int old_level, dungeon_feature_type force_stair )
const bool newlevel =
load(stair_taken, LOAD_ENTER_LEVEL, old_level_type,
old_level, old_where);
-
+
+ set_entry_cause(entry_cause, old_level_type);
+ entry_cause = you.entry_cause;
+
if (newlevel)
- xom_is_stimulated(49);
+ {
+ switch(you.level_type)
+ {
+ case LEVEL_DUNGEON:
+ xom_is_stimulated(49);
+ break;
+
+ case LEVEL_PORTAL_VAULT:
+ // Portal vaults aren't as interesting.
+ xom_is_stimulated(25);
+ break;
+
+ case LEVEL_LABYRINTH:
+ // Finding the way out of a labyrinth interests Xom.
+ xom_is_stimulated(98);
+ break;
+
+ case LEVEL_ABYSS:
+ case LEVEL_PANDEMONIUM:
+ {
+ // Paranoia
+ if (old_level_type == you.level_type)
+ break;
+
+ PlaceInfo &place_info = you.get_place_info();
+
+ // Entering voluntarily only stimulates Xom if you've never
+ // been there before
+ if ((place_info.num_visits == 1 && place_info.levels_seen == 1)
+ || entry_cause != EC_SELF_EXPLICIT)
+ {
+ if (crawl_state.is_god_acting())
+ xom_is_stimulated(256);
+ else if (entry_cause == EC_SELF_EXPLICIT)
+ {
+ // Entering Pandemonium or the Abyss for the first
+ // time *voluntarily* stimulates Xom much more than
+ // entering a normal dungeon level for the first time.
+ xom_is_stimulated(128, XM_INTRIGUED);
+ }
+ else if (entry_cause == EC_SELF_RISKY)
+ xom_is_stimulated(128);
+ else
+ xom_is_stimulated(256);
+ }
+
+ break;
+ }
+
+ default:
+ ASSERT(false);
+ }
+ }
unsigned char pc = 0;
unsigned char pt = random2avg(28, 3);
diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h
index 7d594af86e..460c76e403 100644
--- a/crawl-ref/source/misc.h
+++ b/crawl-ref/source/misc.h
@@ -39,8 +39,9 @@ void search_around( bool only_adjacent = false );
/* ***********************************************************************
* called from: acr - effects - spells3
* *********************************************************************** */
-void down_stairs(int old_level, dungeon_feature_type force_stair = DNGN_UNSEEN);
-
+void down_stairs(int old_level,
+ dungeon_feature_type force_stair = DNGN_UNSEEN,
+ entry_cause_type entry_cause = EC_UNKNOWN);
// last updated 12may2000 {dlb}
/* ***********************************************************************
@@ -75,7 +76,8 @@ void turn_corpse_into_chunks( item_def &item );
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void up_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN);
+void up_stairs(dungeon_feature_type force_stair = DNGN_UNSEEN,
+ entry_cause_type entry_cause = EC_UNKNOWN);
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index c9775005c9..c06233b88a 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -67,6 +67,7 @@
#include "tutorial.h"
#include "view.h"
#include "stash.h"
+#include "xom.h"
static bool handle_special_ability(monsters *monster, bolt & beem);
static bool handle_pickup(monsters *monster);
@@ -242,6 +243,10 @@ bool curse_an_item( bool decay_potions )
/* don't change you.inv_special (just for fun) */
if (you.inv[item].base_type == OBJ_POTIONS)
{
+ // Xom is amused by useful potions being ruined.
+ if (item_value(you.inv[item], true) / you.inv[item].quantity > 2)
+ xom_is_stimulated(32 * you.inv[item].quantity);
+
you.inv[item].sub_type = POT_DECAY;
unset_ident_flags( you.inv[item], ISFLAG_IDENT_MASK ); // all different
}
diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc
index f59a2b99d2..cf6cb04919 100644
--- a/crawl-ref/source/mutation.cc
+++ b/crawl-ref/source/mutation.cc
@@ -46,6 +46,7 @@
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
int how_mutated(void);
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index ebfb0d2b7a..636a9234dc 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -77,6 +77,7 @@
#include "stuff.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
static void end_game( scorefile_entry &se );
@@ -682,12 +683,24 @@ static void xom_checks_damage(kill_method_type death_type,
//if (you.hp <= dam)
// xom_is_stimulated(32);
- if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
- || death_source < 0 || death_source >= MAX_MONSTERS)
+ if (death_type == KILLED_BY_TARGETTING)
+ {
+ // Xom thinks the player hurting him/herself is funny.
+ xom_is_stimulated(255 * dam / (dam + you.hp));
+ return;
+ }
+ else if (death_type == KILLED_BY_FALLING_DOWN_STAIRS)
+ {
+ // Xom thinks falling down the stairs is hilarious
+ xom_is_stimulated(255);
+ return;
+ }
+ else if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
+ || death_source < 0 || death_source >= MAX_MONSTERS)
{
return ;
}
-
+
int amusementvalue = 1;
const monsters *monster = &menv[death_source];
@@ -695,6 +708,13 @@ static void xom_checks_damage(kill_method_type death_type,
if (!monster->alive())
return;
+ if (mons_attitude(monster) == ATT_FRIENDLY)
+ {
+ // Xom thinks collateral damage is funny
+ xom_is_stimulated(255 * dam / (dam + you.hp));
+ return;
+ }
+
int leveldif = monster->hit_dice - you.experience_level;
if (leveldif == 0)
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index c897a1432e..e6e36f69be 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -70,6 +70,7 @@
#include "travel.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
std::string pronoun_you(description_level_type desc)
{
@@ -5121,7 +5122,9 @@ void player::init()
your_level = 0;
level_type = LEVEL_DUNGEON;
- where_are_you = BRANCH_MAIN_DUNGEON;
+ entry_cause = EC_SELF_EXPLICIT;
+ entry_cause_god = GOD_NO_GOD;
+ where_are_you = BRANCH_MAIN_DUNGEON;
char_direction = GDT_DESCENDING;
prev_targ = MHITNOT;
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 3aacbe4df7..1171c62c47 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -73,6 +73,7 @@
#include "terrain.h"
#include "tutorial.h"
#include "view.h"
+#include "xom.h"
#if DEBUG_RELIGION
# define DEBUG_DIAGNOSTICS 1
diff --git a/crawl-ref/source/religion.h b/crawl-ref/source/religion.h
index 1d124a1fa2..20bf075669 100644
--- a/crawl-ref/source/religion.h
+++ b/crawl-ref/source/religion.h
@@ -44,21 +44,10 @@ bool god_likes_butchery(god_type god);
bool god_hates_butchery(god_type god);
void divine_retribution(god_type god);
-bool xom_is_nice();
-void xom_is_stimulated(int maxinterestingness);
-void xom_acts(bool niceness, int sever);
-const char *describe_xom_favour();
-
bool beogh_water_walk();
void beogh_idol_revenge();
bool ely_destroy_weapons();
void trog_burn_books();
bool tso_stab_safe_monster(const actor *act);
-
-inline void xom_acts(int sever)
-{
- xom_acts(xom_is_nice(), sever);
-}
-
#endif
diff --git a/crawl-ref/source/skills2.cc b/crawl-ref/source/skills2.cc
index b21d075fcc..91bfaca21c 100644
--- a/crawl-ref/source/skills2.cc
+++ b/crawl-ref/source/skills2.cc
@@ -34,7 +34,6 @@
#include "menu.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "stuff.h"
#include "transfor.h"
#include "view.h"
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index 0d1f1ef171..6b1a19a48d 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -50,6 +50,7 @@
#include "terrain.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
static int raise_corpse( int corps, int corx, int cory, beh_type corps_beh,
int corps_hit, int actual );
@@ -379,9 +380,16 @@ int animate_a_corpse( int axps, int ayps, beh_type corps_beh, int corps_hit,
if (is_animatable_corpse(item) &&
(class_allowed == CORPSE_BODY || item.sub_type == CORPSE_SKELETON))
{
+ bool was_butchering = is_being_butchered(item);
+
rc = raise_corpse(objl, axps, ayps, corps_beh, corps_hit, 1);
if ( rc )
+ {
mpr("The dead are walking!");
+
+ if (was_butchering)
+ xom_is_stimulated(255);
+ }
break;
}
objl = item.link;
@@ -611,7 +619,7 @@ bool brand_weapon(int which_brand, int power)
// with removing the miscast effect. We may need to revise the spell
// to level 8 or 9. XXX.
// miscast_effect(SPTYP_TRANSLOCATION,
- // 9, 90, 100, "a distortion effect");
+ // 9, 90, 100, "distortion branding");
break;
case SPWPN_PAIN:
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 3560fbb80f..f8e6621329 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -43,7 +43,6 @@
#include "place.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "spells1.h"
#include "spells4.h"
#include "spl-cast.h"
@@ -51,6 +50,7 @@
#include "stuff.h"
#include "traps.h"
#include "view.h"
+#include "xom.h"
bool cast_selective_amnesia(bool force)
{
@@ -654,10 +654,17 @@ static bool teleport_player( bool allow_control, bool new_abyss_area )
void you_teleport_now( bool allow_control, bool new_abyss_area )
{
const bool randtele = teleport_player(allow_control, new_abyss_area);
+
// Xom is amused by uncontrolled teleports that land you in a
- // dangerous place.
- if (randtele && player_in_a_dangerous_place())
+ // dangerous place, unless the player is in the Abyss and
+ // teleported to escape from all the monsters chasing him/her,
+ // since in that case the new dangerous area is almost certainly
+ // *less* dangerous than the old dangerous area.
+ if (randtele && player_in_a_dangerous_place()
+ && you.level_type != LEVEL_ABYSS)
+ {
xom_is_stimulated(255);
+ }
}
bool entomb(int powc)
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 4fddf1ddf0..486c649878 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -44,7 +44,6 @@
#include "ouch.h"
#include "player.h"
#include "randart.h"
-#include "religion.h"
#include "skills.h"
#include "spells1.h"
#include "spells4.h"
@@ -1360,12 +1359,12 @@ static int distortion_monsters(int x, int y, int pow, int message)
if (you.skills[SK_TRANSLOCATIONS] < random2(8))
{
miscast_effect( SPTYP_TRANSLOCATION, pow / 9 + 1, pow, 100,
- "a distortion effect" );
+ "cast bend on self" );
}
else
{
miscast_effect( SPTYP_TRANSLOCATION, 1, 1, 100,
- "a distortion effect" );
+ "cast bend on self" );
}
return 1;
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 31377824bc..565e98e98d 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -55,6 +55,7 @@
#include "stuff.h"
#include "transfor.h"
#include "view.h"
+#include "xom.h"
#ifdef DOS
#include <conio.h>
diff --git a/crawl-ref/source/state.cc b/crawl-ref/source/state.cc
index 25e314eda6..21c25d8450 100644
--- a/crawl-ref/source/state.cc
+++ b/crawl-ref/source/state.cc
@@ -298,7 +298,7 @@ void game_state::inc_god_acting(god_type which_god, bool is_retribution)
}
god_act.which_god = which_god;
- god_act.retribution = is_retribution;
+ god_act.retribution = is_retribution || god_act.retribution;
god_act.depth++;
}
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 7921420285..478c53d5ad 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -777,6 +777,8 @@ static void tag_construct_you(struct tagHeader &th)
marshallByte(th,you.berserk_penalty);
marshallByte(th,you.level_type);
marshallString(th, you.level_type_name);
+ marshallByte(th,you.entry_cause);
+ marshallByte(th,you.entry_cause_god);
marshallByte(th,you.synch_time);
marshallByte(th,you.disease);
marshallByte(th,you.species);
@@ -1124,6 +1126,8 @@ static void tag_read_you(struct tagHeader &th, char minorVersion)
you.berserk_penalty = unmarshallByte(th);
you.level_type = static_cast<level_area_type>( unmarshallByte(th) );
you.level_type_name = unmarshallString(th);
+ you.entry_cause = static_cast<entry_cause_type>( unmarshallByte(th) );
+ you.entry_cause_god = static_cast<god_type>( unmarshallByte(th) );
you.synch_time = unmarshallByte(th);
you.disease = unmarshallByte(th);
you.species = static_cast<species_type>(unmarshallByte(th));
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 0fd7ced541..0fd01f982c 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -66,6 +66,7 @@
#include "terrain.h"
#include "travel.h"
#include "tutorial.h"
+#include "xom.h"
// These are hidden from the rest of the world... use the functions
// below to get information about the map grid.
@@ -1011,6 +1012,8 @@ void monster_grid(bool do_updates)
void fire_monster_alerts()
{
+ int num_hostile = 0;
+
for (int s = 0; s < MAX_MONSTERS; s++)
{
monsters *monster = &menv[s];
@@ -1037,6 +1040,9 @@ void fire_monster_alerts()
// Monster was viewed this turn
monster->flags |= MF_WAS_IN_VIEW;
+
+ if (mons_attitude(monster) == ATT_HOSTILE)
+ num_hostile++;
}
else
{
@@ -1051,6 +1057,21 @@ void fire_monster_alerts()
}
}
+ // Xom thinks it's hilarious the way the player picks up an ever
+ // growing entourage of monsters while running through the Abyss.
+ // To approximate this, if the number of hostile monsters in view
+ // is greater than it ever was for this particular trip to the
+ // Abyss, Xom is stimulated in proprotion to the number of
+ // hostile monsters. Thus if the entourage doesn't grow, then
+ // Xom becomes bored.
+ if (you.level_type == LEVEL_ABYSS
+ && you.attribute[ATTR_ABYSS_ENTOURAGE] < num_hostile)
+ {
+ you.attribute[ATTR_ABYSS_ENTOURAGE] = num_hostile;
+
+ xom_is_stimulated(16 * num_hostile);
+ }
+
monsters_seen_this_turn.clear();
}
diff --git a/crawl-ref/source/xom.cc b/crawl-ref/source/xom.cc
index ed8b244b5c..3c4cc6f6b7 100644
--- a/crawl-ref/source/xom.cc
+++ b/crawl-ref/source/xom.cc
@@ -21,6 +21,7 @@
#include "mutation.h"
#include "ouch.h"
#include "player.h"
+#include "randart.h"
#include "religion.h"
#include "spells3.h"
#include "spl-cast.h"
@@ -28,6 +29,18 @@
#include "state.h"
#include "stuff.h"
#include "view.h"
+#include "xom.h"
+
+#if DEBUG_RELIGION
+# define DEBUG_DIAGNOSTICS 1
+# define DEBUG_GIFTS 1
+#endif
+
+#if DEBUG_XOM
+# define DEBUG_DIAGNOSTICS 1
+# define DEBUG_RELIGION 1
+# define DEBUG_GIFTS 1
+#endif
// Which spell? First I copied all spells from you_spells(), then I
// filtered some out (especially conjurations). Then I sorted them in
@@ -110,9 +123,34 @@ bool xom_is_nice()
return (you.gift_timeout > 0 && you.piety > 100);
}
-void xom_is_stimulated(int maxinterestingness)
+static const char* xom_message_arrays[NUM_XOM_MESSAGE_TYPES][6] =
+{
+ // XM_NORMAL
+ {
+ "Xom roars with laughter!",
+ "Xom thinks this is hilarious!",
+ "Xom is highly amused!",
+ "Xom is amused.",
+ "Xom is mildly amused.",
+ "Xom is interested."
+ },
+
+ // XM_INTRIGUED
+ {
+ "Xom is fascinated!",
+ "Xom is very intrigued!",
+ "Xom is intrigued!",
+ "Xom is extremely interested.",
+ "Xom is very interested.",
+ "Xom is interested."
+ }
+};
+
+static void _xom_is_stimulated(int maxinterestingness,
+ const char* message_array[],
+ bool force_message)
{
- if (you.religion != GOD_XOM)
+ if (you.religion != GOD_XOM || maxinterestingness <= 0)
return;
// Xom is not stimulated by his own acts, at least not directly.
@@ -120,21 +158,49 @@ void xom_is_stimulated(int maxinterestingness)
return;
int interestingness = random2(maxinterestingness);
- if (interestingness < 12)
- return;
+
+#if DEBUG_RELIGION || DEBUG_GIFTS || DEBUG_XOM
+ mprf(MSGCH_DIAGNOSTICS,
+ "Xom: maxinterestingness = %d, interestingness = %d",
+ maxinterestingness, interestingness);
+#endif
+
if (interestingness > 255)
interestingness = 255;
- if (interestingness > you.gift_timeout)
+
+ bool was_stimulated = false;
+ if (interestingness > you.gift_timeout && interestingness >= 12)
{
you.gift_timeout = interestingness;
- god_speaks(GOD_XOM,
- ((interestingness > 200) ? "Xom roars with laughter!" :
- (interestingness > 100) ? "Xom thinks this is hilarious!" :
- (interestingness > 75) ? "Xom is highly amused!" :
- (interestingness > 50) ? "Xom is amused." :
- (interestingness > 25) ? "Xom is mildly amused." :
- "Xom is interested."));
+ was_stimulated = true;
}
+
+ if (was_stimulated || force_message)
+ god_speaks(GOD_XOM,
+ ((interestingness > 200) ? message_array[5] :
+ (interestingness > 100) ? message_array[4] :
+ (interestingness > 75) ? message_array[3] :
+ (interestingness > 50) ? message_array[2] :
+ (interestingness > 25) ? message_array[1] :
+ message_array[0]));
+}
+
+void xom_is_stimulated(int maxinterestingness, xom_message_type message_type,
+ bool force_message)
+{
+ _xom_is_stimulated(maxinterestingness, xom_message_arrays[message_type],
+ force_message);
+}
+
+void xom_is_stimulated(int maxinterestingness, std::string message,
+ bool force_message)
+{
+ const char* message_array[6];
+
+ for (int i = 0; i < 6; i++)
+ message_array[i] = message.c_str();
+
+ _xom_is_stimulated(maxinterestingness, message_array, force_message);
}
void xom_makes_you_cast_random_spell(int sever)
@@ -151,7 +217,7 @@ void xom_makes_you_cast_random_spell(int sever)
god_speaks(GOD_XOM, "Xom's power flows through you!");
-#if DEBUG_DIAGNOSTICS
+#if DEBUG_DIAGNOSTICS || DEBUG_RELIGION || DEBUG_XOM
mprf(MSGCH_DIAGNOSTICS,
"Xom_acts();spell: %d, spellenum: %d", spell, spellenum);
#endif
@@ -547,7 +613,7 @@ static bool xom_is_good(int sever)
(temp_rand == 0) ? "\"You need some minor adjustments, mortal!\"" :
(temp_rand == 1) ? "\"Let me alter your pitiful body.\"" :
(temp_rand == 2) ? "Xom's power touches on you for a moment."
- : "You hear Xom's maniacal chuckling.");
+ : "You hear Xom's maniacal cackling.");
mpr("Your body is suffused with distortional energy.");
set_hp(1 + random2(you.hp), false);
@@ -818,14 +884,37 @@ static bool xom_is_bad(int sever)
void xom_acts(bool niceness, int sever)
{
-#if DEBUG_DIAGNOSTICS
+#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);
#endif
+ entry_cause_type old_entry_cause = you.entry_cause;
+
if (sever < 1)
sever = 1;
-
+
+ // Nemelex's deck of punishment drawing the Xom card
+ if (crawl_state.is_god_acting()
+ && crawl_state.which_god_acting() != GOD_XOM)
+ {
+ god_type which_god = crawl_state.which_god_acting();
+
+ if (crawl_state.is_god_retribution())
+ {
+ niceness = false;
+ mprf(MSGCH_GOD, which_god,
+ "%s asks Xom for help in punishing you, and Xom happily "
+ "agrees.", god_name(which_god));
+ }
+ else
+ {
+ niceness = true;
+ mprf(MSGCH_GOD, which_god,
+ "%s calls in a favour from Xom.", god_name(which_god));
+ }
+ }
+
if (niceness)
{
// Good stuff.
@@ -838,7 +927,48 @@ void xom_acts(bool niceness, int sever)
while (!xom_is_bad(sever))
;
}
+
+ // Nemelex's deck of punishment drawing the Xom card
+ if (crawl_state.is_god_acting()
+ && crawl_state.which_god_acting() != GOD_XOM)
+ {
+ if (old_entry_cause != you.entry_cause
+ && you.entry_cause_god == GOD_XOM)
+ {
+ you.entry_cause_god = crawl_state.which_god_acting();
+ }
+ }
if (you.religion == GOD_XOM && coinflip())
you.piety = 200 - you.piety;
}
+
+void xom_check_lost_item(item_def& item)
+{
+ if (item.base_type == OBJ_ORBS)
+ xom_is_stimulated(255, "Xom laughs nastily.", true);
+ else if (is_fixed_artefact(item))
+ xom_is_stimulated(128, "Xom snickers.", true);
+ else if (is_rune(item))
+ {
+ if (is_unique_rune(item))
+ xom_is_stimulated(255, "Xom snickers loudly.", true);
+ else if (you.entry_cause == EC_SELF_EXPLICIT &&
+ !(item.flags & ISFLAG_DROPPED))
+ {
+ // Player voluntarily entered Pan or the Abyss looking
+ // for runes, yet never found it.
+ if (item.plus == RUNE_ABYSSAL)
+ {
+ // Ignore Abyss area shifts.
+ if (you.level_type != LEVEL_ABYSS)
+ // Abyssal runes are a lot more trouble to find
+ // than demonic runes, so it gets twice the
+ // stimulation.
+ xom_is_stimulated(128, "Xom snickers.", true);
+ }
+ else
+ xom_is_stimulated(64, "Xom snickers softly.", true);
+ }
+ }
+}
diff --git a/crawl-ref/source/xom.h b/crawl-ref/source/xom.h
new file mode 100644
index 0000000000..c68bafafbc
--- /dev/null
+++ b/crawl-ref/source/xom.h
@@ -0,0 +1,41 @@
+/*
+ * File: xom.h
+ * Summary: Misc Xom related functions.
+ * Written by: Linley Henzell
+ *
+ * Modified for Crawl Reference by $Author$ on $Date$
+ *
+ * Change History (most recent first):
+ *
+ * <1> 09/28/07 MPC Split from religion.h
+ */
+
+#ifndef XOM_H
+#define XOM_H
+
+class item_def;
+
+enum xom_message_type
+{
+ XM_NORMAL,
+ XM_INTRIGUED,
+ NUM_XOM_MESSAGE_TYPES
+};
+
+void xom_is_stimulated(int maxinterestingness,
+ xom_message_type message_type = XM_NORMAL,
+ bool force_message = false);
+void xom_is_stimulated(int maxinterestingness, std::string message,
+ bool force_message = false);
+bool xom_is_nice();
+void xom_acts(bool niceness, int sever);
+const char *describe_xom_favour();
+
+inline void xom_acts(int sever)
+{
+ xom_acts(xom_is_nice(), sever);
+}
+
+void xom_check_lost_item(item_def& item);
+
+#endif