summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-12-30 20:31:38 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-12-30 20:31:38 +0000
commite864f4d3b84c1efe09175652a9830dddbc0bd6a5 (patch)
tree7322d1cc0393f62adb256204a714cdcd976a2d62 /crawl-ref/source
parent7554b6525e58b192f168e50233479f3fb1d19f5e (diff)
downloadcrawl-ref-e864f4d3b84c1efe09175652a9830dddbc0bd6a5.tar.gz
crawl-ref-e864f4d3b84c1efe09175652a9830dddbc0bd6a5.zip
A completely reworked version of Zin as per the lengthy
discussion in October/November. Zin effects: - protection from harm (like all good gods) - feeding when starving (as before) - mutation resistance (chance of piety/200) Zin restrictions: - no cannibalism (like all good gods) - no attacking friends - no eating of intelligent beings' corpses - no deliberate mutating Zin invocations: - Smiting (general priestly ability?) - Revitalisation (Minor Healing + 5 mp) - Sanctuary (protection from attacks) git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3164 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/Kills.cc1
-rw-r--r--crawl-ref/source/abl-show.cc43
-rw-r--r--crawl-ref/source/acr.cc37
-rw-r--r--crawl-ref/source/beam.cc12
-rw-r--r--crawl-ref/source/delay.cc10
-rw-r--r--crawl-ref/source/describe.cc3
-rw-r--r--crawl-ref/source/direct.cc4
-rw-r--r--crawl-ref/source/effects.cc8
-rw-r--r--crawl-ref/source/enum.h17
-rw-r--r--crawl-ref/source/externs.h11
-rw-r--r--crawl-ref/source/fight.cc8
-rw-r--r--crawl-ref/source/files.cc5
-rw-r--r--crawl-ref/source/food.cc15
-rw-r--r--crawl-ref/source/it_use2.cc4
-rw-r--r--crawl-ref/source/makeitem.cc4
-rw-r--r--crawl-ref/source/misc.cc5
-rw-r--r--crawl-ref/source/mon-util.cc8
-rw-r--r--crawl-ref/source/monstuff.cc128
-rw-r--r--crawl-ref/source/mutation.cc70
-rw-r--r--crawl-ref/source/mutation.h5
-rw-r--r--crawl-ref/source/output.cc5
-rw-r--r--crawl-ref/source/religion.cc162
-rw-r--r--crawl-ref/source/spells1.cc9
-rw-r--r--crawl-ref/source/spells1.h1
-rw-r--r--crawl-ref/source/spells3.cc123
-rw-r--r--crawl-ref/source/spells3.h3
-rw-r--r--crawl-ref/source/spl-cast.cc3
-rw-r--r--crawl-ref/source/tags.cc10
-rw-r--r--crawl-ref/source/view.cc26
-rw-r--r--crawl-ref/source/view.h2
30 files changed, 614 insertions, 128 deletions
diff --git a/crawl-ref/source/Kills.cc b/crawl-ref/source/Kills.cc
index b3bad8d05f..02c3decb20 100644
--- a/crawl-ref/source/Kills.cc
+++ b/crawl-ref/source/Kills.cc
@@ -608,6 +608,7 @@ kill_monster_desc::kill_monster_desc(const monsters *mon)
case MONS_SPECTRAL_THING:
modifier = M_SPECTRE;
break;
+ default: break;
}
if (modifier != M_NORMAL) monnum = mon->number;
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 7ec8d6d746..21ee6f148b 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -110,8 +110,8 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] =
{ ABIL_NON_ABILITY, ABIL_NON_ABILITY, ABIL_NON_ABILITY,
ABIL_NON_ABILITY, ABIL_NON_ABILITY },
// Zin
- { ABIL_ZIN_REPEL_UNDEAD, ABIL_ZIN_HEALING, ABIL_ZIN_PESTILENCE,
- ABIL_ZIN_HOLY_WORD, ABIL_ZIN_SUMMON_GUARDIAN },
+ { ABIL_NON_ABILITY, ABIL_ZIN_SMITING, ABIL_ZIN_REVITALISATION,
+ ABIL_NON_ABILITY, ABIL_ZIN_SANCTUARY },
// TSO
{ ABIL_TSO_REPEL_UNDEAD, ABIL_TSO_SMITING, ABIL_TSO_ANNIHILATE_UNDEAD,
ABIL_TSO_CLEANSING_FLAME, ABIL_TSO_SUMMON_DAEVA },
@@ -232,11 +232,10 @@ static const ability_def Ability_List[] =
// INVOCATIONS:
// Zin
- { ABIL_ZIN_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE },
- { ABIL_ZIN_HEALING, "Minor Healing", 2, 0, 50, 1, ABFLAG_NONE },
- { ABIL_ZIN_PESTILENCE, "Pestilence", 3, 0, 100, 2, ABFLAG_NONE },
- { ABIL_ZIN_HOLY_WORD, "Holy Word", 6, 0, 150, 3, ABFLAG_NONE },
- { ABIL_ZIN_SUMMON_GUARDIAN, "Summon Guardian", 7, 0, 150, 4, ABFLAG_NONE },
+ { ABIL_ZIN_SMITING, "Smiting",
+ 3, 0, 50, generic_cost::fixed(2), ABFLAG_NONE },
+ { ABIL_ZIN_REVITALISATION, "Revitalisation", 0, 0, 100, 3, ABFLAG_NONE },
+ { ABIL_ZIN_SANCTUARY, "Sanctuary", 7, 0, 150, 10, ABFLAG_NONE },
// The Shining One
{ ABIL_TSO_REPEL_UNDEAD, "Repel Undead", 1, 0, 100, 0, ABFLAG_NONE },
@@ -637,7 +636,6 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 20 - (you.piety / 20) - (5 * you.skills[SK_INVOCATIONS]);
break;
- case ABIL_ZIN_REPEL_UNDEAD:
case ABIL_TSO_REPEL_UNDEAD:
case ABIL_KIKU_RECALL_UNDEAD_SLAVES:
case ABIL_BEOGH_RECALL_ORCISH_FOLLOWERS:
@@ -680,7 +678,7 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 40 - (you.piety / 20) - (3 * you.skills[SK_INVOCATIONS]);
break;
- case ABIL_ZIN_HEALING:
+ case ABIL_ZIN_SMITING:
case ABIL_TSO_SMITING:
case ABIL_BEOGH_SMITING:
case ABIL_MAKHLEB_MINOR_DESTRUCTION:
@@ -704,7 +702,7 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 50 - (you.piety / 20) - (you.skills[SK_INVOCATIONS] * 4);
break;
- case ABIL_ZIN_PESTILENCE:
+ case ABIL_ZIN_REVITALISATION:
case ABIL_TSO_ANNIHILATE_UNDEAD:
case ABIL_LUGONU_BANISH:
invoc = true;
@@ -717,7 +715,6 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 60 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
break;
- case ABIL_ZIN_HOLY_WORD:
case ABIL_TSO_CLEANSING_FLAME:
case ABIL_ELYVILON_RESTORATION:
case ABIL_YRED_CONTROL_UNDEAD:
@@ -728,7 +725,7 @@ static talent get_talent(ability_type ability, bool check_confused)
failure = 70 - (you.piety / 25) - (you.skills[SK_INVOCATIONS] * 4);
break;
- case ABIL_ZIN_SUMMON_GUARDIAN:
+ case ABIL_ZIN_SANCTUARY:
case ABIL_TSO_SUMMON_DAEVA:
case ABIL_KIKU_INVOKE_DEATH:
case ABIL_ELYVILON_GREATER_HEALING:
@@ -1314,7 +1311,6 @@ static bool do_ability(const ability_def& abil)
break;
// INVOCATIONS:
- case ABIL_ZIN_REPEL_UNDEAD:
case ABIL_TSO_REPEL_UNDEAD:
turn_undead(you.piety);
@@ -1330,13 +1326,8 @@ static bool do_ability(const ability_def& abil)
exercise(SK_INVOCATIONS, 1);
break;
- case ABIL_ZIN_HEALING:
- if (!cast_healing( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
- break;
-
- exercise(SK_INVOCATIONS, 1 + random2(3));
- break;
-
+// no longer in use, maybe keep for other cases (or remove!)
+/*
case ABIL_ZIN_PESTILENCE:
mpr( "You call forth a swarm of pestilential beasts!" );
@@ -1355,7 +1346,19 @@ static bool do_ability(const ability_def& abil)
summon_ice_beast_etc(you.skills[SK_INVOCATIONS] * 4, MONS_ANGEL, true);
exercise(SK_INVOCATIONS, 8 + random2(10));
break;
+*/
+
+ case ABIL_ZIN_REVITALISATION:
+ if (cast_revitalisation( 3 + (you.skills[SK_INVOCATIONS] / 6) ))
+ exercise(SK_INVOCATIONS, 1 + random2(3));
+ break;
+
+ case ABIL_ZIN_SANCTUARY:
+ if (cast_sanctuary(you.skills[SK_INVOCATIONS] * 4))
+ exercise(SK_INVOCATIONS, 5 + random2(8));
+ break;
+ case ABIL_ZIN_SMITING:
case ABIL_TSO_SMITING:
if (your_spells( SPELL_SMITING, (2 + skill_bump(SK_INVOCATIONS)) * 6,
false ) == SPRET_ABORT)
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 117f9bd7df..c0b18b5ee3 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -2749,6 +2749,16 @@ static void check_shafts()
}
}
+static void check_sanctuary()
+{
+ if (env.sanctuary_time <= 0)
+ return;
+
+ env.sanctuary_time--;
+ if (env.sanctuary_time == 0)
+ remove_sanctuary();
+}
+
static void world_reacts()
{
crawl_state.clear_god_acting();
@@ -2764,6 +2774,8 @@ static void world_reacts()
check_banished();
check_shafts();
+
+ check_sanctuary();
run_environment_effects();
@@ -3684,10 +3696,17 @@ static void move_player(int move_x, int move_y)
const unsigned short targ_monst = mgrd[ targ_x ][ targ_y ];
const bool targ_pass = you.can_pass_through(targ_x, targ_y);
+ // you can swap places with a friendly monster if you're not confused
+ // or if both of you are inside a sanctuary
+ const bool can_swap_places = targ_monst != NON_MONSTER
+ && (mons_friendly(&menv[targ_monst])
+ && !you.duration[DUR_CONF]
+ || is_sanctuary(you.x_pos, you.y_pos)
+ && is_sanctuary(targ_x, targ_y));
+
// cannot move away from mermaid but you CAN fight neighbouring squares
if (you.duration[DUR_BEHELD] && !you.duration[DUR_CONF]
- && (targ_monst == NON_MONSTER || mons_friendly(&menv[targ_monst])
- || mons_is_submerged(&menv[targ_monst])))
+ && (!can_swap_places || mons_is_submerged(&menv[targ_monst])))
{
for (unsigned int i = 0; i < you.beheld_by.size(); i++)
{
@@ -3722,8 +3741,7 @@ static void move_player(int move_x, int move_y)
{
struct monsters *mon = &menv[targ_monst];
- // you can swap places with a friendly monster if you're not confused
- if (mons_friendly( mon ) && !you.duration[DUR_CONF])
+ if (can_swap_places)
{
if (swap_places( mon ))
swap = true;
@@ -3732,6 +3750,17 @@ static void move_player(int move_x, int move_y)
}
else // attack!
{
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(mon->x, mon->y))
+ {
+ snprintf(info, INFO_SIZE,
+ "Really attack %s, despite your sanctuary? ",
+ mon->name(DESC_NOCAP_THE).c_str());
+
+ if (!yesno(info, true, 'n'))
+ return;
+ }
+
// XXX: Moving into a normal wall does nothing and uses no
// turns or energy, but moving into a wall which contains
// an invisible monster attacks the monster, thus allowing
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index bd6ffba766..fd38a1aa4c 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -3692,6 +3692,12 @@ static int affect_monster(bolt &beam, monsters *mon)
{
if (YOU_KILL( beam.thrower ))
{
+ if (is_sanctuary(mon->x, mon->y)
+ || is_sanctuary(you.x_pos, you.y_pos))
+ {
+ remove_sanctuary(true);
+ }
+
if (mons_friendly( mon ))
did_god_conduct( DID_ATTACK_FRIEND, 5, true, mon );
@@ -3855,6 +3861,12 @@ static int affect_monster(bolt &beam, monsters *mon)
beam.aux_source == "reading a scroll of immolation"
&& !beam.effect_known;
+ if (is_sanctuary(mon->x, mon->y)
+ || is_sanctuary(you.x_pos, you.y_pos))
+ {
+ remove_sanctuary(true);
+ }
+
if (mons_friendly(mon))
conduct.set( DID_ATTACK_FRIEND, 5, !okay, mon );
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index c05cf3057f..88d541f35a 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -637,7 +637,10 @@ static void finish_delay(const delay_queue_item &delay)
(you.has_usable_claws() || you.mutation[MUT_FANGS] == 3) ?
"ripping" : "chopping");
- if (is_good_god(you.religion) && is_player_same_species(item.plus))
+ if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)
+ simple_god_message(" demands a ceremonial burial for a corpse "
+ "like this!");
+ else if (is_good_god(you.religion) && is_player_same_species(item.plus))
simple_god_message(" expects more respect for your departed "
"relatives.");
@@ -1211,6 +1214,11 @@ bool interrupt_activity( activity_interrupt_type ai,
if (should_stop_activity(item, ai, at))
{
+ // no monster will attack you inside a sanctuary,
+ // so presence of monsters won't matter
+ if (is_sanctuary(you.x_pos, you.y_pos))
+ return (false);
+
monster_warning(ai, at, item.type);
stop_delay();
return (true);
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 7de3811582..c70ab8da21 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -1872,8 +1872,9 @@ static std::string describe_draconian_role(const monsters *mon)
return "It looks unnaturally strong and dangerous with its fists.";
case MONS_DRACONIAN_KNIGHT:
return "It wields a deadly weapon with menacing efficiency.";
+ default:
+ return ("");
}
- return ("");
}
static std::string describe_draconian_colour(int species)
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index b634c01bb7..0c5cdd769a 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -2035,6 +2035,10 @@ static void describe_cell(int mx, int my)
// removing warning
look_clouds:
#endif
+
+ if (is_sanctuary(mx, my))
+ mpr("This square lies inside a sanctuary.");
+
if (env.cgrid[mx][my] != EMPTY_CLOUD)
{
const int cloud_inspected = env.cgrid[mx][my];
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 0aa101bf09..c3a4d5f16b 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -2405,6 +2405,14 @@ void update_level( double elapsedTime )
#endif
update_corpses( elapsedTime );
+
+ if (env.sanctuary_time)
+ {
+ if (turns >= env.sanctuary_time)
+ remove_sanctuary();
+ else
+ env.sanctuary_time -= turns;
+ }
dungeon_events.fire_event(
dgn_event(DET_TURN_ELAPSED, coord_def(0, 0), turns * 10));
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 77e327e4eb..04596cff72 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -75,11 +75,9 @@ enum ability_type
ABIL_END_TRANSFORMATION, // 55
// Divine abilities
- ABIL_ZIN_REPEL_UNDEAD = 110, // 110
- ABIL_ZIN_HEALING,
- ABIL_ZIN_PESTILENCE,
- ABIL_ZIN_HOLY_WORD,
- ABIL_ZIN_SUMMON_GUARDIAN, // 114
+ ABIL_ZIN_SMITING = 110, // 110
+ ABIL_ZIN_REVITALISATION,
+ ABIL_ZIN_SANCTUARY,
ABIL_TSO_REPEL_UNDEAD = 120, // 120
ABIL_TSO_SMITING,
ABIL_TSO_ANNIHILATE_UNDEAD,
@@ -634,7 +632,9 @@ enum conduct_type
DID_DRINK_BLOOD,
DID_CANNIBALISM,
DID_EAT_MEAT, // unused
+ DID_EAT_SOULED_BEING, // Zin
DID_CREATED_LIFE, // unused
+ DID_DELIBERATE_MUTATING,
NUM_CONDUCTS
};
@@ -1001,6 +1001,13 @@ enum dungeon_feature_type
DNGN_START_OF_MONSTERS = 297 // don't go past here! see view.cc
};
+enum floor_property_type
+{
+ FPROP_NONE, // 0
+ FPROP_SANCTUARY_1,
+ FPROP_SANCTUARY_2
+};
+
enum duration_type
{
DUR_INVIS,
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f3d0959fe3..a0ad006bc9 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1253,9 +1253,10 @@ struct map_cell
short object; // The object: monster, item, feature, or cloud.
unsigned short flags; // Flags describing the mappedness of this square.
unsigned short colour;
+ unsigned short property;
- map_cell() : object(0), flags(0), colour(0) { }
- void clear() { flags = object = colour = 0; }
+ map_cell() : object(0), flags(0), colour(0), property(0) { }
+ void clear() { flags = object = colour = property = 0; }
unsigned glyph() const;
bool known() const;
@@ -1319,7 +1320,7 @@ public:
FixedArray< unsigned short, GXM, GYM > cgrid; // cloud grid
FixedArray< unsigned short, GXM, GYM > grid_colours; // colour overrides
- FixedArray< map_cell, GXM, GYM > map; // discovered terrain
+ FixedArray< map_cell, GXM, GYM > map; // discovered terrain
// Glyphs of squares that are in LOS.
env_show_grid show;
@@ -1348,6 +1349,10 @@ public:
// Flags for things like preventing teleport control; see
// level_flag_type in enum.h
unsigned long level_flags;
+
+ int sanctuary_x;
+ int sanctuary_y;
+ int sanctuary_time;
};
extern struct crawl_environment env;
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index df3bf61b6a..1019d862a0 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -3645,7 +3645,13 @@ bool you_attack(int monster_attacked, bool unarmed_attacks)
// check if the player is fighting with something unsuitable
wielded_weapon_check(attk.weapon);
- return attk.attack();
+ bool attack = attk.attack();
+ if (attack && (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(defender->x, defender->y)))
+ {
+ remove_sanctuary(true);
+ }
+ return attack;
}
// Lose attack energy for attacking with a weapon. The monster has already lost
diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc
index 442d166183..e02c1b9cea 100644
--- a/crawl-ref/source/files.cc
+++ b/crawl-ref/source/files.cc
@@ -977,6 +977,9 @@ bool load( dungeon_feature_type stair_taken, load_mode_type load_mode,
load_ghost();
}
env.turns_on_level = 0;
+ env.sanctuary_x = -1;
+ env.sanctuary_y = -1;
+ env.sanctuary_time = 0;
}
else
{
@@ -1148,7 +1151,7 @@ void save_level(int level_saved, level_area_type old_ltype,
where_were_you, old_ltype,
false );
- you.prev_targ = MHITNOT;
+ you.prev_targ = MHITNOT;
you.prev_grd_targ = coord_def(0, 0);
FILE *saveFile = fopen(cha_fil.c_str(), "wb");
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index 63866f3099..626517d118 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -55,7 +55,7 @@
#include "xom.h"
static int determine_chunk_effect(int which_chunk_type, bool rotten_chunk);
-static void eat_chunk( int chunk_effect, bool cannibal );
+static void eat_chunk( int chunk_effect, bool cannibal, int mon_intel = 0);
static void eating(unsigned char item_class, int item_type);
static void describe_food_change(int hunger_increment);
static bool food_change(bool suppress_message);
@@ -622,7 +622,6 @@ static bool food_change(bool suppress_message)
return (state_changed);
} // end food_change()
-
// food_increment is positive for eating, negative for hungering
static void describe_food_change(int food_increment)
{
@@ -694,13 +693,14 @@ void eat_from_inventory(int which_inventory_slot)
// handle this the same -- bwr
const int mons_type = you.inv[ which_inventory_slot ].plus;
const bool cannibal = is_player_same_species(mons_type);
+ const int intel = mons_intel(mons_type) - I_ANIMAL;
const int chunk_type = mons_corpse_effect( mons_type );
const bool rotten = (you.inv[which_inventory_slot].special < 100);
if (!prompt_eat_chunk(you.inv[which_inventory_slot], rotten))
return;
- eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal );
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal, intel );
}
else
{
@@ -742,11 +742,12 @@ void eat_floor_item(int item_link)
else if (mitm[item_link].sub_type == FOOD_CHUNK)
{
const int chunk_type = mons_corpse_effect( mitm[item_link].plus );
+ const int intel = mons_intel( mitm[item_link].plus ) - I_ANIMAL;
const bool cannibal = is_player_same_species( mitm[item_link].plus );
const bool rotten = (mitm[item_link].special < 100);
if (!prompt_eat_chunk(mitm[item_link], rotten))
return;
- eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal );
+ eat_chunk( determine_chunk_effect( chunk_type, rotten ), cannibal, intel );
}
else
{
@@ -879,7 +880,7 @@ static void say_chunk_flavour(bool likes_chunks)
// never called directly - chunk_effect values must pass
// through food::determine_chunk_effect() first {dlb}:
-static void eat_chunk( int chunk_effect, bool cannibal )
+static void eat_chunk( int chunk_effect, bool cannibal, int mon_intel )
{
bool likes_chunks = (you.omnivorous() ||
@@ -901,12 +902,14 @@ static void eat_chunk( int chunk_effect, bool cannibal )
case CE_MUTAGEN_RANDOM:
mpr("This meat tastes really weird.");
mutate(RANDOM_MUTATION);
+ did_god_conduct( DID_DELIBERATE_MUTATING, 10);
xom_is_stimulated(100);
break;
case CE_MUTAGEN_BAD:
mpr("This meat tastes *really* weird.");
give_bad_mutation();
+ did_god_conduct( DID_DELIBERATE_MUTATING, 10);
xom_is_stimulated(random2(200));
break;
@@ -963,6 +966,8 @@ static void eat_chunk( int chunk_effect, bool cannibal )
if (cannibal)
did_god_conduct( DID_CANNIBALISM, 10 );
+ else if (mon_intel > 0)
+ did_god_conduct( DID_EAT_SOULED_BEING, mon_intel);
if (do_eat)
{
diff --git a/crawl-ref/source/it_use2.cc b/crawl-ref/source/it_use2.cc
index e7a3a64bcc..5ee28cd004 100644
--- a/crawl-ref/source/it_use2.cc
+++ b/crawl-ref/source/it_use2.cc
@@ -302,7 +302,9 @@ bool potion_effect( potion_type pot_eff, int pow )
mpr("You feel extremely strange.");
for (int i = 0; i < 3; i++)
mutate(RANDOM_MUTATION, false);
- did_god_conduct(DID_STIMULANTS, 4 + random2(4));
+
+ did_god_conduct(DID_DELIBERATE_MUTATING, 10, was_known);
+ did_god_conduct(DID_STIMULANTS, 4 + random2(4), was_known);
break;
case POT_BLOOD:
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 729588e647..71d471dfee 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -3547,6 +3547,8 @@ static item_make_species_type give_weapon(monsters *mon, int level,
item.colour = RED; // forced by force_item above {dlb}
break;
}
+
+ default: break;
} // end "switch(mon->type)"
// Nagas don't get racial stuff.
@@ -3798,6 +3800,8 @@ void give_shield(monsters *mon, int level)
make_item_for_monster(mon, OBJ_ARMOUR, ARM_SHIELD,
level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
break;
+
+ default: break;
}
}
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index c2c19ddf8c..ae0c9b404e 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1586,6 +1586,11 @@ bool i_feel_safe(bool announce, bool want_move)
return (false);
}
}
+
+ // no monster will attack you inside a sanctuary,
+ // so presence of monsters won't matter
+ if (is_sanctuary(you.x_pos, you.y_pos))
+ return (true);
std::vector<const monsters *> mons;
/* monster check */
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 1eba1d7e4e..8caa6245f6 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -1622,6 +1622,7 @@ static std::string str_monam(const monsters& mon, description_level_type desc,
case MONS_WHITE_DRACONIAN: result += "white "; break;
case MONS_PALE_DRACONIAN: result += "pale "; break;
}
+ default:
break;
}
@@ -1637,6 +1638,7 @@ static std::string str_monam(const monsters& mon, description_level_type desc,
result += " skeleton"; break;
case MONS_SIMULACRUM_SMALL: case MONS_SIMULACRUM_LARGE:
result += " simulacrum"; break;
+ default: break;
}
// Vowel fix: Change 'a orc' to 'an orc'
@@ -4102,8 +4104,12 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet)
break;
case ENCH_FEAR:
+ snprintf( info, INFO_SIZE, " seems to regain %s courage.",
+ mons_pronoun(static_cast<monster_type>(this->type),
+ PRONOUN_NOCAP_POSSESSIVE));
+
if (!quiet)
- simple_monster_message(this, " seems to regain its courage.");
+ simple_monster_message(this, info);
// reevaluate behaviour
behaviour_event(this, ME_EVAL);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 7088423fde..b4f35b3405 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2254,6 +2254,22 @@ static void handle_movement(monsters *monster)
{
int dx, dy;
+ // monsters will try to flee out of a sanctuary
+ if (is_sanctuary(monster->x, monster->y) && !mons_friendly(monster)
+ && !mons_is_fleeing(monster)
+ && monster->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU)))
+ {
+ behaviour_event(monster, ME_SCARE, MHITNOT, monster->x, monster->y);
+ }
+ else if (mons_is_fleeing(monster) && env.sanctuary_x != -1
+ && !is_sanctuary(monster->x, monster->y)
+ && monster->target_x == env.sanctuary_x
+ && monster->target_y == env.sanctuary_y)
+ { // once outside there's a chance they'll regain their courage
+ if (random2(5) > 2)
+ monster->del_ench(ENCH_FEAR);
+ }
+
// some calculations
if (monster->type == MONS_BORING_BEETLE && monster->foe == MHITYOU)
{
@@ -2436,6 +2452,8 @@ static void handle_nearby_ability(monsters *monster)
if (monster->ghost->values[ GVAL_DEMONLORD_CYCLE_COLOUR ])
monster->colour = random_colour();
break;
+
+ default: break;
}
} // end handle_nearby_ability()
@@ -2467,14 +2485,27 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
{
case MONS_ORC_KNIGHT:
case MONS_ORC_WARLORD:
+ if (is_sanctuary(monster->x, monster->y))
+ break;
+
used = orc_battle_cry(monster);
break;
case MONS_ORANGE_STATUE:
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
used = orange_statue_effects(monster);
break;
case MONS_SILVER_STATUE:
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
used = silver_statue_effects(monster);
break;
@@ -2487,6 +2518,9 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
break;
}
+ if (is_sanctuary(monster->x, monster->y))
+ break;
+
for (int i = 0; i < MAX_MONSTERS; i++)
{
monsters *targ = &menv[i];
@@ -2525,6 +2559,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (!mons_player_visible( monster ))
break;
+
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
if (coinflip())
break;
@@ -2561,6 +2601,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (!mons_player_visible( monster ))
break;
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
+
if (coinflip())
break;
@@ -2596,6 +2642,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (monster->has_ench(ENCH_CONFUSION))
break;
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
+
if (one_chance_in(3))
used = plant_spit(monster, beem);
@@ -2614,6 +2666,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (monster->has_ench(ENCH_CONFUSION))
break;
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
+
// friendly fiends won't use torment, preferring hellfire
// (right now there is no way a monster can predict how
// badly they'll damage the player with torment) -- GDL
@@ -2677,6 +2735,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (monster->has_ench(ENCH_CONFUSION))
break;
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
+
if (!mons_near(monster))
break;
@@ -2731,6 +2795,12 @@ static bool handle_special_ability(monsters *monster, bolt & beem)
if (monster->has_ench(ENCH_CONFUSION))
break;
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ break;
+ }
+
if ((monster->type != MONS_HELL_HOUND && random2(13) < 3)
|| one_chance_in(10))
{
@@ -3695,6 +3765,11 @@ static bool handle_spell( monsters *monster, bolt & beem )
spell_cast = (one_chance_in(5) ? SPELL_NO_SPELL
: hspell_pass[5]);
}
+ else if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ return (false);
+ }
else
{
// Randomly picking one of the non-emergency spells:
@@ -3719,9 +3794,14 @@ static bool handle_spell( monsters *monster, bolt & beem )
{
// all direct-effect/summoning/self-enchantments/etc
spellOK = true;
-
- if (ms_direct_nasty(spell_cast)
- && mons_aligned(monster_index(monster), monster->foe))
+
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ spellOK = false;
+ }
+ else if (ms_direct_nasty(spell_cast)
+ && mons_aligned(monster_index(monster), monster->foe))
{
spellOK = false;
}
@@ -3747,7 +3827,15 @@ static bool handle_spell( monsters *monster, bolt & beem )
// if not okay, then maybe we'll cast a defensive spell
if (!spellOK)
- spell_cast = (coinflip() ? hspell_pass[2] : SPELL_NO_SPELL);
+ {
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(monster->x, monster->y))
+ {
+ spell_cast = SPELL_NO_SPELL;
+ }
+ else
+ spell_cast = (coinflip() ? hspell_pass[2] : SPELL_NO_SPELL);
+ }
if (spell_cast != SPELL_NO_SPELL)
break;
@@ -3759,7 +3847,9 @@ static bool handle_spell( monsters *monster, bolt & beem )
if (draco_breath != SPELL_NO_SPELL
&& (spell_cast == SPELL_NO_SPELL
|| (!is_emergency_spell(hspell_pass, spell_cast)
- && one_chance_in(4))))
+ && one_chance_in(4)))
+ && !is_sanctuary(you.x_pos, you.y_pos)
+ && !is_sanctuary(monster->x, monster->y))
{
spell_cast = draco_breath;
finalAnswer = true;
@@ -3918,12 +4008,18 @@ static bool handle_throw(monsters *monster, bolt & beem)
if (mon_item == NON_ITEM || !is_valid_item(mitm[mon_item]))
return (false);
+ if (is_sanctuary(monster->x, monster->y)
+ || is_sanctuary(beem.target_x, beem.target_y))
+ {
+ return (false);
+ }
+
// throwing a net at a target that is already caught would be
// completely useless, so bail out
if (mitm[mon_item].base_type == OBJ_MISSILES
&& mitm[mon_item].sub_type == MI_THROWING_NET
&& (beem.target_x == you.x_pos && beem.target_y == you.y_pos
- && you.caught()))
+ && you.caught()))
{
return (false);
}
@@ -4279,6 +4375,7 @@ static void handle_monster_move(int i, monsters *monster)
}
if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER
+ && !is_sanctuary(monster->x, monster->y)
&& (mmov_x != 0 || mmov_y != 0))
{
monsters_fight(
@@ -5101,6 +5198,21 @@ bool mon_can_move_to_pos(const monsters *monster, const int count_x,
// bounds check - don't consider moving out of grid!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
return false;
+
+ // hostile monsters won't enter sanctuaries
+ if (!mons_friendly(monster)
+ && is_sanctuary(targ_x, targ_y)
+ && !is_sanctuary(monster->x, monster->y))
+ {
+ return (false);
+ }
+ // inside a sanctuary don't attack anything!
+ if (is_sanctuary(monster->x, monster->y)
+ && (targ_x == you.x_pos && targ_y == you.y_pos
+ || mgrd[targ_x][targ_y] != NON_MONSTER))
+ {
+ return (false);
+ }
const dungeon_feature_type target_grid = grd[targ_x][targ_y];
const dungeon_feature_type habitat = monster_habitat( monster->type );
@@ -5358,7 +5470,6 @@ static bool monster_move(monsters *monster)
}
for (count_x = 0; count_x < 3; count_x++)
- {
for (count_y = 0; count_y < 3; count_y++)
{
const int targ_x = monster->x + count_x - 1;
@@ -5381,8 +5492,7 @@ static bool monster_move(monsters *monster)
const monsters* mons = dynamic_cast<const monsters*>(monster);
good_move[count_x][count_y] =
mon_can_move_to_pos(mons, count_x-1, count_y-1);
- }
- } // now we know where we _can_ move.
+ } // now we know where we _can_ move.
const coord_def newpos = monster->pos() + coord_def(mmov_x, mmov_y);
// normal/smart monsters know about secret doors (they _live_ in the
diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc
index dcec47cd8f..a970cb99e9 100644
--- a/crawl-ref/source/mutation.cc
+++ b/crawl-ref/source/mutation.cc
@@ -1393,6 +1393,35 @@ static int calc_mutation_amusement_value(mutation_type which_mutation)
return (amusement);
}
+static bool is_good_mutation( mutation_type which_mutation )
+{
+ switch (which_mutation)
+ {
+ case MUT_TOUGH_SKIN:
+ case MUT_STRONG:
+ case MUT_CLEVER:
+ case MUT_AGILE:
+ case MUT_POISON_RESISTANCE:
+ case MUT_TELEPORT_CONTROL:
+ case MUT_MAGIC_RESISTANCE:
+ case MUT_TELEPORT_AT_WILL:
+ case MUT_MAPPING:
+ case MUT_CLARITY:
+ case MUT_MUTATION_RESISTANCE:
+ case MUT_FAST:
+ case MUT_BLINK:
+ case MUT_BREATHE_FLAMES:
+ case MUT_SPIT_POISON:
+ case MUT_BREATHE_POISON:
+ case MUT_STINGER:
+ case MUT_FANGS:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
static bool accept_mutation( mutation_type mutat, bool ignore_rarity = false )
{
if ( you.mutation[mutat] >= mutation_defs[mutat].levels )
@@ -1497,23 +1526,18 @@ bool mutate(mutation_type which_mutation, bool failMsg, bool force_mutation,
return (false);
}
- if (wearing_amulet(AMU_RESIST_MUTATION)
- && !force_mutation && !one_chance_in(10))
- {
- if (failMsg)
- mpr("You feel odd for a moment.", MSGCH_MUTATION);
-
- return (false);
- }
-
- if (you.mutation[MUT_MUTATION_RESISTANCE]
- && !force_mutation
- && (you.mutation[MUT_MUTATION_RESISTANCE] == 3 || !one_chance_in(3)))
+ if (!force_mutation)
{
- if (failMsg)
- mpr("You feel odd for a moment.", MSGCH_MUTATION);
+ if (wearing_amulet(AMU_RESIST_MUTATION) && !one_chance_in(10)
+ || you.religion == GOD_ZIN && you.piety > random2(200)
+ || you.mutation[MUT_MUTATION_RESISTANCE] == 3
+ || you.mutation[MUT_MUTATION_RESISTANCE] && !one_chance_in(3))
+ {
+ if (failMsg)
+ mpr("You feel odd for a moment.", MSGCH_MUTATION);
- return (false);
+ return (false);
+ }
}
if (which_mutation == RANDOM_MUTATION
@@ -1952,7 +1976,18 @@ int how_mutated(void)
return (j);
} // end how_mutated()
-bool delete_mutation(mutation_type which_mutation, bool force)
+int count_mutations()
+{
+ int count = 0;
+
+ for (int i = 0; i < NUM_MUTATIONS; i++)
+ if (you.mutation[i] && you.demon_pow[i] < you.mutation[i])
+ count++;
+
+ return count;
+}
+
+bool delete_mutation(mutation_type which_mutation, bool force, bool good)
{
mutation_type mutat = which_mutation;
int i;
@@ -1979,7 +2014,8 @@ bool delete_mutation(mutation_type which_mutation, bool force)
&& (mutat != MUT_WEAK && mutat != MUT_DOPEY
&& mutat != MUT_CLUMSY))
|| random2(10) >= mutation_defs[mutat].rarity
- || you.demon_pow[mutat] >= you.mutation[mutat]);
+ || you.demon_pow[mutat] >= you.mutation[mutat]
+ || good && (!is_good_mutation(mutat) || one_chance_in(10)));
}
if (you.mutation[mutat] == 0)
diff --git a/crawl-ref/source/mutation.h b/crawl-ref/source/mutation.h
index 6f653e3c30..33497ce5b5 100644
--- a/crawl-ref/source/mutation.h
+++ b/crawl-ref/source/mutation.h
@@ -50,8 +50,11 @@ formatted_string describe_mutations();
/* ***********************************************************************
* called from: decks - it_use2 - mutation - spells
* *********************************************************************** */
-bool delete_mutation(mutation_type which_mutation, bool force = false);
+bool delete_mutation(mutation_type which_mutation, bool force = false,
+ bool good = false);
+// used by Zin (religion.cc)
+int count_mutations(void);
// last updated 12may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index 6f1831319f..2d3ce26638 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -1124,7 +1124,10 @@ void print_overview_screen()
const int rpois = player_res_poison(calc_unid);
const int relec = player_res_electricity(calc_unid);
const int rsust = player_sust_abil(calc_unid);
- const int rmuta = wearing_amulet(AMU_RESIST_MUTATION, calc_unid);
+ const int rmuta = wearing_amulet(AMU_RESIST_MUTATION, calc_unid)
+ || you.religion == GOD_ZIN && you.piety >= 180
+ || you.mutation[MUT_MUTATION_RESISTANCE] == 3;
+
const int rslow = wearing_amulet(AMU_RESIST_SLOW, calc_unid);
snprintf(buf, sizeof buf,
diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc
index 0f876d8cd5..6f9985f7ee 100644
--- a/crawl-ref/source/religion.cc
+++ b/crawl-ref/source/religion.cc
@@ -187,11 +187,11 @@ const char* god_gain_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
// no god
{ "", "", "", "", "" },
// Zin
- { "repel the undead",
- "call upon Zin for minor healing",
- "call down a plague",
- "utter a Holy Word",
- "summon a guardian angel" },
+ { "",
+ "smite your foes",
+ "call upon Zin for revitalisation",
+ "",
+ "call upon Zin to create a Sanctuary" },
// TSO
{ "repel the undead",
"smite your foes",
@@ -272,11 +272,11 @@ const char* god_lose_power_messages[NUM_GODS][MAX_GOD_ABILITIES] =
// no god
{ "", "", "", "", "" },
// Zin
- { "repel the undead",
- "call upon Zin for minor healing",
- "call down a plague",
- "utter a Holy Word",
- "summon a guardian angel" },
+ { "",
+ "smite your foes",
+ "call upon Zin for revitalisation",
+ "",
+ "call upon Zin to create a Sanctuary" },
// TSO
{ "repel the undead",
"smite your foes",
@@ -1549,6 +1549,28 @@ bool did_god_conduct( conduct_type thing_done, int level, bool known,
}
break;
+ case DID_DELIBERATE_MUTATING:
+ if (you.religion == GOD_ZIN)
+ {
+ if (!known)
+ {
+ simple_god_message(" did not appreciate that!");
+ break;
+ }
+ piety_change = -level;
+ ret = true;
+ }
+ break;
+
+ case DID_EAT_SOULED_BEING:
+ if (you.religion == GOD_ZIN)
+ {
+ piety_change = -level;
+ penance = level * 5;
+ ret = true;
+ }
+ break;
+
case DID_STIMULANTS: // unused
case DID_EAT_MEAT: // unused
case DID_CREATED_LIFE: // unused
@@ -1578,7 +1600,7 @@ bool did_god_conduct( conduct_type thing_done, int level, bool known,
"Servant Kill Natural Evil", "Servant Kill Angel",
"Spell Memorise", "Spell Cast", "Spell Practise", "Spell Nonutility",
"Cards", "Stimulants", "Drink Blood", "Cannibalism", "Eat Meat",
- "Create Life"
+ "Eat Souled Beings", "Create Life", "Deliberate Mutation"
};
ASSERT(ARRAYSIZE(conducts) == NUM_CONDUCTS);
@@ -1721,8 +1743,8 @@ void gain_piety(int pgn)
}
if ( you.piety > 160 && old_piety <= 160 &&
- (you.religion == GOD_SHINING_ONE || you.religion == GOD_ZIN ||
- you.religion == GOD_LUGONU) && you.num_gifts[you.religion] == 0 )
+ (you.religion == GOD_SHINING_ONE || you.religion == GOD_LUGONU)
+ && you.num_gifts[you.religion] == 0 )
simple_god_message( " will now bless your weapon at an altar...once.");
do_god_gift(false);
@@ -1948,8 +1970,8 @@ void lose_piety(int pgn)
if (!player_under_penance() && you.piety != old_piety)
{
if (you.piety <= 160 && old_piety > 160 &&
- (you.religion == GOD_SHINING_ONE || you.religion == GOD_ZIN ||
- you.religion == GOD_LUGONU) && you.num_gifts[you.religion] == 0)
+ (you.religion == GOD_SHINING_ONE || you.religion == GOD_LUGONU)
+ && you.num_gifts[you.religion] == 0)
simple_god_message(" is no longer ready to bless your weapon.");
for ( int i = 0; i < MAX_GOD_ABILITIES; ++i )
@@ -2027,33 +2049,70 @@ static bool zin_retribution()
if (!is_evil_god(you.religion))
return false;
- bool success = false;
+ int punishment = random2(8);
+
+ // if little mutated, do something else instead
+ if (punishment < 2 && count_mutations() <= random2(3))
+ punishment = random2(6)+2;
- if (random2(you.experience_level) > 7 && !one_chance_in(5))
+ switch(random2(8))
{
- const int how_many = 1 + (you.experience_level / 10) + random2(3);
-
- for (int i = 0; i < how_many; i++)
- if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE,
- you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ case 0: // remove good mutations (25%)
+ case 1:
+ {
+ simple_god_message(" draws some chaos from your body!", god);
+ bool success = false;
+ for (int i = 0; i < 7; i++)
+ if (random2(10) > i
+ && delete_mutation(RANDOM_MUTATION, true, true))
+ {
success = true;
-
- simple_god_message( success ?
- " sends the divine host to punish you "
- "for your evil ways!" :
- "'s divine host fails to appear.",
- god);
+ }
+
+ if (success && !count_mutations())
+ simple_god_message(" rids your body of chaos!");
+
+ break;
}
- else
- {
- // god_gift == false gives unfriendly
- success = summon_swarm( you.experience_level * 20, true, false );
- simple_god_message(success ?
- " sends a plague down upon you!" :
- "'s plague fails to arrive.",
- god);
+ case 2:
+ case 3:
+ case 4: // summon angels or bugs (pestilence), 3/8
+ if (random2(you.experience_level) > 7 && !one_chance_in(5))
+ {
+ const int how_many = 1 + (you.experience_level / 10) + random2(3);
+ bool success = false;
+
+ for (int i = 0; i < how_many; i++)
+ if (create_monster(MONS_ANGEL, 0, BEH_HOSTILE,
+ you.x_pos, you.y_pos, MHITYOU, 250) != -1)
+ success = true;
+
+ simple_god_message( success ?
+ " sends the divine host to punish you "
+ "for your evil ways!" :
+ "'s divine host fails to appear.",
+ god);
+ }
+ else
+ {
+ // god_gift == false gives unfriendly
+ bool success = summon_swarm( you.experience_level * 20, true, false );
+ simple_god_message(success ?
+ " sends a plague down upon you!" :
+ "'s plague fails to arrive.",
+ god);
+ }
+ break;
+ case 5:
+ case 6: // famine, 25%
+ simple_god_message(" sends a famine down upon you!", god);
+ make_hungry( you.hunger/2, false );
+ break;
+ case 7: // noisiness, 12.5%
+ simple_god_message(" booms out: \"Return to the light! REPENT!\"", god);
+ noisy( 25, you.x_pos, you.y_pos ); // same as scroll of noise
+ break;
}
-
return false;
}
@@ -2904,6 +2963,10 @@ void excommunication(void)
case GOD_ELYVILON: // never seeks revenge
break;
+ case GOD_ZIN:
+ if (env.sanctuary_time)
+ remove_sanctuary();
+ // deliberate fall-through
default:
inc_penance( old_god, 25 );
break;
@@ -2994,24 +3057,6 @@ void altar_prayer(void)
}
}
- // Zin blesses maces with disruption
- if (you.religion == GOD_ZIN
- && !you.num_gifts[GOD_ZIN]
- && !player_under_penance()
- && you.piety > 160)
- {
- const int wpn = get_player_wielded_weapon();
-
- if (wpn != -1
- && (you.inv[wpn].base_type == OBJ_WEAPONS
- && (you.inv[wpn].sub_type == WPN_MACE
- || you.inv[wpn].sub_type == WPN_GREAT_MACE))
- && get_weapon_brand( you.inv[wpn] ) != SPWPN_DISRUPTION)
- {
- bless_weapon( GOD_ZIN, SPWPN_DISRUPTION, WHITE );
- }
- }
-
// Lugonu blesses weapons with distortion
if (you.religion == GOD_LUGONU
&& !you.num_gifts[GOD_LUGONU]
@@ -3543,7 +3588,7 @@ void handle_god_time(void)
break;
}
- case GOD_ZIN: // These gods like long-standing worshippers
+ // These gods like long-standing worshippers
case GOD_ELYVILON:
if (need_free_piety() && one_chance_in(20))
gain_piety(1);
@@ -3554,6 +3599,11 @@ void handle_god_time(void)
gain_piety(1);
break;
+ case GOD_ZIN:
+ if (need_free_piety() && one_chance_in(12))
+ gain_piety(1);
+ break;
+
case GOD_YREDELEMNUL:
case GOD_KIKUBAAQUDGHA:
case GOD_VEHUMET:
diff --git a/crawl-ref/source/spells1.cc b/crawl-ref/source/spells1.cc
index 900514d471..f59185f960 100644
--- a/crawl-ref/source/spells1.cc
+++ b/crawl-ref/source/spells1.cc
@@ -653,6 +653,15 @@ int cast_healing( int pow )
return (healing_spell( pow + roll_dice( 2, pow ) - 2 ));
}
+int cast_revitalisation( int pow )
+{
+ // first increase MP by 5 or to maximum, whichever is lower
+ inc_mp(5, false);
+
+ // then cast healing (as in Minor Healing)
+ return cast_healing(pow);
+}
+
bool cast_revivification(int power)
{
int loopy = 0; // general purpose loop variable {dlb}
diff --git a/crawl-ref/source/spells1.h b/crawl-ref/source/spells1.h
index 5764bdef73..00881795be 100644
--- a/crawl-ref/source/spells1.h
+++ b/crawl-ref/source/spells1.h
@@ -52,6 +52,7 @@ char cast_lesser_healing(void);
* called from: ability - spell
* *********************************************************************** */
int cast_healing(int power);
+int cast_revitalisation(int power);
// last updated 24may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 08f9d4cffe..a930ba8652 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -43,7 +43,9 @@
#include "place.h"
#include "player.h"
#include "randart.h"
+#include "religion.h"
#include "spells1.h"
+#include "spells2.h" // holy word
#include "spells4.h"
#include "spl-cast.h"
#include "spl-util.h"
@@ -798,6 +800,127 @@ bool entomb(int powc)
return (number_built > 0);
} // end entomb()
+bool remove_sanctuary(bool did_attack)
+{
+ if (env.sanctuary_time)
+ env.sanctuary_time = 0;
+
+ if (env.sanctuary_x < 0 || env.sanctuary_y < 0)
+ return false;
+
+ const int radius = 5;
+ bool seen_change = false;
+ for (int x=-radius; x<=radius; x++)
+ for (int y=-radius; y<=radius; y++)
+ {
+ int posx = env.sanctuary_x + x;
+ int posy = env.sanctuary_y + y;
+
+ if (posx <= 0 || posx > GXM || posy <= 0 || posy > GYM)
+ continue;
+
+ if (is_sanctuary(posx, posy))
+ {
+ env.map[posx][posy].property = FPROP_NONE;
+ if (see_grid(coord_def(posx,posy)))
+ seen_change = true;
+ }
+ }
+
+// do not reset so as to allow monsters to see if their fleeing source
+// used to be the centre of a sanctuary
+// env.sanctuary_x = env.sanctuary_y = -1;
+
+ if (did_attack)
+ {
+ if (seen_change)
+ simple_god_message(" revokes the gift of sanctuary.", GOD_ZIN);
+ did_god_conduct(DID_FRIEND_DIES, 3);
+ }
+ else if (seen_change)
+ {
+ mpr("The air around you flickers and hums.");
+ if (is_resting())
+ stop_running();
+ }
+
+ return true;
+}
+
+bool cast_sanctuary(const int power)
+{
+ // first get rid of old sanctuary
+ remove_sanctuary();
+
+ if (!silenced(you.x_pos, you.y_pos))
+ mpr("You hear a choir sing!");
+ else
+ mpr("You are suddenly bathed in radiance!");
+
+ you.flash_colour = WHITE;
+ viewwindow( true, false );
+ holy_word( 100, true );
+ delay(1000);
+
+ env.sanctuary_x = you.x_pos;
+ env.sanctuary_y = you.y_pos;
+ env.sanctuary_time = 15;
+
+ const int radius = 5;
+ const int pattern = random2(4);
+ int count = 0;
+ int monster = -1;
+
+ for (int x=-radius; x<=radius; x++)
+ for (int y=-radius; y<=radius; y++)
+ {
+ int posx = you.x_pos + x;
+ int posy = you.y_pos + y;
+
+ if (posx <= 0 || posx > GXM || posy <= 0 || posy > GYM)
+ continue;
+
+ int dist = distance(posx, posy, you.x_pos, you.y_pos);
+ if (dist > radius*radius)
+ continue;
+
+ // scare all hostile monsters inside sanctuary
+ if (mgrd[posx][posy] != NON_MONSTER)
+ {
+ monster = mgrd[posx][posy];
+ monsters *mon = &menv[monster];
+
+ if (!mons_friendly(mon)
+ && mon->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU)))
+ {
+ behaviour_event(mon, ME_SCARE, MHITYOU);
+ count++;
+ }
+ }
+
+ // forming patterns
+ if (pattern == 0
+ && (x == 0 || y == 0 || x == y || x == -y)
+ || pattern == 1
+ && (dist >= (radius-1)*(radius-1) && dist <= radius*radius)
+ || pattern == 2
+ && (x%2 == 0 || y%2 == 0)
+ || pattern == 3
+ && (abs(x)+abs(y) < 5 && x != y && x != -y))
+ {
+ env.map[posx][posy].property = FPROP_SANCTUARY_1;
+ }
+ else
+ env.map[posx][posy].property = FPROP_SANCTUARY_2;
+ }
+ if (count == 1)
+ simple_monster_message(&menv[monster], " turns to flee the light!");
+ else if (count > 0)
+ mpr("The monsters scatter in all directions!");
+
+ return (true);
+}
+
void cast_poison_ammo(void)
{
const int ammo = you.equip[EQ_WEAPON];
diff --git a/crawl-ref/source/spells3.h b/crawl-ref/source/spells3.h
index f72d3fbf41..a5dfc30195 100644
--- a/crawl-ref/source/spells3.h
+++ b/crawl-ref/source/spells3.h
@@ -63,7 +63,8 @@ bool cast_selective_amnesia(bool force);
* called from: ability - spell
* *********************************************************************** */
int cast_smiting(int power, dist &);
-
+bool remove_sanctuary(bool did_attack = false);
+bool cast_sanctuary(int power);
// updated 24may2000 {dlb}
/* ***********************************************************************
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index bf739e56f0..6647de8ded 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -1595,6 +1595,9 @@ spret_type your_spells( spell_type spell, int powc, bool allow_fail )
break;
case SPELL_ALTER_SELF:
+ // trying is already enough, even if it fails
+ did_god_conduct(DID_DELIBERATE_MUTATING, 10);
+
crawl_state.cant_cmd_repeat("You can't repeat alter self.");
if (!enough_hp( you.hp_max / 2, true ))
{
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 1f5c9c6cca..656b2a640f 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1574,6 +1574,7 @@ static void tag_construct_level(tagHeader &th)
marshallShort(th, env.map[count_x][count_y].object);
marshallShort(th, env.map[count_x][count_y].colour);
marshallShort(th, env.map[count_x][count_y].flags);
+ marshallShort(th, env.map[count_x][count_y].property);
marshallShort(th, env.cgrid[count_x][count_y]);
}
}
@@ -1608,6 +1609,10 @@ static void tag_construct_level(tagHeader &th)
marshallByte(th, env.shop[i].level);
}
+ marshallByte(th, env.sanctuary_x);
+ marshallByte(th, env.sanctuary_y);
+ marshallByte(th, env.sanctuary_time);
+
env.markers.write(th);
}
@@ -1806,6 +1811,7 @@ static void tag_read_level( tagHeader &th, char minorVersion )
env.map[i][j].object = unmarshallShort(th);
env.map[i][j].colour = unmarshallShort(th);
env.map[i][j].flags = unmarshallShort(th);
+ env.map[i][j].property = unmarshallShort(th);
mgrd[i][j] = NON_MONSTER;
env.cgrid[i][j] = (unsigned short) unmarshallShort(th);
@@ -1844,6 +1850,10 @@ static void tag_read_level( tagHeader &th, char minorVersion )
env.shop[i].level = unmarshallByte(th);
}
+ env.sanctuary_x = unmarshallByte(th);
+ env.sanctuary_y = unmarshallByte(th);
+ env.sanctuary_time = unmarshallByte(th);
+
env.markers.read(th);
}
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index ef9a12b817..dff80df984 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -182,6 +182,16 @@ void set_envmap_col( int x, int y, int colour )
env.map[x][y].colour = colour;
}
+void set_envmap_prop( int x, int y, int prop )
+{
+ env.map[x][y].property = prop;
+}
+
+bool is_sanctuary( int x, int y)
+{
+ return (env.map[x][y].property != FPROP_NONE);
+}
+
bool is_envmap_item(int x, int y)
{
return (get_viewobj_flags(env.map[x][y].object) & MC_ITEM);
@@ -350,6 +360,22 @@ static void get_symbol( int x, int y,
{
const int colmask = *colour & COLFLAG_MASK;
+ if (object < NUM_REAL_FEATURES
+ && is_sanctuary(x,y) && object >= DNGN_MINMOVE)
+ {
+ if (env.map[x][y].property == FPROP_SANCTUARY_1)
+ *colour = YELLOW | colmask;
+ else if (env.map[x][y].property == FPROP_SANCTUARY_2)
+ {
+ if (!one_chance_in(3))
+ *colour = WHITE | colmask;
+ else if (one_chance_in(3))
+ *colour = LIGHTCYAN | colmask;
+ else
+ *colour = LIGHTGRAY | colmask;
+ }
+ }
+ else
if (object < NUM_REAL_FEATURES && env.grid_colours[x][y])
{
*colour = env.grid_colours[x][y] | colmask;
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 5eae770a41..6122d7e1ac 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -162,6 +162,8 @@ void set_envmap_detected_item(int x, int y, bool detected = true);
void set_envmap_detected_mons(int x, int y, bool detected = true);
void set_envmap_col( int x, int y, int colour, int flags );
void set_envmap_col( int x, int y, int colour );
+void set_envmap_prop( int x, int y, int prop );
+bool is_sanctuary( int x, int y );
bool is_envmap_detected_item(int x, int y);
bool is_envmap_detected_mons(int x, int y);