Skip to content

Commit

Permalink
Prevent monsters from leaping to their death in water (#38150)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkraybill authored Feb 20, 2020
1 parent f5babd6 commit f3fbeb8
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 19 deletions.
4 changes: 4 additions & 0 deletions src/mattack_actors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ bool leap_actor::call( monster &z ) const
break;
}
}
// don't leap into water if you could drown (#38038)
if( z.is_aquatic_danger( dest ) ) {
blocked_path = true;
}
if( blocked_path ) {
continue;
}
Expand Down
39 changes: 20 additions & 19 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,14 +546,19 @@ static float get_stagger_adjust( const tripoint &source, const tripoint &destina
return std::max( 0.01f, initial_dist - new_dist );
}

/**
* Returns true if the given square presents a possibility of drowning for the monster: it's deep water, it's liquid,
* the monster can drown, and there is no boardable vehicle part present.
*/
bool monster::is_aquatic_danger( const tripoint &at_pos )
{
return g->m.has_flag_ter( TFLAG_DEEP_WATER, at_pos ) && g->m.has_flag( flag_LIQUID, at_pos ) &&
can_drown() && !g->m.veh_at( at_pos ).part_with_feature( "BOARDABLE", false );
}

bool monster::die_if_drowning( const tripoint &at_pos, const int chance )
{
if( g->m.has_flag( flag_LIQUID, at_pos ) && can_drown() && one_in( chance ) ) {
// if there's a vehicle here with a boardable part, the monster is on it
// and not drowning
if( g->m.veh_at( at_pos ).part_with_feature( "BOARDABLE", false ) ) {
return false;
}
if( is_aquatic_danger( at_pos ) && one_in( chance ) ) {
die( nullptr );
if( g->u.sees( at_pos ) ) {
add_msg( _( "The %s drowns!" ), name() );
Expand Down Expand Up @@ -662,11 +667,9 @@ void monster::move()
}
}

// The monster is in a deep water tile and has a chance to drown
if( g->m.has_flag_ter( TFLAG_DEEP_WATER, pos() ) ) {
if( die_if_drowning( pos(), 10 ) ) {
return;
}
// if the monster is in a deep water tile, it has a chance to drown
if( die_if_drowning( pos(), 10 ) ) {
return;
}

if( moves < 0 ) {
Expand Down Expand Up @@ -1818,14 +1821,12 @@ void monster::knock_back_to( const tripoint &to )
}

// If we're still in the function at this point, we're actually moving a tile!
if( g->m.has_flag_ter( TFLAG_DEEP_WATER, to ) ) {
// die_if_drowning will kill the monster if necessary, but if the deep water
// tile is on a vehicle, we should check for swimmers out of water
if( !die_if_drowning( to ) && has_flag( MF_AQUATIC ) ) {
die( nullptr );
if( u_see ) {
add_msg( _( "The %s flops around and dies!" ), name() );
}
// die_if_drowning will kill the monster if necessary, but if the deep water
// tile is on a vehicle, we should check for swimmers out of water
if( !die_if_drowning( to ) && has_flag( MF_AQUATIC ) ) {
die( nullptr );
if( u_see ) {
add_msg( _( "The %s flops around and dies!" ), name() );
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ class monster : public Creature
void footsteps( const tripoint &p ); // noise made by movement
void shove_vehicle( const tripoint &remote_destination,
const tripoint &nearby_destination ); // shove vehicles out of the way

// check if the given square could drown a drownable monster
bool is_aquatic_danger( const tripoint &at_pos );

// check if a monster at a position will drown and kill it if necessary
// returns true if the monster dies
// chance is the one_in( chance ) that the monster will drown
Expand Down

0 comments on commit f3fbeb8

Please sign in to comment.