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

Vehicle holes #1610

Merged
merged 7 commits into from
Aug 18, 2022
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
20 changes: 17 additions & 3 deletions src/action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,11 @@ action_id handle_action_menu()
// display that action at the top of the list.
for( const tripoint &pos : here.points_in_radius( g->u.pos(), 1 ) ) {
if( pos != g->u.pos() ) {
// Check for actions that work on nearby tiles
// Check for actions that work on nearby tiles, skipping tiles blocked by vehicles
if( here.obstructed_by_vehicle_rotation( g->u.pos(), pos ) ) {
continue;
}

if( can_interact_at( ACTION_OPEN, pos ) ) {
action_weightings[ACTION_OPEN] = 200;
}
Expand Down Expand Up @@ -1013,7 +1017,17 @@ cata::optional<tripoint> choose_direction( const std::string &message, const boo
cata::optional<tripoint> choose_adjacent( const std::string &message, const bool allow_vertical )
{
const cata::optional<tripoint> dir = choose_direction( message, allow_vertical );
return dir ? *dir + g->u.pos() : dir;

if( !dir ) {
return cata::nullopt;
}

if( get_map().obstructed_by_vehicle_rotation( g->u.pos(), *dir + g->u.pos() ) ) {
add_msg( _( "You can't reach through that vehicle's wall." ) );
return cata::nullopt;
}

return *dir + g->u.pos();
}

cata::optional<tripoint> choose_adjacent_highlight( const std::string &message,
Expand All @@ -1033,7 +1047,7 @@ cata::optional<tripoint> choose_adjacent_highlight( const std::string &message,
map &here = get_map();
if( allowed ) {
for( const tripoint &pos : here.points_in_radius( g->u.pos(), 1 ) ) {
if( allowed( pos ) ) {
if( !here.obstructed_by_vehicle_rotation( g->u.pos(), pos ) && allowed( pos ) ) {
valid.emplace_back( pos );
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ std::vector<tripoint> route_adjacent( const player &p, const tripoint &dest )
map &here = get_map();

for( const tripoint &tp : here.points_in_radius( dest, 1 ) ) {
if( tp != p.pos() && here.passable( tp ) ) {
if( tp != p.pos() && here.passable( tp ) && !here.obstructed_by_vehicle_rotation( dest, tp ) ) {
passable_tiles.emplace( tp );
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d )
return false;
}

if( m.obstructed_by_vehicle_rotation( you.pos(), dest_loc ) ) {
add_msg( _( "You can't walk through that vehicle's wall." ) );
return false;
}

if( monster *const mon_ptr = g->critter_at<monster>( dest_loc, true ) ) {
monster &critter = *mon_ptr;
if( critter.friendly == 0 &&
Expand Down
20 changes: 20 additions & 0 deletions src/ballistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,26 @@ dealt_projectile_attack projectile_attack( const projectile &proj_arg, const tri
critter->ranged_target_size(), 0.4 );
}

if( here.obstructed_by_vehicle_rotation( prev_point, tp ) ) {
//We're firing through an impassible gap in a rotated vehicle, randomly hit one of the two walls
tripoint rand = tp;
if( one_in( 2 ) ) {
rand.x = prev_point.x;
} else {
rand.y = prev_point.y;
}
if( in_veh == nullptr || veh_pointer_or_null( here.veh_at( rand ) ) != in_veh ) {
here.shoot( rand, proj, false );
if( proj.impact.total_damage() <= 0 ) {
//If the projectile stops here move it back a square so it doesn't end up inside the vehicle
traj_len = i - 1;
tp = prev_point;
break;
}
}
}


if( critter != nullptr && cur_missed_by < 1.0 ) {
if( in_veh != nullptr && veh_pointer_or_null( here.veh_at( tp ) ) == in_veh &&
critter->is_player() ) {
Expand Down
2 changes: 1 addition & 1 deletion src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7876,7 +7876,7 @@ tripoint Character::adjacent_tile() const
}
}

if( dangerous_fields == 0 ) {
if( dangerous_fields == 0 && ! get_map().obstructed_by_vehicle_rotation( pos(), p ) ) {
ret.push_back( p );
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,15 @@ bool Creature::sees( const Creature &critter ) const
return ch == nullptr || !ch->is_invisible();
};

map &here = get_map();
const Character *ch = critter.as_character();
const int wanted_range = rl_dist( pos(), critter.pos() );
map &here = get_map();
// Can always see adjacent monsters on the same level.
// Can always see adjacent monsters on the same level, unless they're through a vehicle wall.
// We also bypass lighting for vertically adjacent monsters, but still check for floors.
if( wanted_range <= 1 && ( posz() == critter.posz() || here.sees( pos(), critter.pos(), 1 ) ) ) {
if( here.obscured_by_vehicle_rotation( pos(), critter.pos() ) ) {
return false;
}
return visible( ch );
} else if( ( wanted_range > 1 && critter.digging() ) ||
( critter.has_flag( MF_NIGHT_INVISIBILITY ) && here.light_at( critter.pos() ) <= lit_level::LOW ) ||
Expand Down
17 changes: 14 additions & 3 deletions src/explosion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ static std::map<const Creature *, int> do_blast( const tripoint &p, const float
// Iterate over all neighbors. Bash all of them, propagate to some
for( size_t i = 0; i < max_index; i++ ) {
tripoint dest( pt + tripoint( x_offset[i], y_offset[i], z_offset[i] ) );
if( closed.count( dest ) != 0 || !here.inbounds( dest ) ) {
if( closed.count( dest ) != 0 || !here.inbounds( dest ) ||
here.obstructed_by_vehicle_rotation( pt, dest ) ) {
continue;
}

Expand Down Expand Up @@ -439,11 +440,16 @@ static std::map<const Creature *, int> do_blast_new( const tripoint &blast_cente
for( const dist_point_pair &pair : blast_map ) {
float distance;
tripoint position;
tripoint last_position = blast_center;
std::tie( distance, position ) = pair;

const std::vector<tripoint> line_of_movement = line_to( blast_center, position );
const bool has_obstacles = std::any_of( line_of_movement.begin(),
line_of_movement.end(), [position]( tripoint ray_position ) {
line_of_movement.end(), [position, &last_position]( tripoint ray_position ) {
if( get_map().obstructed_by_vehicle_rotation( last_position, ray_position ) ) {
return true;
}
last_position = ray_position;
return ray_position != position && get_map().impassable( ray_position );
} );

Expand Down Expand Up @@ -614,6 +620,10 @@ static std::map<const Creature *, int> shrapnel( const tripoint &src, const proj
float visited_cache[MAPSIZE_X][MAPSIZE_Y] = {};

map &here = get_map();

diagonal_blocks( &blocked_cache )[MAPSIZE_X][MAPSIZE_Y] = here.access_cache(
src.z ).vehicle_obstructed_cache;

// TODO: Calculate range based on max effective range for projectiles.
// Basically bisect between 0 and map diameter using shrapnel_calc().
// Need to update shadowcasting to support limiting range without adjusting initial distance.
Expand All @@ -631,7 +641,8 @@ static std::map<const Creature *, int> shrapnel( const tripoint &src, const proj
const int offset_distance = 60 - 1 - fragment.range;
castLightAll<float, float, shrapnel_calc, shrapnel_check,
update_fragment_cloud, accumulate_fragment_cloud>
( visited_cache, obstacle_cache, src.xy(), offset_distance, fragment.range + 1.0f );
( visited_cache, obstacle_cache, blocked_cache, src.xy(),
offset_distance, fragment.range + 1.0f );

// Now visited_caches are populated with density and velocity of fragments.
for( const tripoint &target : area ) {
Expand Down
50 changes: 40 additions & 10 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4604,6 +4604,8 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
// TODO: make the force parameter actually do something.
// the header file says higher force causes more damage.
// perhaps that is what it should do?

// TODO: refactor this so it's not copy/pasted 3 times
tripoint tp = traj.front();
if( !critter_at( tp ) ) {
debugmsg( _( "Nothing at (%d,%d,%d) to knockback!" ), tp.x, tp.y, tp.z );
Expand All @@ -4616,7 +4618,7 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
add_msg( _( "%s was stunned!" ), targ->name() );
}
for( size_t i = 1; i < traj.size(); i++ ) {
if( m.impassable( traj[i].xy() ) ) {
if( m.impassable( traj[i].xy() ) || m.obstructed_by_vehicle_rotation( tp, traj[i] ) ) {
targ->setpos( traj[i - 1] );
force_remaining = traj.size() - i;
if( stun != 0 ) {
Expand Down Expand Up @@ -4667,14 +4669,16 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
add_msg( _( "The %s flops around and dies!" ), targ->name() );
}
}
tp = traj[i];
}
} else if( npc *const targ = critter_at<npc>( tp ) ) {
if( stun > 0 ) {
targ->add_effect( effect_stunned, 1_turns * stun );
add_msg( _( "%s was stunned!" ), targ->name );
}
for( size_t i = 1; i < traj.size(); i++ ) {
if( m.impassable( traj[i].xy() ) ) { // oops, we hit a wall!
if( m.impassable( traj[i].xy() ) ||
m.obstructed_by_vehicle_rotation( tp, traj[i] ) ) { // oops, we hit a wall!
targ->setpos( traj[i - 1] );
force_remaining = traj.size() - i;
if( stun != 0 ) {
Expand Down Expand Up @@ -4731,6 +4735,7 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
break;
}
targ->setpos( traj[i] );
tp = traj[i];
}
} else if( u.pos() == tp ) {
if( stun > 0 ) {
Expand All @@ -4741,7 +4746,8 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
stun );
}
for( size_t i = 1; i < traj.size(); i++ ) {
if( m.impassable( traj[i] ) ) { // oops, we hit a wall!
if( m.impassable( traj[i] ) ||
m.obstructed_by_vehicle_rotation( tp, traj[i] ) ) { // oops, we hit a wall!
u.setpos( traj[i - 1] );
force_remaining = traj.size() - i;
if( stun != 0 ) {
Expand Down Expand Up @@ -4809,6 +4815,8 @@ void game::knockback( std::vector<tripoint> &traj, int stun, int dam_mult )
} else {
u.setpos( traj[i] );
}

tp = traj[i];
}
}
}
Expand Down Expand Up @@ -5931,7 +5939,7 @@ void game::peek()
return;
}

if( m.impassable( u.pos() + *p ) ) {
if( m.impassable( u.pos() + *p ) || m.obstructed_by_vehicle_rotation( u.pos(), u.pos() + *p ) ) {
return;
}

Expand Down Expand Up @@ -10331,7 +10339,6 @@ void game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo
return;
}

int steps = 0;
bool thru = true;
const bool is_u = ( c == &u );
// Don't animate critters getting bashed if animations are off
Expand All @@ -10342,16 +10349,36 @@ void game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo
tileray tdir( dir );
int range = flvel / 10;
tripoint pt = c->pos();
tripoint prev_point = pt;
bool force_next = false;
tripoint next_forced;
while( range > 0 ) {
c->underwater = false;
// TODO: Check whenever it is actually in the viewport
// or maybe even just redraw the changed tiles
bool seen = is_u || u.sees( *c ); // To avoid redrawing when not seen
tdir.advance();
pt.x = c->posx() + tdir.dx();
pt.y = c->posy() + tdir.dy();
if( force_next ) {
pt = next_forced;
force_next = false;
} else {
tdir.advance();
pt.x = c->posx() + tdir.dx();
pt.y = c->posy() + tdir.dy();
}
float force = 0;

if( m.obstructed_by_vehicle_rotation( prev_point, pt ) ) {
//We process the intervening tile on this iteration and then the current tile on the next
next_forced = pt;
force_next = true;
if( one_in( 2 ) ) {
pt.x = prev_point.x;
} else {
pt.y = prev_point.y;
}
}


if( monster *const mon_ptr = critter_at<monster>( pt ) ) {
monster &critter = *mon_ptr;
// Approximate critter's "stopping power" with its max hp
Expand Down Expand Up @@ -10415,8 +10442,11 @@ void game::fling_creature( Creature *c, const units::angle &dir, float flvel, bo
// although at lower velocity
break;
}
range--;
steps++;
//Vehicle wall tiles don't count for range
if( !force_next ) {
range--;
}
prev_point = pt;
if( animate && ( seen || u.sees( *c ) ) ) {
invalidate_main_ui_adaptor();
ui_manager::redraw_invalidated();
Expand Down
3 changes: 2 additions & 1 deletion src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,8 @@ int iuse::fungicide( player *p, item *it, bool, const tripoint & )
if( dest == p->pos() ) {
continue;
}
if( g->m.passable( dest ) && x_in_y( spore_count, 8 ) ) {
if( g->m.passable( dest ) && !get_map().obstructed_by_vehicle_rotation( p->pos(), dest ) &&
x_in_y( spore_count, 8 ) ) {
if( monster *const mon_ptr = g->critter_at<monster>( dest ) ) {
monster &critter = *mon_ptr;
if( g->u.sees( dest ) &&
Expand Down
Loading