Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sane-ify in-vehicle movement size checks #74004

Merged
merged 6 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 5 additions & 100 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8017,63 +8017,6 @@ std::string Character::weapname_ammo() const
}
}

// Tests to see if a character has room to enter a vehicle tile.
bool Character::move_in_vehicle( Creature *c, const tripoint &dest_loc ) const
{
map &m = get_map();
const optional_vpart_position vp_there = m.veh_at( dest_loc );
if( vp_there ) {
vehicle &veh = vp_there->vehicle();
units::volume capacity = 0_ml;
units::volume free_cargo = 0_ml;
auto cargo_parts = veh.get_parts_at( dest_loc, "CARGO", part_status_flag::any );
for( vehicle_part *&part : cargo_parts ) {
vehicle_stack contents = veh.get_items( *part );
const optional_vpart_position vp = m.veh_at( dest_loc );
// Check for obstacles and appliances to prevent squishing when the part is
// not a vehicle or when the player is not actually entering the tile IE grabbing.
if( !vp.part_with_feature( "CARGO_PASSABLE", false ) &&
!vp.part_with_feature( "APPLIANCE", false ) && !vp.part_with_feature( "OBSTACLE", false ) ) {
capacity += contents.max_volume();
free_cargo += contents.free_volume();
}
}
if( capacity > 0_ml ) {
// First, we'll try to squeeze in. Open-topped vehicle parts have more room for us.
if( !veh.enclosed_at( dest_loc ) ) {
free_cargo *= 1.2;
}
const creature_size size = get_size();
if( ( size == creature_size::tiny && free_cargo < 15625_ml ) ||
( size == creature_size::small && free_cargo < 31250_ml ) ||
( size == creature_size::medium && free_cargo < 62500_ml ) ||
( size == creature_size::large && free_cargo < 125000_ml ) ||
( size == creature_size::huge && free_cargo < 250000_ml ) ) {
if( ( size == creature_size::tiny && free_cargo < 11719_ml ) ||
( size == creature_size::small && free_cargo < 23438_ml ) ||
( size == creature_size::medium && free_cargo < 46875_ml ) ||
( size == creature_size::large && free_cargo < 93750_ml ) ||
( size == creature_size::huge && free_cargo < 187500_ml ) ) {
add_msg_if_player( m_warning, _( "There's not enough room for you to fit there." ) );
return false; // Even if we squeeze, there's no room.
}
c->add_effect( effect_cramped_space, 2_turns, true );
return true;
}
}
const optional_vpart_position vp = m.veh_at( dest_loc );
// Sufficiently gigantic characters aren't comfortable in stock seats, roof or no.
if( in_vehicle && get_size() == creature_size::huge && !vp.part_with_feature( "AISLE", false ) &&
!vp.part_with_feature( "HUGE_OK", false ) && !has_effect( effect_cramped_space ) ) {
add_msg_if_player( m_warning, _( "You barely fit in this tiny human vehicle." ) );
add_msg_if_npc( m_warning, _( "%s has to really cram their huge body to fit." ), c->disp_name() );
c->add_effect( effect_cramped_space, 2_turns, true );
return true;
}
}
return true;
}

void Character::on_hit( Creature *source, bodypart_id bp_hit,
float /*difficulty*/, dealt_projectile_attack const *const proj )
{
Expand Down Expand Up @@ -11122,52 +11065,14 @@ void Character::process_effects()
}

