From e864f4d3b84c1efe09175652a9830dddbc0bd6a5 Mon Sep 17 00:00:00 2001 From: j-p-e-g Date: Sun, 30 Dec 2007 20:31:38 +0000 Subject: 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 --- crawl-ref/source/Kills.cc | 1 + crawl-ref/source/abl-show.cc | 43 ++++++------ crawl-ref/source/acr.cc | 37 ++++++++-- crawl-ref/source/beam.cc | 12 ++++ crawl-ref/source/delay.cc | 10 ++- crawl-ref/source/describe.cc | 3 +- crawl-ref/source/direct.cc | 4 ++ crawl-ref/source/effects.cc | 8 +++ crawl-ref/source/enum.h | 17 +++-- crawl-ref/source/externs.h | 11 ++- crawl-ref/source/fight.cc | 8 ++- crawl-ref/source/files.cc | 5 +- crawl-ref/source/food.cc | 15 ++-- crawl-ref/source/it_use2.cc | 4 +- crawl-ref/source/makeitem.cc | 4 ++ crawl-ref/source/misc.cc | 5 ++ crawl-ref/source/mon-util.cc | 8 ++- crawl-ref/source/monstuff.cc | 128 +++++++++++++++++++++++++++++++--- crawl-ref/source/mutation.cc | 70 ++++++++++++++----- crawl-ref/source/mutation.h | 5 +- crawl-ref/source/output.cc | 5 +- crawl-ref/source/religion.cc | 162 ++++++++++++++++++++++++++++--------------- crawl-ref/source/spells1.cc | 9 +++ crawl-ref/source/spells1.h | 1 + crawl-ref/source/spells3.cc | 123 ++++++++++++++++++++++++++++++++ crawl-ref/source/spells3.h | 3 +- crawl-ref/source/spl-cast.cc | 3 + crawl-ref/source/tags.cc | 10 +++ crawl-ref/source/view.cc | 26 +++++++ crawl-ref/source/view.h | 2 + 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 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(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(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); -- cgit v1.2.3-54-g00ecf