diff --git a/src/avatar.cpp b/src/avatar.cpp index 4a3a44011c051..2ba803fd47ba6 100644 --- a/src/avatar.cpp +++ b/src/avatar.cpp @@ -1302,7 +1302,9 @@ void avatar::set_movement_mode( const move_mode_id &new_mode ) // Enchantments based on move modes can stack inappropriately without a recalc here recalculate_enchantment_cache(); // crouching affects visibility - get_map().set_seen_cache_dirty( pos().z ); + //TODO: Replace with dirtying vision_transparency_cache + get_map().set_transparency_cache_dirty( pos_bub() ); + get_map().set_seen_cache_dirty( pos_bub().z() ); recoil = MAX_RECOIL; } else { add_msg( new_mode->change_message( false, get_steed_type() ) ); diff --git a/src/avatar_action.cpp b/src/avatar_action.cpp index 9e050b8421cfa..086e7b6e22728 100644 --- a/src/avatar_action.cpp +++ b/src/avatar_action.cpp @@ -70,6 +70,7 @@ static const efftype_id effect_incorporeal( "incorporeal" ); static const efftype_id effect_onfire( "onfire" ); static const efftype_id effect_pet( "pet" ); static const efftype_id effect_psi_stunned( "psi_stunned" ); +static const efftype_id effect_quadruped_full( "quadruped_full" ); static const efftype_id effect_ridden( "ridden" ); static const efftype_id effect_stunned( "stunned" ); static const efftype_id effect_winded( "winded" ); @@ -187,6 +188,16 @@ bool avatar_action::move( avatar &you, map &m, const tripoint_rel_ms &d ) return false; } + //TODO: Replace with dirtying vision_transparency_cache + //TODO: Really ugly bc we're not sure we're moving anywhere yet + const bool is_crouching = you.is_crouching(); + const bool low_profile = you.has_effect( effect_quadruped_full ) && + you.is_running(); + const bool is_prone = you.is_prone(); + if( is_crouching || is_prone || low_profile ) { + m.set_transparency_cache_dirty( d.z() ); + } + // If any leg broken without crutches and not already on the ground topple over if( ( !you.enough_working_legs() && !you.is_prone() && !( you.get_wielded_item() && you.get_wielded_item()->has_flag( flag_CRUTCHES ) ) ) ) { diff --git a/src/lightmap.cpp b/src/lightmap.cpp index 14a058206b2ec..c358968642a72 100644 --- a/src/lightmap.cpp +++ b/src/lightmap.cpp @@ -187,65 +187,88 @@ bool map::build_transparency_cache( const int zlev ) } } } - map_cache.transparency_cache_dirty.reset(); + //build_vision_transparency_cache copies the transparency_cache so don't reset transparency_cache_dirty until it's resolved return true; } bool map::build_vision_transparency_cache( int zlev ) { level_cache &map_cache = get_cache( zlev ); - cata::mdarray &transparency_cache = map_cache.transparency_cache; - cata::mdarray &vision_transparency_cache = map_cache.vision_transparency_cache; - - Character &player_character = get_player_character(); - const tripoint_bub_ms p = player_character.pos_bub(); - if( p.z() != zlev ) { - // Just copy the transparency cache and be done with it. - memcpy( &vision_transparency_cache, &transparency_cache, sizeof( transparency_cache ) ); + // We copy the transparency_cache so we need to recalc if it's dirty + if( map_cache.transparency_cache_dirty.none() /*&& map_cache.vision_transparency_cache_dirty.none()*/ ) { return false; } + const cata::mdarray &transparency_cache = map_cache.transparency_cache; + cata::mdarray &vision_transparency_cache = map_cache.vision_transparency_cache; + + // TODO: Should only copy if transparency_cache was dirty + memcpy( &vision_transparency_cache, &transparency_cache, sizeof( transparency_cache ) ); + + const Character &player_character = get_player_character(); + const tripoint_bub_ms p = player_character.pos_bub(); + const bool is_player_z = p.z() == zlev; + bool dirty = false; - std::vector solid_tiles; - - // This segment handles vision when the player is crouching or prone. It only checks adjacent tiles. - // If you change this, also consider creature::sees and map::obstacle_coverage. - const bool is_crouching = player_character.is_crouching(); - const bool low_profile = player_character.has_effect( effect_quadruped_full ) && - player_character.is_running(); - const bool is_prone = player_character.is_prone(); - - if( is_crouching || is_prone || low_profile ) { - for( const tripoint_bub_ms &loc : points_in_radius( p, 1 ) ) { - if( loc != p && coverage( loc ) >= 30 ) { - // If we're crouching or prone behind an obstacle, we can't see past it. - dirty |= vision_transparency_cache[loc.x()][loc.y()] != LIGHT_TRANSPARENCY_SOLID; - solid_tiles.emplace_back( loc ); + if( is_player_z ) { + // This segment handles vision when the player is crouching or prone. It only checks adjacent tiles. + // If you change this, also consider creature::sees and map::obstacle_coverage. + // TODO: Is fairly nonsense because it changes vision for everyone only (eg if you @ crouch behind the window W then the NPC N and monster M can't see each other bc the window is counted as opaque) + // .N. + // .@. + // #W# + // .M. + const bool is_crouching = player_character.is_crouching(); + const bool low_profile = player_character.has_effect( effect_quadruped_full ) && + player_character.is_running(); + const bool is_prone = player_character.is_prone(); + if( is_crouching || is_prone || low_profile ) { + for( const tripoint_bub_ms &loc : points_in_radius( p, 1 ) ) { + if( loc != p && coverage( loc ) >= 30 ) { + // If we're crouching or prone behind an obstacle, we can't see past it. + dirty |= vision_transparency_cache[loc.x()][loc.y()] != LIGHT_TRANSPARENCY_SOLID; + vision_transparency_cache[loc.x()][loc.y()] = LIGHT_TRANSPARENCY_SOLID; + } } } } - memcpy( &vision_transparency_cache, &transparency_cache, sizeof( transparency_cache ) ); - // This segment handles blocking vision through TRANSLUCENT flagged terrain. - // We don't need to deal with cache dirtying, because that was handled when the terrain was changed. - for( const tripoint_bub_ms &loc : points_in_radius( p, MAX_VIEW_DISTANCE ) ) { - if( map::ter( loc ).obj().has_flag( ter_furn_flag::TFLAG_TRANSLUCENT ) && loc != p ) { - vision_transparency_cache[loc.x()][loc.y()] = LIGHT_TRANSPARENCY_SOLID; + // Traverse the submaps in order (else map::ter() calls get_submap each time) + for( int smx = 0; smx < my_MAPSIZE; ++smx ) { + for( int smy = 0; smy < my_MAPSIZE; ++smy ) { + const submap *cur_submap = get_submap_at_grid( tripoint_rel_sm{smx, smy, zlev} ); + if( cur_submap == nullptr ) { + debugmsg( "Tried to build transparency cache at (%d,%d,%d) but the submap is not loaded", smx, smy, + zlev ); + continue; + } + if( !map_cache.transparency_cache_dirty[smx * MAPSIZE + smy] ) { + continue; + } + for( int smi = 0; smi < SEEX; smi++ ) { + for( int smj = 0; smj < SEEY; smj++ ) { + if( cur_submap->get_ter( point_sm_ms{smi, smj} ).obj().has_flag( + ter_furn_flag::TFLAG_TRANSLUCENT ) ) { + const int i = smi + ( smx * SEEX ); + const int j = smj + ( smy * SEEY ); + dirty |= vision_transparency_cache[i][j] != LIGHT_TRANSPARENCY_SOLID; + vision_transparency_cache[i][j] = LIGHT_TRANSPARENCY_SOLID; + } + } + } } } // The tile player is standing on should always be visible - if( inbounds( p ) ) { + // Shouldn't this be handled in the player's seen cache instead?? + if( is_player_z && inbounds( p ) ) { vision_transparency_cache[p.x()][p.y()] = LIGHT_TRANSPARENCY_OPEN_AIR; } - for( const tripoint_bub_ms loc : solid_tiles ) { - vision_transparency_cache[loc.x()][loc.y()] = LIGHT_TRANSPARENCY_SOLID; - } - + map_cache.transparency_cache_dirty.reset(); return dirty; }