// Being stuck in tight spaces sucks. TODO: could be expanded to apply to non-vehicle conditions.
if( has_effect( effect_cramped_space ) ) {
map &here = get_map();
const tripoint your_pos = pos();
const optional_vpart_position vp_there = here.veh_at( your_pos );
if( !vp_there ) {
remove_effect( effect_cramped_space );
return;
}
if( is_npc() && !has_effect( effect_narcosis ) && has_effect( effect_cramped_space ) ) {
bool cramped = has_effect( effect_cramped_space );
// return is intentionally discarded, sets cramped if appropriate
can_move_to_vehicle_tile( get_map().getglobal( pos() ), cramped );
if( cramped ) {
if( is_npc() && !has_effect( effect_narcosis ) ) {
npc &as_npc = dynamic_cast<npc &>( *this );
as_npc.complain_about( "cramped_vehicle", 30_minutes, "<cramped_vehicle>", false );
}
bool is_cramped_space = false;
vehicle &veh = vp_there->vehicle();
units::volume capacity = 0_ml;
units::volume free_cargo = 0_ml;
auto cargo_parts = veh.get_parts_at( your_pos, "CARGO", part_status_flag::any );
for( vehicle_part *&part : cargo_parts ) {
vehicle_stack contents = veh.get_items( *part );
const optional_vpart_position vp = here.veh_at( your_pos );
if( !vp.part_with_feature( "CARGO_PASSABLE", false ) ) {
capacity += contents.max_volume();
free_cargo += contents.free_volume();
}
const creature_size size = get_size();
if( capacity > 0_ml ) {
// Open-topped vehicle parts have more room.
if( !veh.enclosed_at( your_pos ) ) {
free_cargo *= 1.2;
}
if( ( size == creature_size::tiny && free_cargo < 15625_ml ) ||
( size == creature_size::small && free_cargo < 31250_ml ) ||
( size == creature_size::medium && free_cargo < 62500_ml ) ||
( size == creature_size::large && free_cargo < 125000_ml ) ||
( size == creature_size::huge && free_cargo < 250000_ml ) ) {
is_cramped_space = true;
}
}
if( get_size() == creature_size::huge && !vp.part_with_feature( "AISLE", false ) &&
!vp.part_with_feature( "HUGE_OK", false ) ) {
is_cramped_space = true;
}
}
if( !is_cramped_space ) {
remove_effect( effect_cramped_space );
}
}

Creature::process_effects();
Expand Down
3 changes: 0 additions & 3 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -1437,9 +1437,6 @@ class Character : public Creature, public visitable
void dismount();
void forced_dismount();

/** Attempt to enter a tile in a vehicle */
bool move_in_vehicle( Creature *c, const tripoint &dest_loc ) const;

bool is_deaf() const;
bool is_mute() const;
// Get the specified limb score. If bp is defined, only the scores from that body part type are summed.
Expand Down
89 changes: 89 additions & 0 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,95 @@ void Creature::setpos( const tripoint &p )
on_move( old_loc );
}

static units::volume size_to_volume( creature_size size_class )
{
// returns midpoint of size from volume_to_size, minus 1_ml
// e.g. max tiny size is 7500, max small size is 46250, we return
// 46250+7500 / 2 - 1_ml = 26875_ml - 1ml
// This is still stupid and both of these functions should be merged into one single source of truth.
if( size_class == creature_size::tiny ) {
return 3749_ml;
} else if( size_class == creature_size::small ) {
return 26874_ml;
} else if( size_class == creature_size::medium ) {
return 77124_ml;
} else if( size_class == creature_size::large ) {
return 295874_ml;
}
return 741874_ml;
}

bool Creature::can_move_to_vehicle_tile( const tripoint_abs_ms &loc, bool &cramped ) const
{
map &here = get_map();
const optional_vpart_position vp_there = here.veh_at( loc );
if( !vp_there ) {
return true;
}

const monster *mon = as_monster();

vehicle &veh = vp_there->vehicle();

std::vector<vehicle_part *> cargo_parts;
cargo_parts = veh.get_parts_at( here.bub_from_abs( loc ), "CARGO", part_status_flag::any );

units::volume capacity = 0_ml;
units::volume free_cargo = 0_ml;
for( vehicle_part *part : cargo_parts ) {
vehicle_stack contents = veh.get_items( *part );
if( !vp_there.part_with_feature( "CARGO_PASSABLE", false ) &&
!vp_there.part_with_feature( "APPLIANCE", false ) &&
!vp_there.part_with_feature( "OBSTACLE", false ) ) {
capacity += contents.max_volume();
free_cargo += contents.free_volume();
}
}
if( capacity > 0_ml ) {
// First, we'll try to squeeze in. Open-topped vehicle parts have more room to step over cargo.
if( !veh.enclosed_at( here.getlocal( loc ) ) ) {
free_cargo *= 1.2;
}
const creature_size size = get_size();
units::volume critter_volume;
if( mon ) {
critter_volume = mon->get_volume();
} else {
critter_volume = size_to_volume( size );
}

if( critter_volume > free_cargo ) {
return false;
}

if( critter_volume > size_to_volume( creature_size::large ) &&
!vp_there.part_with_feature( "HUGE_OK", false ) ) {
return false;
}

if( critter_volume < free_cargo * 1.33 ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I reading this right? If the creature's volume is less than a third over the free cargo space and isn't a monster, snake, blob or fish-type then it's cramped? Shouldn't the check be for if the creature's volume greater than a third over free cargo space?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading it right, interpreting it wrong. If the critter is greater than the free cargo size, it can't move into this tile in the first place - we return false earlier in the function. https://github.com/CleverRaven/Cataclysm-DDA/pull/74004/files#diff-5a026da090b6664f91c5f3bc4a9d0844cff966ef6fa5785d258b3aa47b370a2cR253

But yeah this logic is confusing, and part of the reason why I wanted to get rid of the huge block of volume comparisons shown.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah, point. I was so focused on chasing down what was setting cramped to true I failed to remember what the whole function was about.

That said, I'm reasonably sure this particular check is the culprit when it comes to #74068 since commenting out cramped = true; and recompiling prevents the behavior reported there from occurring.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the equation should be free_cargo * 0.75 < critter_volume instead,
thus we set cramped when free_cargo * 0.75 < critter_volume && critter_volume <= free_cargo

I'm already working on it tonight, this whole thing is still a mess.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested critter_volume * 0.75 < free_cargo && critter_volume <= free_cargo and it's still setting cramped to true.

if( !mon || !( mon->type->bodytype == "snake" || mon->type->bodytype == "blob" ||
mon->type->bodytype == "fish" ||
has_flag( mon_flag_PLASTIC ) || has_flag( mon_flag_SMALL_HIDER ) ) ) {
cramped = true;
}
}

if( size == creature_size::huge && !vp_there.part_with_feature( "AISLE", false ) &&
!vp_there.part_with_feature( "HUGE_OK", false ) ) {
cramped = true;
}
}

return true;
}

bool Creature::can_move_to_vehicle_tile( const tripoint_abs_ms &loc ) const
{
bool dummy = false;
return can_move_to_vehicle_tile( loc, dummy );
}

void Creature::move_to( const tripoint_abs_ms &loc )
{
const tripoint_abs_ms old_loc = get_location();
Expand Down
4 changes: 4 additions & 0 deletions src/creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ class Creature : public viewer
return get_location().z();
}
void setpos( const tripoint &p );
/** Checks if the creature fits into a given tile. Set the boolean argument to true if the creature would barely fit. */
bool can_move_to_vehicle_tile( const tripoint_abs_ms &loc, bool &cramped ) const;
/** Helper overload for when the boolean is discardable */
bool can_move_to_vehicle_tile( const tripoint_abs_ms &loc ) const;
/** Moves the creature to the given location and calls the on_move() handler. */
void move_to( const tripoint_abs_ms &loc );

Expand Down
10 changes: 9 additions & 1 deletion src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ static const efftype_id effect_asked_to_train( "asked_to_train" );
static const efftype_id effect_blind( "blind" );
static const efftype_id effect_bouldering( "bouldering" );
static const efftype_id effect_contacts( "contacts" );
static const efftype_id effect_cramped_space( "cramped_space" );
static const efftype_id effect_docile( "docile" );
static const efftype_id effect_downed( "downed" );
static const efftype_id effect_fake_common_cold( "fake_common_cold" );
Expand Down Expand Up @@ -10724,7 +10725,9 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp, const bool
}
u.set_underwater( false );

