diff options
Diffstat (limited to 'crawl-ref/source/monstuff.cc')
-rw-r--r-- | crawl-ref/source/monstuff.cc | 313 |
1 files changed, 195 insertions, 118 deletions
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 5d782c3120..ab4a48d441 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -732,7 +732,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) if (mons_is_caught(monster)) mons_clear_trapping_net(monster); - // update list of monsters beholding player + // Update list of monsters beholding player. update_beholders(monster, true); const int monster_killed = monster_index(monster); @@ -1029,7 +1029,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent) MDAM_DEAD); } - // no piety loss if god gifts killed by other monsters + // No piety loss if god gifts killed by other monsters. if (mons_friendly(monster) && !testbits(monster->flags,MF_GOD_GIFT)) { did_god_conduct(DID_FRIEND_DIED, 1 + (monster->hit_dice / 2), @@ -1319,7 +1319,7 @@ void monster_cleanup(monsters *monster) if (you.pet_target == monster_killed) you.pet_target = MHITNOT; -} // end monster_cleanup() +} static bool _jelly_divide(monsters * parent) { @@ -1330,10 +1330,10 @@ static bool _jelly_divide(monsters * parent) if (!mons_class_flag( parent->type, M_SPLITS ) || parent->hit_points == 1) return (false); - // first, find a suitable spot for the child {dlb}: + // First, find a suitable spot for the child {dlb}: for (jex = -1; jex < 3; jex++) { - // loop moves beyond those tiles contiguous to parent {dlb}: + // Loop moves beyond those tiles contiguous to parent {dlb}: if (jex > 1) return (false); @@ -1351,7 +1351,7 @@ static bool _jelly_divide(monsters * parent) if (foundSpot) break; - } // end of for jex + } // end of for jex int k = 0; // must remain outside loop that follows {dlb} @@ -1366,7 +1366,7 @@ static bool _jelly_divide(monsters * parent) return (false); } - // handle impact of split on parent {dlb}: + // Handle impact of split on parent {dlb}: parent->max_hit_points /= 2; if (parent->hit_points > parent->max_hit_points) @@ -1375,11 +1375,11 @@ static bool _jelly_divide(monsters * parent) parent->init_experience(); parent->experience = parent->experience * 3 / 5 + 1; - // create child {dlb}: - // this is terribly partial and really requires + // Create child {dlb}: + // This is terribly partial and really requires // more thought as to generation ... {dlb} *child = *parent; - child->max_hit_points = child->hit_points; + child->max_hit_points = child->hit_points; child->speed_increment = 70 + random2(5); child->x = parent->x + jex; child->y = parent->y + jey; @@ -1395,7 +1395,7 @@ static bool _jelly_divide(monsters * parent) return (true); } // end jelly_divide() -// if you're invis and throw/zap whatever, alerts menv to your position +// If you're invis and throw/zap whatever, alerts menv to your position. void alert_nearby_monsters(void) { monsters *monster = 0; // NULL {dlb} @@ -2028,6 +2028,9 @@ void behaviour_event( monsters *mon, int event, int src, // interesting for a moment. -- bwr if (!isSmart || mon->foe == MHITNOT || mon->behaviour == BEH_WANDER) { + if (mon->is_patrolling()) + break; + mon->target_x = src_x; mon->target_y = src_y; } @@ -2035,13 +2038,13 @@ void behaviour_event( monsters *mon, int event, int src, case ME_WHACK: case ME_ANNOY: - // will turn monster against <src>, unless they + // Will turn monster against <src>, unless they // are BOTH friendly or good neutral AND stupid, // or else fleeing anyway. Hitting someone over // the head, of course, always triggers this code. if (event == ME_WHACK || ((wontAttack != sourceWontAttack || isSmart) - && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC)) + && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC)) { // (plain) plants and fungi cannot flee or fight back if (mon->type == MONS_FUNGUS || mon->type == MONS_PLANT) @@ -2059,16 +2062,19 @@ 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 x,y so that monster can whack + // back (once) at an invisible foe. if (event == ME_WHACK) setTarget = true; break; case ME_ALERT: - // will alert monster to <src> and turn them + if (mon->is_patrolling()) + break; + + // Will alert monster to <src> and turn them // against them, unless they have a current foe. - // it won't turn friends hostile either. + // It won't turn friends hostile either. if (mon->behaviour != BEH_CORNERED && mon->behaviour != BEH_PANIC && mon->behaviour != BEH_FLEE) { @@ -2108,7 +2114,7 @@ void behaviour_event( monsters *mon, int event, int src, break; } - // Just set behaviour.. foe doesn't change. + // Just set behaviour... foe doesn't change. if (mon->behaviour != BEH_CORNERED) simple_monster_message(mon, " turns to fight!"); @@ -2135,14 +2141,45 @@ void behaviour_event( monsters *mon, int event, int src, } } - // now, break charms if appropriate + // Now, break charms if appropriate. if (breakCharm) mon->del_ench(ENCH_CHARM); - // do any resultant foe or state changes + // Do any resultant foe or state changes. _handle_behaviour( mon ); } +static bool _choose_random_target_grid_in_los(monsters *mon) +{ + int pos_x, pos_y; + int count_grids = 0; + for (int j = -LOS_RADIUS; j < LOS_RADIUS; j++) + for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++) + { + if (j == 0 && k == 0) + continue; + + pos_x = mon->x + j; + pos_y = mon->y + k; + + if (!in_bounds(pos_x, pos_y)) + continue; + if (!mon->mon_see_grid(pos_x, pos_y)) + continue; + if (!mon->can_pass_through_feat(grd[pos_x][pos_y])) + continue; + + if (one_chance_in(++count_grids)) + { + mon->target_x = pos_x; + mon->target_y = pos_y; + } + } + + return (count_grids); +} + + //--------------------------------------------------------------- // // handle_behaviour @@ -2164,11 +2201,12 @@ static void _handle_behaviour(monsters *mon) bool wontAttack = mons_wont_attack(mon); bool proxPlayer = mons_near(mon); bool proxFoe; - bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); - bool isHealthy = (mon->hit_points > mon->max_hit_points / 2); - bool isSmart = (mons_intel(mon->type) > I_ANIMAL); - bool isScared = mon->has_ench(ENCH_FEAR); - bool isMobile = !mons_is_stationary(mon); + bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); + bool isHealthy = (mon->hit_points > mon->max_hit_points / 2); + bool isSmart = (mons_intel(mon->type) > I_ANIMAL); + bool isScared = mon->has_ench(ENCH_FEAR); + bool isMobile = !mons_is_stationary(mon); + bool patrolling = mon->is_patrolling(); // check for confusion -- early out. if (mon->has_ench(ENCH_CONFUSION)) @@ -2178,7 +2216,7 @@ static void _handle_behaviour(monsters *mon) return; } - // validate current target exists + // Validate current target exists. if (mon->foe != MHITNOT && mon->foe != MHITYOU && menv[mon->foe].type == -1) { @@ -2197,15 +2235,15 @@ static void _handle_behaviour(monsters *mon) proxPlayer = false; const int intel = mons_intel(mon->type); - // now, the corollary to that is that sometimes, if a - // player is right next to a monster, they will 'see' + // Now, the corollary to that is that sometimes, if a + // player is right next to a monster, they will 'see'. if (grid_distance( you.x_pos, you.y_pos, mon->x, mon->y ) == 1 && one_chance_in(3)) { proxPlayer = true; } - // [dshaligram] Very smart monsters have a chance of cluing in to + // [dshaligram] Very smart monsters have a chance of clueing in to // invisible players in various ways. else if (intel == I_NORMAL && one_chance_in(13) || intel == I_HIGH && one_chance_in(6)) @@ -2239,7 +2277,7 @@ static void _handle_behaviour(monsters *mon) if (isNeutral && mon->foe == MHITNOT) _set_nearest_monster_foe(mon); - // monsters do not attack themselves {dlb} + // Monsters do not attack themselves. {dlb} if (mon->foe == monster_index(mon)) mon->foe = MHITNOT; @@ -2280,7 +2318,7 @@ static void _handle_behaviour(monsters *mon) int foe_x = you.x_pos; int foe_y = you.y_pos; - // evaluate these each time; they may change + // Evaluate these each time; they may change. if (mon->foe == MHITNOT) proxFoe = false; else @@ -2303,12 +2341,12 @@ static void _handle_behaviour(monsters *mon) } } - // track changes to state; attitude never changes here. - beh_type new_beh = mon->behaviour; + // Track changes to state; attitude never changes here. + beh_type new_beh = mon->behaviour; unsigned int new_foe = mon->foe; // take care of monster state changes - switch(mon->behaviour) + switch (mon->behaviour) { case BEH_SLEEP: // default sleep state @@ -2321,7 +2359,7 @@ static void _handle_behaviour(monsters *mon) // no foe? then wander or seek the player if (mon->foe == MHITNOT) { - if (!proxPlayer || isNeutral) + if (!proxPlayer || isNeutral || patrolling) new_beh = BEH_WANDER; else { @@ -2329,13 +2367,19 @@ static void _handle_behaviour(monsters *mon) mon->target_x = you.x_pos; mon->target_y = you.y_pos; } - break; } // foe gone out of LOS? if (!proxFoe) { + if (patrolling) + { + new_foe = MHITNOT; + new_beh = BEH_WANDER; + break; + } + if (isFriendly) { new_foe = MHITYOU; @@ -2410,11 +2454,11 @@ static void _handle_behaviour(monsters *mon) break; // switch/case BEH_SEEK } - // monster can see foe: continue 'tracking' - // by updating target x,y + // Monster can see foe: continue 'tracking' + // by updating target x,y. if (mon->foe == MHITYOU) { - // sometimes, your friends will wander a bit. + // Sometimes, your friends will wander a bit. if (isFriendly && one_chance_in(8)) { mon->target_x = 10 + random2(GXM - 10); @@ -2439,7 +2483,7 @@ static void _handle_behaviour(monsters *mon) break; case BEH_WANDER: - // is our foe in LOS? + // Is our foe in LOS? // Batty monsters don't automatically reseek so that // they'll flitter away, we'll reset them just before // they get movement in handle_monsters() instead. -- bwr @@ -2462,14 +2506,25 @@ static void _handle_behaviour(monsters *mon) || one_chance_in(20) || testbits( mon->flags, MF_BATTY )) { - mon->target_x = 10 + random2(GXM - 10); - mon->target_y = 10 + random2(GYM - 10); + if (patrolling) + { + if (mon->patrol_point != coord_def(mon->x, mon->y) + || !_choose_random_target_grid_in_los(mon)) + { + mon->target_x = mon->patrol_point.x; + mon->target_y = mon->patrol_point.y; + } + } + else + { + mon->target_x = 10 + random2(GXM - 10); + mon->target_y = 10 + random2(GYM - 10); + } } - // during their wanderings, monsters will - // eventually relax their guard (stupid - // ones will do so faster, smart monsters - // have longer memories + // During their wanderings, monsters will eventually relax their + // guard (stupid ones will do so faster, smart monsters have + // longer memories. if (!proxFoe && mon->foe != MHITNOT && one_chance_in( isSmart ? 60 : 20 )) { @@ -2482,11 +2537,9 @@ static void _handle_behaviour(monsters *mon) if (isHealthy && !isScared) new_beh = BEH_SEEK; - // Smart monsters flee until they can - // flee no more... possible to get a - // 'CORNERED' event, at which point - // we can jump back to WANDER if the foe - // isn't present. + // Smart monsters flee until they can flee no more... + // possible to get a 'CORNERED' event, at which point + // we can jump back to WANDER if the foe isn't present. // XXX: If a monster can move through solid grids, then it // should preferentially flee towards the nearest solid grid @@ -2497,13 +2550,13 @@ static void _handle_behaviour(monsters *mon) if (isFriendly) { - // Special-cased below so that it will flee *towards* you + // Special-cased below so that it will flee *towards* you. mon->target_x = you.x_pos; mon->target_y = you.y_pos; } else if (proxFoe) { - // try to flee _from_ the correct position + // Try to flee _from_ the correct position. mon->target_x = foe_x; mon->target_y = foe_y; } @@ -2516,7 +2569,7 @@ static void _handle_behaviour(monsters *mon) // foe gone out of LOS? if (!proxFoe) { - if ((isFriendly || proxPlayer) && !isNeutral) + if ((isFriendly || proxPlayer) && !isNeutral && !patrolling) new_foe = MHITYOU; else new_beh = BEH_WANDER; @@ -2571,8 +2624,7 @@ static bool _mons_check_set_foe(monsters *mon, int x, int y, return (false); } -// choose nearest monster as a foe -// (used for berserking monsters) +// Choose nearest monster as a foe. (Used for berserking monsters.) void _set_nearest_monster_foe(monsters *mon) { const bool friendly = mons_friendly(mon); @@ -3579,7 +3631,7 @@ static bool _handle_reaching(monsters *monster) { int foe_x = menv[monster->foe].x; int foe_y = menv[monster->foe].y; - // same comments as to invisibility as above. + // Same comments as to invisibility as above. if (monster->target_x == foe_x && monster->target_y == foe_y && monster->mon_see_grid(foe_x, foe_y, true)) { @@ -4526,7 +4578,7 @@ static bool _handle_throw(monsters *monster, bolt & beem) if (one_chance_in(archer? 9 : 5)) return (false); - // don't allow offscreen throwing for now. + // Don't allow offscreen throwing for now. if (monster->foe == MHITYOU && !mons_near(monster)) return (false); @@ -4900,63 +4952,87 @@ static void _handle_monster_move(int i, monsters *monster) } else { - // calculates mmov_x, mmov_y based on monster target. + // Calculates mmov_x, mmov_y based on monster target. _handle_movement(monster); brkk = false; - if (mons_is_confused(monster) - || monster->type == MONS_AIR_ELEMENTAL - && monster->has_ench(ENCH_SUBMERGED)) - { - std::vector<coord_def> moves; - - int pfound = 0; - for (int yi = -1; yi <= 1; ++yi) - for (int xi = -1; xi <= 1; ++xi) - { - coord_def c = monster->pos() + coord_def(xi, yi); - if (in_bounds(c) && monster->can_pass_through(c) - && one_chance_in(++pfound)) - { - mmov_x = xi; - mmov_y = yi; - } - } - - if (random2(2 + pfound) < 2) - mmov_x = mmov_y = 0; - - // Bounds check: don't let confused monsters try to run - // off the map. - if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM) - mmov_x = 0; - - if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM) - mmov_y = 0; - - if (!monster->can_pass_through(monster->x + mmov_x, - monster->y + mmov_y)) - { - mmov_x = mmov_y = 0; - } - - 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(i, - mgrd[monster->x + mmov_x][monster->y + mmov_y]); - - brkk = true; - mmov_x = 0; - mmov_y = 0; - DEBUG_ENERGY_USE("monsters_fight()"); - } - } + if (mons_is_confused(monster) + || monster->type == MONS_AIR_ELEMENTAL + && monster->has_ench(ENCH_SUBMERGED)) + { + std::vector<coord_def> moves; - if (brkk) - continue; + int pfound = 0; + for (int yi = -1; yi <= 1; ++yi) + for (int xi = -1; xi <= 1; ++xi) + { + coord_def c = monster->pos() + coord_def(xi, yi); + if (in_bounds(c) && monster->can_pass_through(c) + && one_chance_in(++pfound)) + { + mmov_x = xi; + mmov_y = yi; + } + } + + if (random2(2 + pfound) < 2) + mmov_x = mmov_y = 0; + + // Bounds check: don't let confused monsters try to run + // off the map. + if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM) + mmov_x = 0; + + if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM) + mmov_y = 0; + + if (!monster->can_pass_through(monster->x + mmov_x, + monster->y + mmov_y)) + { + mmov_x = mmov_y = 0; + } + + int enemy = mgrd[monster->x + mmov_x][monster->y + mmov_y]; + if (enemy != NON_MONSTER + && !is_sanctuary(monster->x, monster->y) + && (mmov_x != 0 || mmov_y != 0)) + { + if (monsters_fight(i, enemy)) + { + brkk = true; + mmov_x = 0; + mmov_y = 0; + DEBUG_ENERGY_USE("monsters_fight()"); + } + else + { + // FIXME: None of these work! + // Instead run away! + if (monster->add_ench(mon_enchant(ENCH_FEAR))) + { + behaviour_event(monster, ME_SCARE, MHITNOT, + monster->x + mmov_x, + monster->y + mmov_y); + } + break; +/* + if (monster->foe == enemy || mons_friendly(monster) + && monster->foe == MHITYOU) + { + monster->foe = MHITNOT; + monster->behaviour = BEH_WANDER; + } + + monster->target_x = 10 + random2(GXM - 10); + monster->target_y = 10 + random2(GYM - 10); +*/ + } + } + } + + if (brkk) + continue; } _handle_nearby_ability( monster ); @@ -5027,7 +5103,7 @@ static void _handle_monster_move(int i, monsters *monster) && targmon != i && !mons_aligned(i, targmon)) { - // figure out if they fight + // Figure out if they fight. if (monsters_fight(i, targmon)) { if (testbits(monster->flags, MF_BATTY)) @@ -5102,7 +5178,7 @@ static void _handle_monster_move(int i, monsters *monster) } update_beholders(monster); - // reevaluate behaviour, since the monster's + // Reevaluate behaviour, since the monster's // surroundings have changed (it may have moved, // or died for that matter. Don't bother for // dead monsters. :) @@ -5883,13 +5959,13 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x, return false; } - // smacking the player is always a good move if we're - // hostile (even if we're heading somewhere else) - // also friendlies want to keep close to the player - // so it's okay as well + // Smacking the player is always a good move if we're + // hostile (even if we're heading somewhere else). + // Also friendlies want to keep close to the player + // so it's okay as well. - // smacking another monster is good, if the monsters - // are aligned differently + // Smacking another monster is good, if the monsters + // are aligned differently. if (mgrd[targ_x][targ_y] != NON_MONSTER) { if (just_check) @@ -5902,6 +5978,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x, const int thismonster = monster_index(monster), targmonster = mgrd[targ_x][targ_y]; + if (mons_aligned(thismonster, targmonster) && targmonster != MHITNOT && targmonster != MHITYOU |