summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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