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

Fix bug where crouching affects lighting #38280

Merged
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
75 changes: 54 additions & 21 deletions src/lightmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,40 @@ bool map::build_transparency_cache( const int zlev )
return true;
}

bool map::build_vision_transparency_cache( const int zlev )
{
auto &map_cache = get_cache( zlev );
auto &transparency_cache = map_cache.transparency_cache;
auto &vision_transparency_cache = map_cache.vision_transparency_cache;

memcpy( &vision_transparency_cache, &transparency_cache, sizeof( transparency_cache ) );

const tripoint &p = g->u.pos();

if( p.z != zlev ) {
return false;
}

bool dirty = false;

bool is_crouching = g->u.movement_mode_is( CMM_CROUCH );
for( const tripoint &loc : points_in_radius( p, 1 ) ) {
if( loc == p ) {
// The tile player is standing on should always be visible
if( ( has_furn( p ) && !furn( p )->transparent ) || !ter( p )->transparent ) {
vision_transparency_cache[p.x][p.y] = LIGHT_TRANSPARENCY_CLEAR;
}
} else if( is_crouching && coverage( loc ) >= 30 ) {
// If we're crouching behind an obstacle, we can't see past it.
vision_transparency_cache[loc.x][loc.y] = LIGHT_TRANSPARENCY_SOLID;
map_cache.transparency_cache_dirty = true;
dirty = true;
}
}

return dirty;
}

