From 78a45dd9099c4340a9aec9d634d3ef91bab181ac Mon Sep 17 00:00:00 2001 From: haranp Date: Mon, 16 Feb 2009 13:14:09 +0000 Subject: Fix [2004960]: clean up sanctuary logic. Monsters will now stop fleeing and attack you if you step outside of sanctuary; also, they can acquire and chase new targets while still respecting sanctuary. Hopefully non-buggy. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9100 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/enum.h | 3 +- crawl-ref/source/mon-util.cc | 29 +++++++++++++ crawl-ref/source/mon-util.h | 6 ++- crawl-ref/source/monstuff.cc | 63 ++++++++++++++-------------- crawl-ref/source/monstuff.h | 10 +---- crawl-ref/source/spells3.cc | 98 +++++++++++++++++++++++--------------------- 6 files changed, 122 insertions(+), 87 deletions(-) (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index aedfa39668..9c298c19e4 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -2109,7 +2109,8 @@ enum monster_flag_type MF_NAME_REPLACE = 0x30000, // mname entirely replaces normal monster // name. MF_NAME_MASK = 0x30000, - MF_GOD_GIFT = 0x40000 // Is a god gift. + MF_GOD_GIFT = 0x40000, // Is a god gift. + MF_FLEEING_FROM_SANCTUARY = 0x80000 // Is running away from player sanctuary }; // Adding slots breaks saves. YHBW. diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 2c1fac0b54..9ebfc2737a 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2651,6 +2651,20 @@ bool mons_is_lurking(const monsters *m) return (m->behaviour == BEH_LURK); } +bool mons_is_influenced_by_sanctuary(const monsters *m) +{ + return (!mons_wont_attack(m) + && mons_holiness(m) != MH_PLANT + && !mons_is_stationary(m)); +} + +bool mons_is_fleeing_sanctuary(const monsters *m) +{ + return (mons_is_influenced_by_sanctuary(m) + && inside_level_bounds(env.sanctuary_pos) + && (m->flags & MF_FLEEING_FROM_SANCTUARY)); +} + bool mons_is_batty(const monsters *m) { return mons_class_flag(m->type, M_BATTY); @@ -2684,6 +2698,21 @@ bool mons_looks_distracted(const monsters *m) && uat != UCAT_SLEEPING); } +void mons_start_fleeing_from_sanctuary(monsters *monster) +{ + monster->flags |= MF_FLEEING_FROM_SANCTUARY; + monster->target = env.sanctuary_pos; + behaviour_event(monster, ME_SCARE, MHITNOT, env.sanctuary_pos); +} + +void mons_stop_fleeing_from_sanctuary(monsters *monster) +{ + const bool had_flag = (monster->flags & MF_FLEEING_FROM_SANCTUARY); + monster->flags &= (~MF_FLEEING_FROM_SANCTUARY); + if (had_flag) + behaviour_event(monster, ME_EVAL, MHITYOU); +} + void mons_pacify(monsters *mon) { // Make the monster permanently neutral. diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 1cbf54ed89..ab343e73df 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -161,7 +161,6 @@ enum mon_event_type ME_ANNOY, // annoy at range ME_ALERT, // alert to presence ME_WHACK, // physical attack - ME_SHOT, // attack at range ME_SCARE, // frighten monster ME_CORNERED // cannot flee }; @@ -767,6 +766,8 @@ bool mons_is_panicking(const monsters *m); bool mons_is_cornered(const monsters *m); bool mons_is_lurking(const monsters *m); bool mons_is_batty(const monsters *m); +bool mons_is_influenced_by_sanctuary(const monsters *m); +bool mons_is_fleeing_sanctuary(const monsters *m); bool mons_was_seen(const monsters *m); bool mons_is_known_mimic(const monsters *m); bool mons_is_holy(const monsters *mon); @@ -783,6 +784,9 @@ monster_type mons_species(int mc); bool mons_looks_stabbable(const monsters *m); bool mons_looks_distracted(const monsters *m); +void mons_start_fleeing_from_sanctuary(monsters *monster); +void mons_stop_fleeing_from_sanctuary(monsters *monster); + bool mons_has_smite_attack(const monsters *monster); bool check_mons_resist_magic(const monsters *monster, int pow); diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 66fafc2233..fb1be02ae6 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -1827,7 +1827,7 @@ void alert_nearby_monsters(void) // alert monsters that aren't sleeping. For cases where an // event should wake up monsters and alert them, I'd suggest // calling noisy() before calling this function. -- bwr - if (monster->type != -1 + if (monster->alive() && mons_near(monster) && !mons_is_sleeping(monster)) { @@ -2490,14 +2490,14 @@ static bool _wounded_damaged(int monster_type) // 2. Call handle_behaviour to re-evaluate AI state and target x,y // //--------------------------------------------------------------- -void behaviour_event(monsters *mon, int event, int src, +void behaviour_event(monsters *mon, mon_event_type event, int src, coord_def src_pos) { ASSERT(src >= 0 && src <= MHITYOU); ASSERT(!crawl_state.arena || src != MHITYOU); ASSERT(in_bounds(src_pos) || src_pos.origin()); - beh_type old_behaviour = mon->behaviour; + const beh_type old_behaviour = mon->behaviour; bool isSmart = (mons_intel(mon) > I_ANIMAL); bool wontAttack = mons_wont_attack_real(mon); @@ -2510,6 +2510,14 @@ void behaviour_event(monsters *mon, int event, int src, else if (src != MHITNOT) sourceWontAttack = mons_wont_attack_real( &menv[src] ); + if (is_sanctuary(mon->pos()) && mons_is_fleeing_sanctuary(mon)) + { + mon->behaviour = BEH_FLEE; + mon->foe = MHITYOU; + mon->target = env.sanctuary_pos; + return; + } + switch (event) { case ME_DISTURB: @@ -2566,8 +2574,8 @@ void behaviour_event(monsters *mon, int event, int src, } } - // Now set target x, y so that monster can whack - // back (once) at an invisible foe. + // Now set target so that monster can whack back (once) at an + // invisible foe. if (event == ME_WHACK) setTarget = true; break; @@ -2614,25 +2622,20 @@ void behaviour_event(monsters *mon, int event, int src, break; case ME_SCARE: - { - const bool flee_sanct = !mons_wont_attack(mon) - && is_sanctuary(mon->pos()); - - // Stationary monsters can't flee, even from sanctuary. + // Stationary monsters can't flee. if (mons_is_stationary(mon)) { mon->del_ench(ENCH_FEAR, true, true); break; } - // Berserking monsters don't flee, unless it's from sanctuary. - if (mon->has_ench(ENCH_BERSERK) && !flee_sanct) + // Berserking monsters don't flee. + if (mon->has_ench(ENCH_BERSERK)) break; - // Neither do plants or nonliving beings, and sanctuary doesn't - // affect plants. + // Neither do plants or nonliving beings. if (mons_class_holiness(mon->type) == MH_PLANT - || (mons_class_holiness(mon->type) == MH_NONLIVING && !flee_sanct)) + || mons_class_holiness(mon->type) == MH_NONLIVING) { mon->del_ench(ENCH_FEAR, true, true); break; @@ -2646,17 +2649,12 @@ void behaviour_event(monsters *mon, int event, int src, if (see_grid(mon->pos())) learned_something_new(TUT_FLEEING_MONSTER); break; - } case ME_CORNERED: // Some monsters can't flee. if (mon->behaviour != BEH_FLEE && !mon->has_ench(ENCH_FEAR)) break; - // Don't stop fleeing from sanctuary. - if (!mons_wont_attack(mon) && is_sanctuary(mon->pos())) - break; - // Pacified monsters shouldn't change their behaviour. if (mons_is_pacified(mon)) break; @@ -2669,7 +2667,6 @@ void behaviour_event(monsters *mon, int event, int src, break; case ME_EVAL: - default: break; } @@ -3797,6 +3794,13 @@ static void _handle_behaviour(monsters *mon) return; } + if (mons_is_fleeing_sanctuary(mon) + && mons_is_fleeing(mon) + && is_sanctuary(you.pos())) + { + return; + } + if (crawl_state.arena) { if (Options.arena_force_ai) @@ -4564,15 +4568,14 @@ static void _handle_movement(monsters *monster) _maybe_set_patrol_route(monster); // Monsters will try to flee out of a sanctuary. - if (is_sanctuary(monster->pos()) && !mons_friendly(monster) - && !mons_is_fleeing(monster) - && monster->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU))) + if (is_sanctuary(monster->pos()) + && mons_is_influenced_by_sanctuary(monster) + && !mons_is_fleeing_sanctuary(monster)) { - behaviour_event(monster, ME_SCARE, MHITNOT, monster->pos()); + mons_start_fleeing_from_sanctuary(monster); } - else if (mons_is_fleeing(monster) && inside_level_bounds(env.sanctuary_pos) - && !is_sanctuary(monster->pos()) - && monster->target == env.sanctuary_pos) + else if (mons_is_fleeing_sanctuary(monster) + && !is_sanctuary(monster->pos())) { // Once outside there's a chance they'll regain their courage. // Nonliving and berserking monsters always stop immediately, @@ -4580,9 +4583,9 @@ static void _handle_movement(monsters *monster) // scared. if (monster->holiness() == MH_NONLIVING || monster->has_ench(ENCH_BERSERK) - || random2(5) > 2) + || x_chance_in_y(2, 5)) { - monster->del_ench(ENCH_FEAR); + mons_stop_fleeing_from_sanctuary(monster); } } diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h index 36561e82a4..128b9d1f02 100644 --- a/crawl-ref/source/monstuff.h +++ b/crawl-ref/source/monstuff.h @@ -105,15 +105,9 @@ void mons_check_pool(monsters *monster, const coord_def &oldpos, void monster_cleanup(monsters *monster); -/* *********************************************************************** - * called from: monstuff beam effects fight view - * *********************************************************************** */ -void behaviour_event(monsters *mon, int event_type, int src = MHITNOT, - coord_def src_pos = coord_def() ); +void behaviour_event(monsters *mon, mon_event_type event_type, + int src = MHITNOT, coord_def src_pos = coord_def()); -/* *********************************************************************** - * called from: fight - it_use3 - spells - * *********************************************************************** */ bool curse_an_item(bool decay_potions, bool quiet = false); diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index 9d63b3ca96..7bbe991901 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -1534,7 +1534,7 @@ static int _inside_circle(const coord_def& where, int radius) return (dist); } -static void _remove_sanctuary_property(coord_def where) +static void _remove_sanctuary_property(const coord_def& where) { env.map(where).property &= ~(FPROP_SANCTUARY_1 | FPROP_SANCTUARY_2); } @@ -1559,9 +1559,7 @@ bool remove_sanctuary(bool did_attack) } } -// Do not reset so as to allow monsters to see if their fleeing source -// used to be the centre of a sanctuary. (jpeg) -// env.sanctuary_pos.x = env.sanctuary_pos.y = -1; + env.sanctuary_pos.set(-1, -1); if (did_attack) { @@ -1570,6 +1568,15 @@ bool remove_sanctuary(bool did_attack) did_god_conduct(DID_FRIEND_DIED, 3); } + // Now that the sanctuary is gone, monsters aren't afraid of it + // anymore. + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters *mon = &menv[i]; + if (mon->alive()) + mons_stop_fleeing_from_sanctuary(mon); + } + if (is_resting()) stop_running(); @@ -1579,7 +1586,7 @@ bool remove_sanctuary(bool did_attack) // For the last (radius) counter turns the sanctuary will slowly shrink. void decrease_sanctuary_radius() { - int radius = 5; + const int radius = 5; // For the last (radius-1) turns 33% chance of not decreasing. if (env.sanctuary_time < radius && one_chance_in(3)) @@ -1595,30 +1602,20 @@ void decrease_sanctuary_radius() stop_running(); } - radius = size+1; - for (int x = -radius; x <= radius; x++) - for (int y = -radius; y <= radius; y++) - { - int posx = env.sanctuary_pos.x + x; - int posy = env.sanctuary_pos.y + y; - - if (!inside_level_bounds(posx,posy)) - continue; - - int dist = distance(posx, posy, env.sanctuary_pos.x, - env.sanctuary_pos.y); + for (radius_iterator ri(env.sanctuary_pos, size+1, true, false); ri; ++ri) + { + int dist = distance(*ri, env.sanctuary_pos); - // If necessary overwrite sanctuary property. - if (dist > size*size) - _remove_sanctuary_property(coord_def(posx, posy)); - } + // If necessary overwrite sanctuary property. + if (dist > size*size) + _remove_sanctuary_property(*ri); + } // Special case for time-out of sanctuary. if (!size) { - _remove_sanctuary_property(coord_def(env.sanctuary_pos.x, - env.sanctuary_pos.y)); - if (see_grid(coord_def(env.sanctuary_pos.x,env.sanctuary_pos.y))) + _remove_sanctuary_property(env.sanctuary_pos); + if (see_grid(env.sanctuary_pos)) mpr("The sanctuary disappears.", MSGCH_DURATION); } } @@ -1653,16 +1650,15 @@ bool cast_sanctuary(const int power) // radius could also be influenced by Inv // and would then have to be stored globally. const int radius = 5; - const int pattern = random2(4); int blood_count = 0; int trap_count = 0; int scare_count = 0; int cloud_count = 0; monsters *seen_mon = NULL; - for ( radius_iterator ri(you.pos(), radius, false, false); ri; ++ri ) + for (radius_iterator ri(you.pos(), radius, false, false); ri; ++ri) { - int dist = _inside_circle(*ri, radius); + const int dist = _inside_circle(*ri, radius); if (dist == -1) continue; @@ -1682,25 +1678,34 @@ bool cast_sanctuary(const int power) // forming patterns const int x = pos.x - you.pos().x, y = pos.y - you.pos().y; - if (pattern == 0 // outward rays - && (x == 0 || y == 0 || x == y || x == -y) - || pattern == 1 // circles - && (dist >= (radius-1)*(radius-1) && dist <= radius*radius - || dist >= (radius/2-1)*(radius/2-1) - && dist <= radius*radius/4) - || pattern == 2 // latticed - && (x%2 == 0 || y%2 == 0) - || pattern == 3 // cross-like - && (abs(x)+abs(y) < 5 && x != y && x != -y)) + bool in_yellow = false; + switch (random2(4)) { - env.map(pos).property |= FPROP_SANCTUARY_1; // yellow + case 0: // outward rays + in_yellow = (x == 0 || y == 0 || x == y || x == -y); + break; + case 1: // circles + in_yellow = (dist >= (radius-1)*(radius-1) + && dist <= radius*radius + || dist >= (radius/2-1)*(radius/2-1) + && dist <= radius*radius/4); + break; + case 2: // latticed + in_yellow = (x%2 == 0 || y%2 == 0); + break; + case 3: // cross-like + in_yellow = (abs(x)+abs(y) < 5 && x != y && x != -y); + break; + default: + break; } - else - env.map(pos).property |= FPROP_SANCTUARY_2; // white + + env.map(pos).property |= (in_yellow ? FPROP_SANCTUARY_1 + : FPROP_SANCTUARY_2); env.map(pos).property &= ~(FPROP_BLOODY); - // scare all attacking monsters inside sanctuary, and make + // Scare all attacking monsters inside sanctuary, and make // all friendly monsters inside sanctuary stop attacking and // move towards the player. if (monsters* mon = monster_at(pos)) @@ -1717,18 +1722,17 @@ bool cast_sanctuary(const int power) if (mons_is_mimic(mon->type)) { mimic_alert(mon); - if(you.can_see(mon)) + if (you.can_see(mon)) { scare_count++; seen_mon = mon; } } - else if (mon->add_ench(mon_enchant(ENCH_FEAR, 0, KC_YOU))) + else if (mons_is_influenced_by_sanctuary(mon)) { - behaviour_event(mon, ME_SCARE, MHITYOU); + mons_start_fleeing_from_sanctuary(mon); - // Check to see that monster is actually fleeing, - // since plants can't flee. + // Check to see that monster is actually fleeing. if (mons_is_fleeing(mon) && you.can_see(mon)) { scare_count++; @@ -1736,7 +1740,7 @@ bool cast_sanctuary(const int power) } } } - } // if (monster != NON_MONSTER) + } if (!is_harmless_cloud(cloud_type_at(pos))) { -- cgit v1.2.3-54-g00ecf