if( vp_there && !u.move_in_vehicle( static_cast<Creature *>( &u ), dest_loc ) ) {
bool cramped = false;
if( vp_there && !u.can_move_to_vehicle_tile( get_map().getglobal( dest_loc ), cramped ) ) {
add_msg( m_warning, _( "There's not enough room for you to fit there." ) );
return false;
}

Expand Down Expand Up @@ -10941,6 +10944,11 @@ bool game::walk_move( const tripoint &dest_loc, const bool via_ramp, const bool
start_hauling( oldpos );
}

if( cramped ) { // passed by reference, can_move_to_vehicle_tile sets to true if actually cramped
add_msg( m_warning, _( "You barely fit in this tiny human vehicle." ) );
u.add_effect( effect_cramped_space, 2_turns, true );
}

on_move_effects();

return true;
Expand Down
69 changes: 8 additions & 61 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,64 +132,6 @@ static bool z_is_valid( int z )
return z >= -OVERMAP_DEPTH && z <= OVERMAP_HEIGHT;
}

bool monster::monster_move_in_vehicle( const tripoint &p ) const
{
map &m = get_map();
monster critter = *this;
const optional_vpart_position vp = m.veh_at( p );
if( vp.has_value() ) {
vehicle &veh = vp->vehicle();
units::volume capacity = 0_ml;
units::volume free_cargo = 0_ml;
auto cargo_parts = veh.get_parts_at( p, "CARGO", part_status_flag::any );
for( vehicle_part *&part : cargo_parts ) {
vehicle_stack contents = veh.get_items( *part );
if( !vp.part_with_feature( "CARGO_PASSABLE", false ) &&
!vp.part_with_feature( "APPLIANCE", false ) && !vp.part_with_feature( "OBSTACLE", false ) ) {
capacity += contents.max_volume();
free_cargo += contents.free_volume();
}
}
if( capacity > 0_ml ) {
// First, we'll try to squeeze in. Open-topped vehicle parts have more room to step over cargo.
if( !veh.enclosed_at( p ) ) {
free_cargo *= 1.2;
}
if( !veh.enclosed_at( p ) && flies() ) {
return true; // No amount of cargo will block a flying monster if there's no roof.
}
const creature_size size = get_size();
if( ( size == creature_size::tiny && free_cargo < 15625_ml ) ||
( size == creature_size::small && free_cargo < 31250_ml ) ||
( size == creature_size::medium && free_cargo < 62500_ml ) ||
( size == creature_size::large && free_cargo < 125000_ml ) ||
( size == creature_size::huge && free_cargo < 250000_ml ) ) {
if( ( size == creature_size::tiny && free_cargo < 11719_ml ) ||
( size == creature_size::small && free_cargo < 23438_ml ) ||
( size == creature_size::medium && free_cargo < 46875_ml ) ||
( size == creature_size::large && free_cargo < 93750_ml ) ||
( size == creature_size::huge && free_cargo < 187500_ml ) ||
( get_volume() > 850000_ml && !vp.part_with_feature( "HUGE_OK", false ) ) ) {
return false; // Return false if there's just no room whatsoever. Anything over 850 liters will simply never fit in a vehicle part that isn't specifically made for it.
// I'm sorry but you can't let a kaiju ride shotgun.
}
if( type->bodytype == "snake" || type->bodytype == "blob" || type->bodytype == "fish" ||
has_flag( mon_flag_PLASTIC ) || has_flag( mon_flag_SMALL_HIDER ) ) {
return true; // Return true if we're wiggly enough to be fine with cramped space.
}
critter.add_effect( effect_cramped_space, 2_turns, true );
return true; // Otherwise we add the effect and return true.
}
if( size == creature_size::huge && !vp.part_with_feature( "AISLE", false ) &&
!vp.part_with_feature( "HUGE_OK", false ) ) {
critter.add_effect( effect_cramped_space, 2_turns, true );
return true; // Sufficiently gigantic creatures have trouble in stock seats, roof or no.
}
}
}
return true;
}