void map::apply_character_light( player &p )
{
if( p.has_effect( effect_onfire ) ) {
Expand Down Expand Up @@ -670,9 +704,9 @@ template<int xx, int xy, int xz, int yx, int yy, int yz, int zz, typename T,
bool( *check )( const T &, const T & ),
T( *accumulate )( const T &, const T &, const int & )>
void cast_zlight_segment(
const std::array<T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<T> &output_caches,
const array_of_grids_of<const T> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &offset, int offset_distance,
T numerator = 1.0f, int row = 1,
float start_major = 0.0f, float end_major = 1.0f,
Expand All @@ -684,9 +718,9 @@ template<int xx, int xy, int xz, int yx, int yy, int yz, int zz, typename T,
bool( *check )( const T &, const T & ),
T( *accumulate )( const T &, const T &, const int & )>
void cast_zlight_segment(
const std::array<T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<T> &output_caches,
const array_of_grids_of<const T> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &offset, const int offset_distance,
const T numerator, const int row,
float start_major, const float end_major,
Expand Down Expand Up @@ -877,9 +911,9 @@ template<typename T, T( *calc )( const T &, const T &, const int & ),
bool( *check )( const T &, const T & ),
T( *accumulate )( const T &, const T &, const int & )>
void cast_zlight(
const std::array<T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<T> &output_caches,
const array_of_grids_of<const T> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &origin, const int offset_distance, const T numerator )
{
// Down
Expand Down Expand Up @@ -928,16 +962,15 @@ void cast_zlight(
// I can't figure out how to make implicit instantiation work when the parameters of
// the template-supplied function pointers are involved, so I'm explicitly instantiating instead.
template void cast_zlight<float, sight_calc, sight_check, accumulate_transparency>(
const std::array<float ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const float ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<float> &output_caches,
const array_of_grids_of<const float> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &origin, int offset_distance, float numerator );

template void cast_zlight<fragment_cloud, shrapnel_calc, shrapnel_check, accumulate_fragment_cloud>(
const std::array<fragment_cloud( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const fragment_cloud( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS>
&input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<fragment_cloud> &output_caches,
const array_of_grids_of<const fragment_cloud> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &origin, int offset_distance, fragment_cloud numerator );

template<int xx, int xy, int yx, int yy, typename T, typename Out,
Expand Down Expand Up @@ -1103,7 +1136,7 @@ castLightAll<fragment_cloud, fragment_cloud, shrapnel_calc, shrapnel_check,
void map::build_seen_cache( const tripoint &origin, const int target_z )
{
auto &map_cache = get_cache( target_z );
float ( &transparency_cache )[MAPSIZE_X][MAPSIZE_Y] = map_cache.transparency_cache;
float ( &transparency_cache )[MAPSIZE_X][MAPSIZE_Y] = map_cache.vision_transparency_cache;
float ( &seen_cache )[MAPSIZE_X][MAPSIZE_Y] = map_cache.seen_cache;
float ( &camera_cache )[MAPSIZE_X][MAPSIZE_Y] = map_cache.camera_cache;

Expand All @@ -1121,12 +1154,12 @@ void map::build_seen_cache( const tripoint &origin, const int target_z )
seen_cache, transparency_cache, origin.xy(), 0 );
} else {
// Cache the caches (pointers to them)
std::array<const float ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> transparency_caches;
std::array<float ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> seen_caches;
std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> floor_caches;
array_of_grids_of<const float> transparency_caches;
array_of_grids_of<float> seen_caches;
array_of_grids_of<const bool> floor_caches;
for( int z = -OVERMAP_DEPTH; z <= OVERMAP_HEIGHT; z++ ) {
auto &cur_cache = get_cache( z );
transparency_caches[z + OVERMAP_DEPTH] = &cur_cache.transparency_cache;
transparency_caches[z + OVERMAP_DEPTH] = &cur_cache.vision_transparency_cache;
seen_caches[z + OVERMAP_DEPTH] = &cur_cache.seen_cache;
floor_caches[z + OVERMAP_DEPTH] = &cur_cache.floor_cache;
std::uninitialized_fill_n(
Expand Down
21 changes: 4 additions & 17 deletions src/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7718,33 +7718,19 @@ void map::build_map_cache( const int zlev, bool skip_lightmap )
for( int z = minz; z <= maxz; z++ ) {
build_outside_cache( z );
seen_cache_dirty |= build_transparency_cache( z );
seen_cache_dirty |= build_vision_transparency_cache( zlev );
seen_cache_dirty |= build_floor_cache( z );
do_vehicle_caching( z );
}

const tripoint &p = g->u.pos();
bool is_crouching = g->u.movement_mode_is( CMM_CROUCH );
for( const tripoint &loc : points_in_radius( p, 1 ) ) {
if( loc == p ) {
// The tile player is standing on should always be transparent
if( ( has_furn( p ) && !furn( p ).obj().transparent ) || !ter( p ).obj().transparent ) {
get_cache( p.z ).transparency_cache[p.x][p.y] = LIGHT_TRANSPARENCY_CLEAR;
}
} else if( is_crouching && coverage( loc ) >= 30 ) {
// If we're crouching behind an obstacle, we can't see past it.
get_cache( loc.z ).transparency_cache[loc.x][loc.y] = LIGHT_TRANSPARENCY_SOLID;
get_cache( loc.z ).transparency_cache_dirty = true;
seen_cache_dirty = true;
}
}

if( seen_cache_dirty ) {
skew_vision_cache.clear();
}
// Initial value is illegal player position.
const tripoint &p = g->u.pos();
static tripoint player_prev_pos;
if( seen_cache_dirty || player_prev_pos != p ) {
build_seen_cache( g->u.pos(), zlev );
build_seen_cache( p, zlev );
player_prev_pos = p;
}
if( !skip_lightmap ) {
Expand Down Expand Up @@ -8243,6 +8229,7 @@ level_cache::level_cache()
std::fill_n( &outside_cache[0][0], map_dimensions, false );
std::fill_n( &floor_cache[0][0], map_dimensions, false );
std::fill_n( &transparency_cache[0][0], map_dimensions, 0.0f );
std::fill_n( &vision_transparency_cache[0][0], map_dimensions, 0.0f );
std::fill_n( &seen_cache[0][0], map_dimensions, 0.0f );
std::fill_n( &camera_cache[0][0], map_dimensions, 0.0f );
std::fill_n( &visibility_cache[0][0], map_dimensions, LL_DARK );
Expand Down
2 changes: 2 additions & 0 deletions src/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct level_cache {
bool outside_cache[MAPSIZE_X][MAPSIZE_Y];
bool floor_cache[MAPSIZE_X][MAPSIZE_Y];
float transparency_cache[MAPSIZE_X][MAPSIZE_Y];
float vision_transparency_cache[MAPSIZE_X][MAPSIZE_Y];
float seen_cache[MAPSIZE_X][MAPSIZE_Y];
float camera_cache[MAPSIZE_X][MAPSIZE_Y];
lit_level visibility_cache[MAPSIZE_X][MAPSIZE_Y];
Expand Down Expand Up @@ -1559,6 +1560,7 @@ class map
// Builds a transparency cache and returns true if the cache was invalidated.
// Used to determine if seen cache should be rebuilt.
bool build_transparency_cache( int zlev );
bool build_vision_transparency_cache( int zlev );
void build_sunlight_cache( int zlev );
public:
void build_outside_cache( int zlev );
Expand Down
9 changes: 6 additions & 3 deletions src/shadowcasting.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,17 @@ void castLightAll( Out( &output_cache )[MAPSIZE_X][MAPSIZE_Y],
const point &offset, int offsetDistance = 0,
T numerator = 1.0 );

template<typename T>
using array_of_grids_of = std::array<T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS>;

// TODO: Generalize the floor check, allow semi-transparent floors
template< typename T, T( *calc )( const T &, const T &, const int & ),
bool( *check )( const T &, const T & ),
T( *accumulate )( const T &, const T &, const int & ) >
void cast_zlight(
const std::array<T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &output_caches,
const std::array<const T( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &input_arrays,
const std::array<const bool ( * )[MAPSIZE_X][MAPSIZE_Y], OVERMAP_LAYERS> &floor_caches,
const array_of_grids_of<T> &output_caches,
const array_of_grids_of<const T> &input_arrays,
const array_of_grids_of<const bool> &floor_caches,
const tripoint &origin, int offset_distance, T numerator );

#endif
70 changes: 59 additions & 11 deletions tests/vision_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,27 @@
#include "game_constants.h"
#include "point.h"

enum class vision_test_flags {
none = 0,
no_3d = 1 << 0,
crouching = 1 << 1,
};

static vision_test_flags operator&( vision_test_flags l, vision_test_flags r )
{
return static_cast<vision_test_flags>(
static_cast<unsigned>( l ) & static_cast<unsigned>( r ) );
}

static bool operator!( vision_test_flags f )
{
return !static_cast<unsigned>( f );
}

static void full_map_test( const std::vector<std::string> &setup,
const std::vector<std::string> &expected_results,
const time_point &time )
const time_point &time,
const vision_test_flags flags )
{
const ter_id t_brick_wall( "t_brick_wall" );
const ter_id t_window_frame( "t_window_frame" );
Expand All @@ -40,6 +58,12 @@ static void full_map_test( const std::vector<std::string> &setup,
clear_map();
g->reset_light_level();

if( !!( flags & vision_test_flags::crouching ) ) {
g->u.set_movement_mode( character_movemode::CMM_CROUCH );
} else {
g->u.set_movement_mode( character_movemode::CMM_WALK );
}

REQUIRE( !g->u.is_blind() );
REQUIRE( !g->u.in_sleep_state() );
REQUIRE( !g->u.has_effect( effect_narcosis ) );
Expand Down Expand Up @@ -224,7 +248,7 @@ struct vision_test_case {
std::vector<std::string> setup;
std::vector<std::string> expected_results;
time_point time;
bool test_3d;
vision_test_flags flags;

static void transpose( std::vector<std::string> &v ) {
if( v.empty() ) {
Expand Down Expand Up @@ -261,7 +285,7 @@ struct vision_test_case {
}

void test() const {
full_map_test( setup, expected_results, time );
full_map_test( setup, expected_results, time, flags );
}

void test_all_transformations() const {
Expand All @@ -286,6 +310,7 @@ struct vision_test_case {
void test_all() const {
// Disabling 3d tests for now since 3d sight casting is actually
// different (it sees round corners more).
const bool test_3d = !( flags & vision_test_flags::no_3d );
if( test_3d ) {
INFO( "using 3d casting" );
fov_3d = true;
Expand Down Expand Up @@ -326,7 +351,7 @@ TEST_CASE( "vision_daylight", "[shadowcasting][vision]" )
"444",
},
midday,
true
vision_test_flags::none
};

t.test_all();
Expand All @@ -346,7 +371,7 @@ TEST_CASE( "vision_day_indoors", "[shadowcasting][vision]" )
"111",
},
midday,
true
vision_test_flags::none
};

t.test_all();
Expand All @@ -370,7 +395,8 @@ TEST_CASE( "vision_light_shining_in", "[shadowcasting][vision]" )
"1144444444",
},
midday,
false // 3D FOV gives different results here due to it seeing round corners more
// 3D FOV gives different results here due to it seeing round corners more
vision_test_flags::no_3d
};

t.test_all();
Expand All @@ -388,7 +414,7 @@ TEST_CASE( "vision_no_lights", "[shadowcasting][vision]" )
"111",
},
midnight,
true
vision_test_flags::none
};

t.test_all();
Expand All @@ -408,7 +434,7 @@ TEST_CASE( "vision_utility_light", "[shadowcasting][vision]" )
"444",
},
midnight,
true
vision_test_flags::none
};

t.test_all();
Expand All @@ -428,7 +454,7 @@ TEST_CASE( "vision_wall_obstructs_light", "[shadowcasting][vision]" )
"111",
},
midnight,
true
vision_test_flags::none
};

t.test_all();
Expand All @@ -452,7 +478,29 @@ TEST_CASE( "vision_wall_can_be_lit_by_player", "[shadowcasting][vision]" )
"66",
},
midnight,
true
vision_test_flags::none
};

t.test_all();
}

TEST_CASE( "vision_crouching_blocks_vision_but_not_light", "[shadowcasting][vision]" )
{
vision_test_case t {
{
"###",
"#u#",
"#=#",
" ",
},
{
"444",
"444",
"444",
"666",
},
midday,
vision_test_flags::crouching
};

t.test_all();
Expand Down Expand Up @@ -481,7 +529,7 @@ TEST_CASE( "vision_see_wall_in_moonlight", "[shadowcasting][vision]" )
},
// Want a night time
full_moon - time_past_midnight( full_moon ),
true
vision_test_flags::none
};

t.test_all();
Expand Down