diff --git a/src/game.cpp b/src/game.cpp index ff9e172396164..5f6bc4da0ed1d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -227,6 +227,7 @@ static const efftype_id effect_downed( "downed" ); static const efftype_id effect_fake_common_cold( "fake_common_cold" ); static const efftype_id effect_fake_flu( "fake_flu" ); static const efftype_id effect_laserlocked( "laserlocked" ); +static const efftype_id effect_led_by_leash( "led_by_leash" ); static const efftype_id effect_no_sight( "no_sight" ); static const efftype_id effect_onfire( "onfire" ); static const efftype_id effect_pet( "pet" ); @@ -11954,8 +11955,8 @@ void game::vertical_move( int movez, bool force, bool peeking ) // TODO: just check if it's going for the avatar's location, it's simpler Creature *target = critter.attack_target(); if( ( target && target->is_avatar() ) || ( !critter.has_effect( effect_ridden ) && - critter.has_effect( effect_pet ) && critter.friendly == -1 && - !critter.has_effect( effect_tied ) ) ) { + ( critter.is_pet_follow() || critter.has_effect( effect_led_by_leash ) ) && + !critter.has_effect( effect_tied ) && critter.sees( u ) ) ) { monsters_following.push_back( &critter ); } } diff --git a/src/monexamine.cpp b/src/monexamine.cpp index bd0f1f5120b7f..1aed4d9f9900a 100644 --- a/src/monexamine.cpp +++ b/src/monexamine.cpp @@ -456,6 +456,7 @@ void start_leading( monster &z ) untie_pet( z ); } z.add_effect( effect_led_by_leash, 1_turns, true ); + z.unset_dest(); add_msg( _( "You take hold of the %s's leash to make it follow you." ), z.get_name() ); } diff --git a/src/monmove.cpp b/src/monmove.cpp index 673a1d3d0f884..d2e367d76659b 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -100,7 +100,6 @@ static const mon_flag_str_id mon_flag_PATH_AVOID_DANGER_1( "PATH_AVOID_DANGER_1" static const mon_flag_str_id mon_flag_PATH_AVOID_DANGER_2( "PATH_AVOID_DANGER_2" ); static const mon_flag_str_id mon_flag_PATH_AVOID_FALL( "PATH_AVOID_FALL" ); static const mon_flag_str_id mon_flag_PATH_AVOID_FIRE( "PATH_AVOID_FIRE" ); -static const mon_flag_str_id mon_flag_PET_WONT_FOLLOW( "PET_WONT_FOLLOW" ); static const mon_flag_str_id mon_flag_PRIORITIZE_TARGETS( "PRIORITIZE_TARGETS" ); static const mon_flag_str_id mon_flag_PUSH_MON( "PUSH_MON" ); static const mon_flag_str_id mon_flag_PUSH_VEH( "PUSH_VEH" ); @@ -758,13 +757,11 @@ void monster::plan() next_stop = patrol_route.at( next_patrol_point ); } set_dest( next_stop ); - } else if( friendly != 0 && has_effect( effect_led_by_leash ) ) { + } else if( friendly != 0 && has_effect( effect_led_by_leash ) && + get_location().z() == get_dest().z() ) { // visibility doesn't matter, we're getting pulled by a leash - if( rl_dist( get_location(), player_character.get_location() ) > 1 ) { - set_dest( player_character.get_location() ); - } else { - unset_dest(); - } + // To use stairs smoothly, if the destination is on a different Z-level, move there first. + set_dest( player_character.get_location() ); if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; @@ -772,14 +769,12 @@ void monster::plan() } else if( friendly > 0 && one_in( 3 ) ) { // Grow restless with no targets friendly--; - } else if( friendly < 0 && sees( player_character ) && - // Simpleminded animals are too dumb to follow the player. - !has_flag( mon_flag_PET_WONT_FOLLOW ) ) { - if( rl_dist( get_location(), player_character.get_location() ) > 2 ) { - set_dest( player_character.get_location() ); - } else { - unset_dest(); - } + } else if( is_pet_follow() && sees( player_character ) && + ( get_location().z() == player_character.get_location().z() || + get_location().z() == get_dest().z() ) ) { + // Simpleminded animals are too dumb to follow the player. + // To use stairs smoothly, if the destination is on a different Z-level, move there first. + set_dest( player_character.get_location() ); } } @@ -977,10 +972,20 @@ void monster::move() } } - if( ( current_attitude == MATT_IGNORE && patrol_route.empty() ) || - ( ( current_attitude == MATT_FOLLOW || - ( has_flag( mon_flag_KEEP_DISTANCE ) && !( current_attitude == MATT_FLEE ) ) ) - && rl_dist( get_location(), get_dest() ) <= type->tracking_distance ) ) { + if( is_pet_follow() || ( friendly != 0 && has_effect( effect_led_by_leash ) ) ) { + const int dist = rl_dist( get_location(), get_dest() ); + if( ( dist <= 1 || ( dist <= 2 && !has_effect( effect_led_by_leash ) && + sees( player_character ) ) ) && + ( get_dest() == player_character.get_location() && + get_location().z() == player_character.get_location().z() ) ) { + moves = 0; + stumble(); + return; + } + } else if( ( current_attitude == MATT_IGNORE && patrol_route.empty() ) || + ( ( current_attitude == MATT_FOLLOW || + ( has_flag( mon_flag_KEEP_DISTANCE ) && !( current_attitude == MATT_FLEE ) ) ) + && rl_dist( get_location(), get_dest() ) <= type->tracking_distance ) ) { moves = 0; stumble(); return; diff --git a/src/monster.cpp b/src/monster.cpp index 4f33f99ac0dfd..bd658bf770021 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -104,6 +104,7 @@ static const efftype_id effect_no_sight( "no_sight" ); static const efftype_id effect_onfire( "onfire" ); static const efftype_id effect_pacified( "pacified" ); static const efftype_id effect_paralyzepoison( "paralyzepoison" ); +static const efftype_id effect_pet( "pet" ); static const efftype_id effect_photophobia( "photophobia" ); static const efftype_id effect_poison( "poison" ); static const efftype_id effect_ridden( "ridden" ); @@ -177,6 +178,7 @@ static const mon_flag_str_id mon_flag_NO_BREED( "NO_BREED" ); static const mon_flag_str_id mon_flag_NO_FUNG_DMG( "NO_FUNG_DMG" ); static const mon_flag_str_id mon_flag_PARALYZEVENOM( "PARALYZEVENOM" ); static const mon_flag_str_id mon_flag_PET_MOUNTABLE( "PET_MOUNTABLE" ); +static const mon_flag_str_id mon_flag_PET_WONT_FOLLOW( "PET_WONT_FOLLOW" ); static const mon_flag_str_id mon_flag_PHOTOPHOBIC( "PHOTOPHOBIC" ); static const mon_flag_str_id mon_flag_PLASTIC( "PLASTIC" ); static const mon_flag_str_id mon_flag_QUEEN( "QUEEN" ); @@ -1283,6 +1285,16 @@ bool monster::made_of( phase_id p ) const return type->phase == p; } +bool monster::is_pet() const +{ + return friendly == -1 && has_effect( effect_pet ); +} + +bool monster::is_pet_follow() const +{ + return is_pet() && !has_flag( mon_flag_PET_WONT_FOLLOW ); +} + std::vector monster::get_absorb_material() const { return type->absorb_material; diff --git a/src/monster.h b/src/monster.h index 75ccfbee2aa92..6b7cfa1d1be28 100644 --- a/src/monster.h +++ b/src/monster.h @@ -181,6 +181,8 @@ class monster : public Creature bool made_of( phase_id p ) const; // Returns true if its phase is p bool shearable() const; + bool is_pet() const; + bool is_pet_follow() const; bool avoid_trap( const tripoint &pos, const trap &tr ) const override;