bool monster::will_move_to( const tripoint &p ) const
{
map &here = get_map();
Expand Down Expand Up @@ -1691,7 +1633,8 @@ bool monster::bash_at( const tripoint &p )
return false;
}

bool try_bash = !can_move_to( p ) || one_in( 3 );
const bool too_cramped = !can_move_to_vehicle_tile( get_map().getglobal( p ) );
bool try_bash = !can_move_to( p ) || one_in( 3 ) || too_cramped;
if( !try_bash ) {
return false;
}
Expand All @@ -1701,7 +1644,7 @@ bool monster::bash_at( const tripoint &p )
}

map &here = get_map();
if( !( here.is_bashable_furn( p ) || here.veh_at( p ).obstacle_at_part() ) ) {
if( !( here.is_bashable_furn( p ) || here.veh_at( p ).obstacle_at_part() || too_cramped ) ) {
// if the only thing here is road or flat, rarely bash it
bool flat_ground = here.has_flag( ter_furn_flag::TFLAG_ROAD, p ) ||
here.has_flag( ter_furn_flag::TFLAG_FLAT, p );
Expand Down Expand Up @@ -1872,7 +1815,8 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter,
}
}

if( here.veh_at( p ).part_with_feature( VPFLAG_CARGO, true ) && !monster_move_in_vehicle( p ) ) {
bool cramped = false; // applies an effect if monster does end up moving there
if( !can_move_to_vehicle_tile( here.getglobal( p ), cramped ) ) {
return false;
}

Expand Down Expand Up @@ -1970,6 +1914,9 @@ bool monster::move_to( const tripoint &p, bool force, bool step_on_critter,
optional_vpart_position vp_dest = here.veh_at( destination );
if( vp_dest ) {
vp_dest->vehicle().invalidate_mass();
if( cramped ) {
add_effect( effect_cramped_space, 2_turns, true );
}
}
if( is_hallucination() ) {
//Hallucinations don't do any of the stuff after this point
Expand Down
Loading
Loading