From 9773f38041b8c2dd5ac15f5b3ed12d5ca9e80efb Mon Sep 17 00:00:00 2001 From: jove Date: Mon, 1 Aug 2022 01:33:46 +0100 Subject: [PATCH] Added vehicle holes to a wide range of areas --- src/activity_item_handling.cpp | 2 +- src/character.cpp | 2 +- src/explosion.cpp | 2 +- src/game.cpp | 50 +++++++-- src/iuse.cpp | 3 +- src/magic_spell_effect.cpp | 60 ++++++++--- src/map.cpp | 48 ++++++--- src/map.h | 4 +- src/map_field.cpp | 12 ++- src/mattack_actors.cpp | 4 +- src/monattack.cpp | 188 +++++++++++++++++++++++++-------- src/mondeath.cpp | 39 +++++-- src/monmove.cpp | 5 +- src/npcmove.cpp | 11 +- src/player.cpp | 15 +++ src/ranged.cpp | 29 +++-- src/ranged_aoe.cpp | 10 +- src/trapfunc.cpp | 10 +- 18 files changed, 371 insertions(+), 123 deletions(-) diff --git a/src/activity_item_handling.cpp b/src/activity_item_handling.cpp index 7ed7db26c6bd..ed4f0d3db5c4 100644 --- a/src/activity_item_handling.cpp +++ b/src/activity_item_handling.cpp @@ -1025,7 +1025,7 @@ std::vector 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 ); } } diff --git a/src/character.cpp b/src/character.cpp index 6265c8d53b73..8a55d411507f 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -7872,7 +7872,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 ); } } diff --git a/src/explosion.cpp b/src/explosion.cpp index 6981efcc979a..ccf6b98a3217 100644 --- a/src/explosion.cpp +++ b/src/explosion.cpp @@ -440,7 +440,7 @@ static std::map do_blast_new( const tripoint &blast_cente for( const dist_point_pair &pair : blast_map ) { float distance; tripoint position; - tripoint last_position = position; + tripoint last_position = blast_center; std::tie( distance, position ) = pair; const std::vector line_of_movement = line_to( blast_center, position ); diff --git a/src/game.cpp b/src/game.cpp index bf7daad83350..17e823af67d8 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4602,6 +4602,8 @@ void game::knockback( std::vector &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 ); @@ -4614,7 +4616,7 @@ void game::knockback( std::vector &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 ) { @@ -4665,6 +4667,7 @@ void game::knockback( std::vector &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( tp ) ) { if( stun > 0 ) { @@ -4672,7 +4675,8 @@ void game::knockback( std::vector &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() ) ) { // 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 ) { @@ -4729,6 +4733,7 @@ void game::knockback( std::vector &traj, int stun, int dam_mult ) break; } targ->setpos( traj[i] ); + tp = traj[i]; } } else if( u.pos() == tp ) { if( stun > 0 ) { @@ -4739,7 +4744,8 @@ void game::knockback( std::vector &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 ) { @@ -4807,6 +4813,8 @@ void game::knockback( std::vector &traj, int stun, int dam_mult ) } else { u.setpos( traj[i] ); } + + tp = traj[i]; } } } @@ -5929,7 +5937,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; } @@ -10329,7 +10337,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 @@ -10340,16 +10347,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 = tripoint_zero; 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( pt ) ) { monster &critter = *mon_ptr; // Approximate critter's "stopping power" with its max hp @@ -10413,8 +10440,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(); diff --git a/src/iuse.cpp b/src/iuse.cpp index 5b4d300e3771..5ed6bc774871 100644 --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -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( dest ) ) { monster &critter = *mon_ptr; if( g->u.sees( dest ) && diff --git a/src/magic_spell_effect.cpp b/src/magic_spell_effect.cpp index 1a88a35ca047..cf305e7d7d72 100644 --- a/src/magic_spell_effect.cpp +++ b/src/magic_spell_effect.cpp @@ -97,14 +97,16 @@ static bool between_or_on( const point &a0, const point &a1, const point &d, con } // Builds line until obstructed or outside of region bound by near and far lines. Stores result in set static void build_line( spell_detail::line_iterable line, const tripoint &source, - const point &delta, const point &delta_perp, bool ( *test )( const tripoint & ), + const point &delta, const point &delta_perp, bool ( *test )( const tripoint &, const tripoint & ), std::set &result ) { + tripoint last_point = source; while( between_or_on( point_zero, delta, delta_perp, line.get() ) ) { - if( !test( source + line.get() ) ) { + if( !test( source + line.get(), last_point ) ) { break; } result.emplace( source + line.get() ); + last_point = source + line.get(); line.next(); } } @@ -163,10 +165,13 @@ static bool in_spell_aoe( const tripoint &start, const tripoint &end, const int return true; } const std::vector trajectory = line_to( start, end ); + tripoint last_point = start; for( const tripoint &pt : trajectory ) { - if( g->m.impassable( pt ) && !g->m.has_flag( "THIN_OBSTACLE", pt ) ) { + if( ( g->m.impassable( pt ) && !g->m.has_flag( "THIN_OBSTACLE", pt ) ) || + g->m.obstructed_by_vehicle_rotation( pt, last_point ) ) { return false; } + last_point = pt; } return true; } @@ -202,12 +207,15 @@ std::set spell_effect::spell_effect_cone( const spell &sp, const tripo } for( const tripoint &ep : end_points ) { std::vector trajectory = line_to( source, ep ); + tripoint last_point = source; for( const tripoint &tp : trajectory ) { - if( ignore_walls || g->m.passable( tp ) || g->m.has_flag( "THIN_OBSTACLE", tp ) ) { + if( ignore_walls || ( !g->m.obstructed_by_vehicle_rotation( tp, last_point ) && + ( g->m.passable( tp ) || g->m.has_flag( "THIN_OBSTACLE", tp ) ) ) ) { targets.emplace( tp ); } else { break; } + last_point = tp; } } // we don't want to hit ourselves in the blast! @@ -215,13 +223,14 @@ std::set spell_effect::spell_effect_cone( const spell &sp, const tripo return targets; } -static bool test_always_true( const tripoint & ) +static bool test_always_true( const tripoint &, const tripoint & ) { return true; } -static bool test_passable( const tripoint &p ) +static bool test_passable( const tripoint &p, const tripoint &prev ) { - return ( g->m.passable( p ) || g->m.has_flag( "THIN_OBSTACLE", p ) ); + return ( !g->m.obstructed_by_vehicle_rotation( prev, p ) && ( g->m.passable( p ) || + g->m.has_flag( "THIN_OBSTACLE", p ) ) ); } std::set spell_effect::spell_effect_line( const spell &, const tripoint &source, @@ -254,7 +263,8 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin // is delta aligned with, cw, or ccw of primary axis int delta_side = spell_detail::side_of( point_zero, axis_delta, delta ); - bool ( *test )( const tripoint & ) = ignore_walls ? test_always_true : test_passable; + bool ( *test )( const tripoint &, + const tripoint & ) = ignore_walls ? test_always_true : test_passable; // Canonical path from source to target, offset to local space std::vector path_to_target = line_to( point_zero, delta ); @@ -273,25 +283,30 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin // Add cw and ccw legs if( delta_side == 0 ) { // delta is already axis aligned, only need straight lines // cw leg + point prev_point = point_zero; for( const point &p : line_to( point_zero, unit_cw_perp_axis * cw_len ) ) { base_line.reset( p ); - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } // ccw leg + prev_point = point_zero; for( const point &p : line_to( point_zero, unit_cw_perp_axis * -ccw_len ) ) { base_line.reset( p ); - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } } else if( delta_side == 1 ) { // delta is cw of primary axis // ccw leg is behind perp axis + point prev_point = point_zero; for( const point &p : line_to( point_zero, unit_cw_perp_axis * -ccw_len ) ) { base_line.reset( p ); @@ -299,11 +314,13 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin while( spell_detail::side_of( point_zero, delta_perp, base_line.get() ) == 1 ) { base_line.next(); } - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } + prev_point = point_zero; // cw leg is before perp axis for( const point &p : line_to( point_zero, unit_cw_perp_axis * cw_len ) ) { base_line.reset( p ); @@ -313,13 +330,15 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin base_line.prev(); } base_line.next(); - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } } else if( delta_side == -1 ) { // delta is ccw of primary axis // ccw leg is before perp axis + point prev_point = point_zero; for( const point &p : line_to( point_zero, unit_cw_perp_axis * -ccw_len ) ) { base_line.reset( p ); @@ -328,11 +347,13 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin base_line.prev(); } base_line.next(); - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } + prev_point = point_zero; // cw leg is behind perp axis for( const point &p : line_to( point_zero, unit_cw_perp_axis * cw_len ) ) { base_line.reset( p ); @@ -341,10 +362,11 @@ std::set spell_effect::spell_effect_line( const spell &, const tripoin while( spell_detail::side_of( point_zero, delta_perp, base_line.get() ) == 1 ) { base_line.next(); } - if( !test( source + p ) ) { + if( !test( source + p, source + prev_point ) ) { break; } spell_detail::build_line( base_line, source, delta, delta_perp, test, result ); + prev_point = p; } } @@ -471,8 +493,10 @@ void spell_effect::projectile_attack( const spell &sp, Creature &caster, const tripoint &target ) { std::vector trajectory = line_to( caster.pos(), target ); + tripoint prev_point = caster.pos(); for( std::vector::iterator iter = trajectory.begin(); iter != trajectory.end(); iter++ ) { - if( g->m.impassable( *iter ) && !g->m.has_flag( "THIN_OBSTACLE", *iter ) ) { + if( ( g->m.impassable( *iter ) && !g->m.has_flag( "THIN_OBSTACLE", *iter ) ) || + g->m.obstructed_by_vehicle_rotation( prev_point, *iter ) ) { if( iter != trajectory.begin() ) { target_attack( sp, caster, *( iter - 1 ) ); } else { @@ -480,6 +504,7 @@ void spell_effect::projectile_attack( const spell &sp, Creature &caster, } return; } + prev_point = *iter; } target_attack( sp, caster, trajectory.back() ); } @@ -549,6 +574,8 @@ int area_expander::run( const tripoint ¢er ) // Number of nodes expanded. int expanded = 0; + map &here = get_map(); + while( !frontier.empty() ) { int best_index = frontier.top(); frontier.pop(); @@ -557,7 +584,8 @@ int area_expander::run( const tripoint ¢er ) for( size_t i = 0; i < 8; i++ ) { tripoint pt = best.position + point( x_offset[ i ], y_offset[ i ] ); - if( g->m.impassable( pt ) && !g->m.has_flag( "THIN_OBSTACLE", pt ) ) { + if( ( here.impassable( pt ) && !here.has_flag( "THIN_OBSTACLE", pt ) ) || + here.obstructed_by_vehicle_rotation( best.position, pt ) ) { continue; } diff --git a/src/map.cpp b/src/map.cpp index b9f9f63fea57..d2e1a5943340 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -5491,15 +5491,27 @@ void map::add_splatter_trail( const field_type_id &type, const tripoint &from, if( !type.id() ) { return; } - const auto trail = line_to( from, to ); + auto trail = line_to( from, to ); int remainder = trail.size(); - for( const auto &elem : trail ) { + tripoint last_point = from; + for( tripoint &elem : trail ) { add_splatter( type, elem ); remainder--; + if( obstructed_by_vehicle_rotation( last_point, elem ) ) { + if( one_in( 2 ) ) { + elem.x = last_point.x; + add_splatter( type, elem, remainder ); + } else { + elem.y = last_point.y; + add_splatter( type, elem, remainder ); + } + return; + } if( impassable( elem ) ) { // Blood splatters stop at walls. add_splatter( type, elem, remainder ); return; } + last_point = elem; } } @@ -6131,16 +6143,20 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, // Ugly `if` for now if( !fov_3d || F.z == T.z ) { + + point last_point = F.xy(); bresenham( F.xy(), T.xy(), bresenham_slope, - [this, &visible, &T]( const point & new_point ) { + [this, &visible, &T, &last_point]( const point & new_point ) { // Exit before checking the last square, it's still visible even if opaque. if( new_point.x == T.x && new_point.y == T.y ) { return false; } - if( !this->is_transparent( tripoint( new_point, T.z ) ) ) { + if( !this->is_transparent( tripoint( new_point, T.z ) ) || + obscured_by_vehicle_rotation( tripoint( last_point, T.z ), tripoint( new_point, T.z ) ) ) { visible = false; return false; } + last_point = new_point; return true; } ); skew_vision_cache.insert( 100000, key, visible ? 1 : 0 ); @@ -6158,7 +6174,7 @@ bool map::sees( const tripoint &F, const tripoint &T, const int range, // TODO: Allow transparent floors (and cache them!) if( new_point.z == last_point.z ) { - if( !this->is_transparent( new_point ) ) { + if( !this->is_transparent( new_point ) || obscured_by_vehicle_rotation( last_point, new_point ) ) { visible = false; return false; } @@ -6371,18 +6387,23 @@ bool map::clear_path( const tripoint &f, const tripoint &t, const int range, return false; // Out of range! } bool is_clear = true; + point last_point = f.xy(); bresenham( f.xy(), t.xy(), 0, - [this, &is_clear, cost_min, cost_max, &t]( const point & new_point ) { + [this, &is_clear, cost_min, cost_max, &t, &last_point]( const point & new_point ) { // Exit before checking the last square, it's still reachable even if it is an obstacle. if( new_point.x == t.x && new_point.y == t.y ) { return false; } const int cost = this->move_cost( new_point ); - if( cost < cost_min || cost > cost_max ) { + if( cost < cost_min || cost > cost_max || + get_map().obstructed_by_vehicle_rotation( tripoint( last_point, t.z ), tripoint( new_point, + t.z ) ) ) { is_clear = false; return false; } + + last_point = new_point; return true; } ); return is_clear; @@ -6404,7 +6425,8 @@ bool map::clear_path( const tripoint &f, const tripoint &t, const int range, // We have to check a weird case where the move is both vertical and horizontal if( new_point.z == last_point.z ) { const int cost = move_cost( new_point ); - if( cost < cost_min || cost > cost_max ) { + if( cost < cost_min || cost > cost_max || + get_map().obstructed_by_vehicle_rotation( last_point, new_point ) ) { is_clear = false; return false; } @@ -6413,14 +6435,16 @@ bool map::clear_path( const tripoint &f, const tripoint &t, const int range, const int max_z = std::max( new_point.z, last_point.z ); if( !has_floor_or_support( {new_point.xy(), max_z} ) ) { const int cost = move_cost( {new_point.xy(), last_point.z} ); - if( cost > cost_min && cost < cost_max ) { + if( cost > cost_min && cost < cost_max && + !get_map().obstructed_by_vehicle_rotation( last_point, new_point ) ) { this_clear = true; } } if( !this_clear && has_floor_or_support( {last_point.xy(), max_z} ) ) { const int cost = move_cost( {last_point.xy(), new_point.z} ); - if( cost > cost_min && cost < cost_max ) { + if( cost > cost_min && cost < cost_max && + !get_map().obstructed_by_vehicle_rotation( last_point, new_point ) ) { this_clear = true; } } @@ -6437,7 +6461,7 @@ bool map::clear_path( const tripoint &f, const tripoint &t, const int range, return is_clear; } -bool map::obstructed_by_vehicle_rotation( const tripoint &from, const tripoint &to ) +bool map::obstructed_by_vehicle_rotation( const tripoint &from, const tripoint &to ) const { const optional_vpart_position vp0 = veh_at( from ); vehicle *const veh0 = veh_pointer_or_null( vp0 ); @@ -6460,7 +6484,7 @@ bool map::obstructed_by_vehicle_rotation( const tripoint &from, const tripoint & } -bool map::obscured_by_vehicle_rotation( const tripoint &from, const tripoint &to ) +bool map::obscured_by_vehicle_rotation( const tripoint &from, const tripoint &to ) const { const optional_vpart_position vp0 = veh_at( from ); vehicle *const veh0 = veh_pointer_or_null( vp0 ); diff --git a/src/map.h b/src/map.h index 15420385b370..39dc9a4012ab 100644 --- a/src/map.h +++ b/src/map.h @@ -704,12 +704,12 @@ class map /** * Checks if a rotated vehicle is blocking diagonal movement, tripoints must be adjacent */ - bool obstructed_by_vehicle_rotation( const tripoint &from, const tripoint &to ); + bool obstructed_by_vehicle_rotation( const tripoint &from, const tripoint &to ) const; /** * Checks if a rotated vehicle is blocking diagonal vision, tripoints must be adjacent */ - bool obscured_by_vehicle_rotation( const tripoint &from, const tripoint &to ); + bool obscured_by_vehicle_rotation( const tripoint &from, const tripoint &to ) const; /** * Populates a vector of points that are reachable within a number of steps from a diff --git a/src/map_field.cpp b/src/map_field.cpp index 37ca920776a2..58ada964ebab 100644 --- a/src/map_field.cpp +++ b/src/map_field.cpp @@ -927,7 +927,7 @@ void map::process_fields_in_submap( submap *const current_submap, while( tries < 10 && cur.get_field_age() < 5_minutes && cur.get_field_intensity() > 1 ) { pnt.x = p.x + rng( -1, 1 ); pnt.y = p.y + rng( -1, 1 ); - if( passable( pnt ) ) { + if( passable( pnt ) && !obstructed_by_vehicle_rotation( p, pnt ) ) { add_field( pnt, fd_electricity, 1, cur.get_field_age() + 1_turns ); cur.set_field_intensity( cur.get_field_intensity() - 1 ); tries = 0; @@ -947,11 +947,12 @@ void map::process_fields_in_submap( submap *const current_submap, if( valid.empty() ) { tripoint dst( p + point( rng( -1, 1 ), rng( -1, 1 ) ) ); field_entry *elec = get_field( dst ).find_field( fd_electricity ); - if( passable( dst ) && elec != nullptr && + bool pass = passable( dst ) && !obstructed_by_vehicle_rotation( p, dst ); + if( pass && elec != nullptr && elec->get_field_intensity() < 3 ) { elec->set_field_intensity( elec->get_field_intensity() + 1 ); cur.set_field_intensity( cur.get_field_intensity() - 1 ); - } else if( passable( dst ) ) { + } else if( pass ) { add_field( dst, fd_electricity, 1, cur.get_field_age() + 1_turns ); } cur.set_field_intensity( cur.get_field_intensity() - 1 ); @@ -1996,8 +1997,9 @@ void map::propagate_field( const tripoint ¢er, const field_type_id &type, in closed.insert( pt ); continue; } - - open.push( { static_cast( rl_dist( center, pt ) ), pt } ); + if( !obstructed_by_vehicle_rotation( gp.second, pt ) ) { + open.push( { static_cast( rl_dist( center, pt ) ), pt } ); + } } } } diff --git a/src/mattack_actors.cpp b/src/mattack_actors.cpp index b208af733d1a..53fb8c23fc6f 100644 --- a/src/mattack_actors.cpp +++ b/src/mattack_actors.cpp @@ -122,11 +122,13 @@ bool leap_actor::call( monster &z ) const bool blocked_path = false; // check if monster has a clear path to the proposed point std::vector line = here.find_clear_path( z.pos(), dest ); + tripoint prev_point = z.pos(); for( auto &i : line ) { - if( here.impassable( i ) ) { + if( here.impassable( i ) || here.obstructed_by_vehicle_rotation( prev_point, i ) ) { blocked_path = true; break; } + prev_point = i; } // don't leap into water if you could drown (#38038) if( z.is_aquatic_danger( dest ) ) { diff --git a/src/monattack.cpp b/src/monattack.cpp index ece7733b95a0..1386915e0dc5 100644 --- a/src/monattack.cpp +++ b/src/monattack.cpp @@ -853,24 +853,39 @@ bool mattack::boomer( monster *z ) return false; } - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); + map &here = get_map(); + + std::vector line = here.find_clear_path( z->pos(), target->pos() ); // It takes a while z->moves -= 250; bool u_see = g->u.sees( *z ); if( u_see ) { add_msg( m_warning, _( "The %s spews bile!" ), z->name() ); } + tripoint prev_point = z->pos(); + bool obstructed = false; for( auto &i : line ) { - g->m.add_field( i, fd_bile, 1 ); + if( here.obstructed_by_vehicle_rotation( prev_point, i ) ) { + if( one_in( 2 ) ) { + i.x = prev_point.x; + } else { + i.y = prev_point.y; + } + obstructed = true; + } + + here.add_field( i, fd_bile, 1 ); + // If bile hit a solid tile, return. - if( g->m.impassable( i ) ) { - g->m.add_field( i, fd_bile, 3 ); + if( obstructed || here.impassable( i ) ) { + here.add_field( i, fd_bile, 3 ); if( g->u.sees( i ) ) { add_msg( _( "Bile splatters on the %s!" ), - g->m.tername( i ) ); + here.tername( i ) ); } return true; } + prev_point = i; } if( !target->uncanny_dodge() ) { ///\EFFECT_DODGE increases chance to avoid boomer effect @@ -897,22 +912,35 @@ bool mattack::boomer_glow( monster *z ) return false; } - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); + map &here = get_map(); + + std::vector line = here.find_clear_path( z->pos(), target->pos() ); // It takes a while z->moves -= 250; bool u_see = g->u.sees( *z ); if( u_see ) { add_msg( m_warning, _( "The %s spews bile!" ), z->name() ); } + tripoint prev_point = z->pos(); + bool obstructed = false; for( auto &i : line ) { - g->m.add_field( i, fd_bile, 1 ); - if( g->m.impassable( i ) ) { - g->m.add_field( i, fd_bile, 3 ); + if( here.obstructed_by_vehicle_rotation( prev_point, i ) ) { + if( one_in( 2 ) ) { + i.x = prev_point.x; + } else { + i.y = prev_point.y; + } + obstructed = true; + } + here.add_field( i, fd_bile, 1 ); + if( obstructed || here.impassable( i ) ) { + here.add_field( i, fd_bile, 3 ); if( g->u.sees( i ) ) { - add_msg( _( "Bile splatters on the %s!" ), g->m.tername( i ) ); + add_msg( _( "Bile splatters on the %s!" ), here.tername( i ) ); } return true; } + prev_point = i; } if( !target->uncanny_dodge() ) { ///\EFFECT_DODGE increases chance to avoid glowing boomer effect @@ -2565,16 +2593,20 @@ bool mattack::ranged_pull( monster *z ) return false; } + map &here = get_map(); + player *foe = dynamic_cast< player * >( target ); - std::vector line = g->m.find_clear_path( z->pos(), target->pos() ); + std::vector line = here.find_clear_path( z->pos(), target->pos() ); bool seen = g->u.sees( *z ); - + tripoint prev_point = z->pos(); for( auto &i : line ) { // Player can't be pulled though bars, furniture, cars or creatures // TODO: Add bashing? Currently a window is enough to prevent grabbing - if( !g->is_empty( i ) && i != z->pos() && i != target->pos() ) { + if( ( !g->is_empty( i ) || here.obstructed_by_vehicle_rotation( prev_point, i ) ) && + i != z->pos() && i != target->pos() ) { return false; } + prev_point = i; } z->moves -= 150; @@ -2613,7 +2645,7 @@ bool mattack::ranged_pull( monster *z ) if( foe != nullptr ) { if( foe->in_vehicle ) { - g->m.unboard_vehicle( foe->pos() ); + here.unboard_vehicle( foe->pos() ); } if( target->is_player() && ( pt.x < HALF_MAPSIZE_X || pt.y < HALF_MAPSIZE_Y || @@ -2632,7 +2664,7 @@ bool mattack::ranged_pull( monster *z ) } // The monster might drag a target that's not on it's z level // So if they leave them on open air, make them fall - g->m.creature_on_trap( *target ); + here.creature_on_trap( *target ); if( seen ) { if( z->type->bodytype == "human" || z->type->bodytype == "angel" ) { add_msg( _( "The %1$s's arms fly out and pull and grab %2$s!" ), z->name(), @@ -3662,27 +3694,38 @@ bool mattack::flamethrower( monster *z ) void mattack::flame( monster *z, Creature *target ) { int dist = rl_dist( z->pos(), target->pos() ); + + map &here = get_map(); if( target != &g->u ) { // friendly // It takes a while z->moves -= 500; - if( !g->m.sees( z->pos(), target->pos(), dist ) ) { + if( !here.sees( z->pos(), target->pos(), dist ) ) { // shouldn't happen debugmsg( "mattack::flame invoked on invisible target" ); } - std::vector traj = g->m.find_clear_path( z->pos(), target->pos() ); - + std::vector traj = here.find_clear_path( z->pos(), target->pos() ); + tripoint prev_point = z->pos(); for( auto &i : traj ) { + if( here.obstructed_by_vehicle_rotation( prev_point, i ) ) { + if( one_in( 2 ) ) { + i.x = prev_point.x; + } else { + i.y = prev_point.y; + } + } + // break out of attack if flame hits a wall // TODO: Z - if( g->m.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { + if( here.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { if( g->u.sees( i ) ) { add_msg( _( "The tongue of flame hits the %s!" ), - g->m.tername( i.xy() ) ); + here.tername( i.xy() ) ); } return; } - g->m.add_field( i, fd_fire, 1 ); + here.add_field( i, fd_fire, 1 ); + prev_point = i; } target->add_effect( effect_onfire, 8_turns, bp_torso ); @@ -3691,22 +3734,38 @@ void mattack::flame( monster *z, Creature *target ) // It takes a while z->moves -= 500; - if( !g->m.sees( z->pos(), target->pos(), dist + 1 ) ) { + if( !here.sees( z->pos(), target->pos(), dist + 1 ) ) { // shouldn't happen debugmsg( "mattack::flame invoked on invisible target" ); } - std::vector traj = g->m.find_clear_path( z->pos(), target->pos() ); - + std::vector traj = here.find_clear_path( z->pos(), target->pos() ); + tripoint prev_point = z->pos(); for( auto &i : traj ) { + if( here.obstructed_by_vehicle_rotation( prev_point, i ) ) { + tripoint intervening = i; + if( one_in( 2 ) ) { + intervening.x = prev_point.x; + } else { + intervening.y = prev_point.y; + } + if( here.hit_with_fire( tripoint( intervening.xy(), z->posz() ) ) ) { + if( g->u.sees( i ) ) { + add_msg( _( "The tongue of flame hits the %s!" ), + here.tername( intervening.xy() ) ); + } + return; + } + } // break out of attack if flame hits a wall - if( g->m.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { + if( here.hit_with_fire( tripoint( i.xy(), z->posz() ) ) ) { if( g->u.sees( i ) ) { add_msg( _( "The tongue of flame hits the %s!" ), - g->m.tername( i.xy() ) ); + here.tername( i.xy() ) ); } return; } - g->m.add_field( i, fd_fire, 1 ); + here.add_field( i, fd_fire, 1 ); + prev_point = i; } if( !target->uncanny_dodge() ) { target->add_effect( effect_onfire, 8_turns, bp_torso ); @@ -4064,14 +4123,27 @@ bool mattack::stretch_bite( monster *z ) z->moves -= 150; + tripoint prev_point = z->pos(); + bool obstructed = false; for( auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + + if( get_map().obstructed_by_vehicle_rotation( prev_point, pnt ) ) { + if( one_in( 2 ) ) { + pnt.x = prev_point.x; + } else { + pnt.y = prev_point.y; + } + obstructed = true; + } + + if( obstructed || g->m.impassable( pnt ) ) { z->add_effect( effect_stunned, 6_turns ); target->add_msg_player_or_npc( _( "The %1$s stretches its head at you, but bounces off the %2$s" ), _( "The %1$s stretches its head at , but bounces off the %2$s" ), z->name(), g->m.obstacle_name( pnt ) ); return true; } + prev_point = pnt; } bool uncanny = target->uncanny_dodge(); // Can we dodge the attack? Uses player dodge function % chance (melee.cpp) @@ -4347,19 +4419,33 @@ bool mattack::longswipe( monster *z ) if( rl_dist( z->pos(), target->pos() ) > 3 || !z->sees( *target ) ) { return false; } + map &here = get_map(); //Is there something impassable blocking the claw? - for( const auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + tripoint prev_point = z->pos(); + bool obstructed = false; + for( tripoint &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { + + if( here.obstructed_by_vehicle_rotation( prev_point, pnt ) ) { + if( one_in( 2 ) ) { + pnt.x = prev_point.x; + } else { + pnt.y = prev_point.y; + } + obstructed = true; + } + + if( obstructed || here.impassable( pnt ) ) { //If we're here, it's an nonadjacent attack, which is only attempted 1/5 of the time. if( !one_in( 5 ) ) { return false; } target->add_msg_player_or_npc( _( "The %1$s thrusts a claw at you, but it bounces off the %2$s!" ), _( "The %1$s thrusts a claw at , but it bounces off the %2$s!" ), - z->name(), g->m.obstacle_name( pnt ) ); + z->name(), here.obstacle_name( pnt ) ); z->mod_moves( -150 ); return true; } + prev_point = pnt; } if( !is_adjacent( z, target, true ) ) { @@ -4642,13 +4728,15 @@ bool mattack::riotbot( monster *z ) return false; } + map &here = get_map(); + player *foe = dynamic_cast( target ); if( calendar::once_every( 1_minutes ) ) { - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 4 ) ) { - if( g->m.passable( dest ) && - g->m.clear_path( z->pos(), dest, 3, 1, 100 ) ) { - g->m.add_field( dest, fd_relax_gas, rng( 1, 3 ) ); + for( const tripoint &dest : here.points_in_radius( z->pos(), 4 ) ) { + if( here.passable( dest ) && + here.clear_path( z->pos(), dest, 3, 1, 100 ) ) { + here.add_field( dest, fd_relax_gas, rng( 1, 3 ) ); } } } @@ -4782,10 +4870,10 @@ bool mattack::riotbot( monster *z ) add_msg( m_bad, _( "The robot sprays tear gas!" ) ); z->moves -= 200; - for( const tripoint &dest : g->m.points_in_radius( z->pos(), 2 ) ) { - if( g->m.passable( dest ) && - g->m.clear_path( z->pos(), dest, 3, 1, 100 ) ) { - g->m.add_field( dest, fd_tear_gas, rng( 1, 3 ) ); + for( const tripoint &dest : here.points_in_radius( z->pos(), 2 ) ) { + if( here.passable( dest ) && + here.clear_path( z->pos(), dest, 3, 1, 100 ) ) { + here.add_field( dest, fd_tear_gas, rng( 1, 3 ) ); } } @@ -4819,11 +4907,13 @@ bool mattack::riotbot( monster *z ) sounds::sound( z->pos(), 3, sounds::sound_t::combat, _( "fzzzzzt" ), false, "misc", "flash" ); std::vector traj = line_to( z->pos(), dest, 0, 0 ); + tripoint prev_point = z->pos(); for( auto &elem : traj ) { - if( !g->m.is_transparent( elem ) ) { + if( !here.is_transparent( elem ) || here.obscured_by_vehicle_rotation( prev_point, elem ) ) { break; } - g->m.add_field( elem, fd_dazzling, 1 ); + here.add_field( elem, fd_dazzling, 1 ); + prev_point = elem; } return true; @@ -5660,13 +5750,27 @@ bool mattack::stretch_attack( monster *z ) int dam = rng( 5, 10 ); z->moves -= 100; + tripoint prev_point = z->pos(); + bool bounce = false; for( auto &pnt : g->m.find_clear_path( z->pos(), target->pos() ) ) { - if( g->m.impassable( pnt ) ) { + if( g->m.obstructed_by_vehicle_rotation( prev_point, pnt ) ) { + bounce = true; + //50% chance of bouncing off each intervening tile + if( one_in( 2 ) ) { + pnt.x = prev_point.x; + } else { + pnt.y = prev_point.y; + } + } + if( bounce || g->m.impassable( pnt ) ) { target->add_msg_player_or_npc( _( "The %1$s thrusts its arm at you, but bounces off the %2$s." ), _( "The %1$s thrusts its arm at , but bounces off the %2$s." ), z->name(), g->m.obstacle_name( pnt ) ); return true; } + + prev_point = pnt; + } auto msg_type = target == &g->u ? m_warning : m_info; diff --git a/src/mondeath.cpp b/src/mondeath.cpp index 45073e5b616b..9a5b93186679 100644 --- a/src/mondeath.cpp +++ b/src/mondeath.cpp @@ -130,22 +130,36 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & // can't have more items in a pile than total items pile_size = std::min( chunk_amt, pile_size ); distance = std::abs( distance ); + map &here = get_map(); const item chunk( chunk_name, calendar::turn, pile_size ); for( int i = 0; i < chunk_amt; i += pile_size ) { bool drop_chunks = true; tripoint tarp( z.pos() + point( rng( -distance, distance ), rng( -distance, distance ) ) ); const auto traj = line_to( z.pos(), tarp ); - + tripoint prev_point = z.pos(); for( size_t j = 0; j < traj.size(); j++ ) { tarp = traj[j]; + + bool obstructed = false; + if( here.obstructed_by_vehicle_rotation( prev_point, tarp ) ) { + if( one_in( 2 ) ) { + tarp.x = prev_point.x; + } else { + tarp.y = prev_point.y; + } + obstructed = true; + } + if( one_in( 2 ) && z.bloodType() ) { - g->m.add_splatter( z.bloodType(), tarp ); + here.add_splatter( z.bloodType(), tarp ); } else if( z.gibType() ) { - g->m.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); + here.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); } - if( g->m.impassable( tarp ) ) { - g->m.bash( tarp, distance ); - if( g->m.impassable( tarp ) ) { + + + if( here.impassable( tarp ) ) { + here.bash( tarp, distance ); + if( here.impassable( tarp ) ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster), don't drop anything on it @@ -157,9 +171,14 @@ static void scatter_chunks( const itype_id &chunk_name, int chunk_amt, monster & break; } } + //Don't lower j until after it's used in bashing + if( obstructed ) { + j--; + } + prev_point = tarp; } if( drop_chunks ) { - g->m.add_item_or_charges( tarp, chunk ); + here.add_item_or_charges( tarp, chunk ); } } } @@ -366,7 +385,7 @@ void mdeath::fungus( monster &z ) fungal_effects fe( *g, g->m ); for( const tripoint &sporep : g->m.points_in_radius( z.pos(), 1 ) ) { // *NOPAD* - if( g->m.impassable( sporep ) ) { + if( g->m.impassable( sporep ) && !get_map().obstructed_by_vehicle_rotation( z.pos(), sporep ) ) { continue; } // z is dead, don't credit it with the kill @@ -607,11 +626,13 @@ void mdeath::focused_beam( monster &z ) tripoint p( p2, z.posz() ); std::vector traj = line_to( z.pos(), p, 0, 0 ); + tripoint last_point = z.pos(); for( auto &elem : traj ) { - if( !g->m.is_transparent( elem ) ) { + if( !g->m.is_transparent( elem ) || get_map().obscured_by_vehicle_rotation( last_point, elem ) ) { break; } g->m.add_field( elem, fd_dazzling, 2 ); + last_point = elem; } } diff --git a/src/monmove.cpp b/src/monmove.cpp index 2bcdd40196ec..708ecfd7edd7 100644 --- a/src/monmove.cpp +++ b/src/monmove.cpp @@ -1217,7 +1217,8 @@ tripoint monster::scent_move() continue; } if( g->m.valid_move( pos(), dest, can_bash, true ) && - ( can_move_to( dest ) || ( dest == g->u.pos() ) || + ( ( can_move_to( dest ) && !get_map().obstructed_by_vehicle_rotation( pos(), dest ) ) || + ( dest == g->u.pos() ) || ( can_bash && g->m.bash_rating( bash_estimate(), dest ) > 0 ) ) ) { if( ( !fleeing && smell > bestsmell ) || ( fleeing && smell < bestsmell ) ) { smoves.clear(); @@ -1766,7 +1767,7 @@ bool monster::push_to( const tripoint &p, const int boost, const size_t depth ) // Pushing into cars/windows etc. is harder const int movecost_penalty = g->m.move_cost( dest ) - 2; - if( movecost_penalty <= -2 ) { + if( movecost_penalty <= -2 || get_map().obstructed_by_vehicle_rotation( p, dest ) ) { // Can't push into unpassable terrain continue; } diff --git a/src/npcmove.cpp b/src/npcmove.cpp index 3e5d58443cfa..760e9c87aa2d 100644 --- a/src/npcmove.cpp +++ b/src/npcmove.cpp @@ -2704,8 +2704,8 @@ static cata::optional nearest_passable( const tripoint &p, const tripo const tripoint & r ) { return rl_dist( closest_to, l ) < rl_dist( closest_to, r ); } ); - auto iter = std::find_if( candidates.begin(), candidates.end(), [&here]( const tripoint & pt ) { - return here.passable( pt ); + auto iter = std::find_if( candidates.begin(), candidates.end(), [&here, &p]( const tripoint & pt ) { + return here.passable( pt ) && !here.obstructed_by_vehicle_rotation( p, pt ); } ); if( iter != candidates.end() ) { return *iter; @@ -3003,13 +3003,16 @@ void npc::pick_up_item() } const int dist_to_pickup = rl_dist( pos(), wanted_item_pos ); - if( dist_to_pickup > 1 && !path.empty() ) { + + bool cant_reach = dist_to_pickup > 1 || + get_map().obstructed_by_vehicle_rotation( pos(), wanted_item_pos ); + if( cant_reach && !path.empty() ) { add_msg( m_debug, "Moving; [%d, %d, %d] => [%d, %d, %d]", posx(), posy(), posz(), path[0].x, path[0].y, path[0].z ); move_to_next(); return; - } else if( dist_to_pickup > 1 && path.empty() ) { + } else if( cant_reach && path.empty() ) { add_msg( m_debug, "Can't find path" ); // This can happen, always do something fetching_item = false; diff --git a/src/player.cpp b/src/player.cpp index 3957267ed54b..1453def138c6 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1310,6 +1310,21 @@ void player::knock_back_to( const tripoint &to ) return; } + if( rl_dist( pos(), to ) < 2 && get_map().obstructed_by_vehicle_rotation( pos(), to ) ) { + tripoint intervening = to; + if( one_in( 2 ) ) { + intervening.x = pos().x; + } else { + intervening.y = pos().y; + } + + apply_damage( nullptr, bodypart_id( "torso" ), 3 ); + add_effect( effect_stunned, 2_turns ); + add_msg_player_or_npc( _( "You bounce off a %s!" ), _( " bounces off a %s!" ), + g->m.obstacle_name( intervening ) ); + return; + } + // First, see if we hit a monster if( monster *const critter = g->critter_at( to ) ) { deal_damage( critter, bodypart_id( "torso" ), damage_instance( DT_BASH, critter->type->size ) ); diff --git a/src/ranged.cpp b/src/ranged.cpp index 49079c036e3c..fe9535aa3eb4 100644 --- a/src/ranged.cpp +++ b/src/ranged.cpp @@ -1718,16 +1718,17 @@ int time_to_attack( const Character &p, const itype &firing ) static void cycle_action( item &weap, const tripoint &pos ) { + map &here = get_map(); // eject casings and linkages in random direction avoiding walls using player position as fallback std::vector tiles = closest_points_first( pos, 1 ); tiles.erase( tiles.begin() ); - tiles.erase( std::remove_if( tiles.begin(), tiles.end(), [&]( const tripoint & e ) { - return !g->m.passable( e ); + tiles.erase( std::remove_if( tiles.begin(), tiles.end(), [&pos, &here]( const tripoint & e ) { + return !here.passable( e ) || here.obstructed_by_vehicle_rotation( pos, e ); } ), tiles.end() ); tripoint eject = tiles.empty() ? pos : random_entry( tiles ); // for turrets try and drop casings or linkages directly to any CARGO part on the same tile - const optional_vpart_position vp = g->m.veh_at( pos ); + const optional_vpart_position vp = here.veh_at( pos ); std::vector cargo; if( vp && weap.has_flag( "VEHICLE" ) ) { cargo = vp->vehicle().get_parts_at( pos, "CARGO", part_status_flag::any ); @@ -1739,7 +1740,7 @@ static void cycle_action( item &weap, const tripoint &pos ) weap.put_in( item( casing ).set_flag( "CASING" ) ); } else { if( cargo.empty() ) { - g->m.add_item_or_charges( eject, item( casing ) ); + here.add_item_or_charges( eject, item( casing ) ); } else { vp->vehicle().add_item( *cargo.front(), item( casing ) ); } @@ -1757,7 +1758,7 @@ static void cycle_action( item &weap, const tripoint &pos ) linkage.set_flag( "CASING" ); weap.put_in( linkage ); } else if( cargo.empty() ) { - g->m.add_item_or_charges( eject, linkage ); + here.add_item_or_charges( eject, linkage ); } else { vp->vehicle().add_item( *cargo.front(), linkage ); } @@ -2091,21 +2092,31 @@ std::vector targetable_creatures( const Character &c, const int rang return false; } + map &here = get_map(); + // TODO: It should use projectile passability checks when finding path, not vision checks. - std::vector path = g->m.find_clear_path( c.pos(), critter.pos() ); + std::vector path = here.find_clear_path( c.pos(), critter.pos() ); + tripoint prev_point = c.pos(); for( const tripoint &point : path ) { - if( g->m.passable( point ) ) { + if( here.obstructed_by_vehicle_rotation( prev_point, point ) ) { + //Blocked by a rotated vehicle's walls + return false; + } + + prev_point = point; + + if( here.passable( point ) ) { // If it's passable, it doesn't block bullets continue; } - const vehicle *veh_at_point = veh_pointer_or_null( g->m.veh_at( point ) ); + const vehicle *veh_at_point = veh_pointer_or_null( here.veh_at( point ) ); if( veh_at_point && veh_at_point != veh_from_turret ) { // Vehicles don't have impassable-but-shootable-through parts return false; } - if( !g->m.has_flag_ter( TFLAG_TRANSPARENT, point ) ) { + if( !here.has_flag_ter( TFLAG_TRANSPARENT, point ) ) { // If it's transparent, it's either glass (fine) or reinforced glass (not fine) // Hack it with the more common case for now // TODO: Handle armored glass diff --git a/src/ranged_aoe.cpp b/src/ranged_aoe.cpp index 3912aa574a5d..d827124fcfab 100644 --- a/src/ranged_aoe.cpp +++ b/src/ranged_aoe.cpp @@ -59,7 +59,7 @@ void execute_shaped_attack( const shape &sh, const projectile &proj, Creature &a for( const tripoint &child : here.points_in_radius( origin, 1 ) ) { double coverage = sigdist_to_coverage( sh.distance_at( child ) ); - if( coverage > 0.0 ) { + if( coverage > 0.0 && !get_map().obstructed_by_vehicle_rotation( origin, child ) ) { open[child] = aoe_flood_node( origin, 1.0 ); queue.emplace( child, trig_dist_squared( origin, child ) ); } @@ -101,7 +101,8 @@ void execute_shaped_attack( const shape &sh, const projectile &proj, Creature &a if( current_coverage > 0.0 ) { for( const tripoint &child : here.points_in_radius( p, 1 ) ) { double coverage = sigdist_to_coverage( sh.distance_at( child ) ); - if( coverage > 0.0 && closed.count( child ) == 0 && + if( coverage > 0.0 && !get_map().obstructed_by_vehicle_rotation( p, child ) && + closed.count( child ) == 0 && ( open.count( child ) == 0 || open.at( child ).parent_coverage < current_coverage ) ) { open[child] = aoe_flood_node( p, current_coverage ); queue.emplace( child, trig_dist_squared( origin, child ) ); @@ -137,7 +138,7 @@ std::map expected_coverage( const shape &sh, const map &here, for( const tripoint &child : here.points_in_radius( origin, 1 ) ) { double coverage = sigdist_to_coverage( sh.distance_at( child ) ); - if( coverage > 0.0 ) { + if( coverage > 0.0 && !get_map().obstructed_by_vehicle_rotation( origin, child ) ) { open[child] = aoe_flood_node( origin, 1.0 ); queue.emplace( child, trig_dist_squared( origin, child ) ); } @@ -183,7 +184,8 @@ std::map expected_coverage( const shape &sh, const map &here, if( current_coverage > 0.0 ) { for( const tripoint &child : here.points_in_radius( p, 1 ) ) { double coverage = sigdist_to_coverage( sh.distance_at( child ) ); - if( coverage > 0.0 && closed.count( child ) == 0 && + if( coverage > 0.0 && !get_map().obstructed_by_vehicle_rotation( p, child ) && + closed.count( child ) == 0 && ( open.count( child ) == 0 || open.at( child ).parent_coverage < current_coverage ) ) { open[child] = aoe_flood_node( p, current_coverage ); queue.emplace( child, trig_dist_squared( origin, child ) ); diff --git a/src/trapfunc.cpp b/src/trapfunc.cpp index 6b707ca98857..fb6101dcda7c 100644 --- a/src/trapfunc.cpp +++ b/src/trapfunc.cpp @@ -1032,25 +1032,29 @@ static bool sinkhole_safety_roll( player *p, const itype_id &itemname, const int ///\EFFECT_DEX increases chance to attach grapnel, bullwhip, or rope when falling into a sinkhole ///\EFFECT_THROW increases chance to attach grapnel, bullwhip, or rope when falling into a sinkhole + + map &here = get_map(); + const int throwing_skill_level = p->get_skill_level( skill_throw ); const int roll = rng( throwing_skill_level, throwing_skill_level + p->str_cur + p->dex_cur ); if( roll < diff ) { p->add_msg_if_player( m_bad, _( "You fail to attach it…" ) ); p->use_amount( itemname, 1 ); - g->m.spawn_item( random_neighbor( p->pos() ), itemname ); + here.spawn_item( random_neighbor( p->pos() ), itemname ); return false; } std::vector safe; for( const tripoint &tmp : g->m.points_in_radius( p->pos(), 1 ) ) { - if( g->m.passable( tmp ) && g->m.tr_at( tmp ).loadid != tr_pit ) { + if( here.passable( tmp ) && !here.obstructed_by_vehicle_rotation( p->pos(), tmp ) && + here.tr_at( tmp ).loadid != tr_pit ) { safe.push_back( tmp ); } } if( safe.empty() ) { p->add_msg_if_player( m_bad, _( "There's nowhere to pull yourself to, and you sink!" ) ); p->use_amount( itemname, 1 ); - g->m.spawn_item( random_neighbor( p->pos() ), itemname ); + here.spawn_item( random_neighbor( p->pos() ), itemname ); return false; } else { p->add_msg_player_or_npc( m_good, _( "You pull yourself to safety!" ),