Skip to content

Commit

Permalink
Merge pull request #38280 from jbytheway/crouching_affects_lighting
Browse files Browse the repository at this point in the history
Fix bug where crouching affects lighting
  • Loading branch information
Rivet-the-Zombie authored Feb 24, 2020
2 parents f8c79aa + 9528517 commit bd3524c
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 52 deletions.
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

0 comments on commit bd3524c

Please sign in to comment.