Skip to content

Commit

Permalink
Vehicle holes (#1610)
Browse files Browse the repository at this point in the history
* Prevents moving through vehicle holes

* Bug fix and npc los

* Added vehicle holes to a wide range of areas

* tidy

* Caching

* fix 3d vision for vehicle holes

* Remove awful 3d vision hack
  • Loading branch information
joveeater authored Aug 18, 2022
1 parent 002e131 commit 61a1645
Show file tree
Hide file tree
Showing 41 changed files with 1,550 additions and 300 deletions.
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

0 comments on commit 61a1645

Please sign in to comment.