Skip to content

Commit

Permalink
feat(port): allow vertical movement for avatar in water (cataclysmbnt…
Browse files Browse the repository at this point in the history
…eam#3764)

* Allow vertical movement for avatar in water

* Fix assumptions by visitable tests about the map

* Entering water cube immediately submerges

---------

Co-authored-by: Jason Jones <jasonedwardjones@gmail.com>
  • Loading branch information
Vollch and ralreegorganon authored Nov 27, 2023
1 parent faa472c commit 3c060a0
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 35 deletions.
6 changes: 3 additions & 3 deletions data/json/furniture_and_terrain/terrain-liquids.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"looks_like": "t_water_sh",
"color": "blue",
"move_cost": 8,
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "FISHABLE" ],
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "FISHABLE", "GOES_DOWN" ],
"connects_to": "WATER",
"examine_action": "water_source"
},
Expand Down Expand Up @@ -276,7 +276,7 @@
"symbol": "~",
"color": "blue",
"move_cost": 8,
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "GOES_DOWN", "GOES_UP" ],
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "WATER_CUBE", "GOES_DOWN", "GOES_UP" ],
"connects_to": "WATER",
"examine_action": "water_source"
},
Expand All @@ -290,7 +290,7 @@
"looks_like": "t_sand",
"color": "blue",
"move_cost": 8,
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "GOES_UP" ],
"flags": [ "TRANSPARENT", "LIQUID", "NO_SCENT", "SWIMMABLE", "DEEP_WATER", "WATER_CUBE", "GOES_UP" ],
"connects_to": "WATER",
"examine_action": "water_source"
},
Expand Down
3 changes: 2 additions & 1 deletion doc/src/content/docs/en/mod/json/reference/json_flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,8 @@ List of known flags, used in both `terrain.json` and `furniture.json`.
- `CONSOLE` Used as a computer.
- `CONTAINER` Items on this square are hidden until looted by the player.
- `DECONSTRUCT` Can be deconstructed.
- `DEEP_WATER`
- `DEEP_WATER` Deep enough to submerge things
- `WATER_CUBE` Water tile that is entirely water
- `DESTROY_ITEM` Items that land here are destroyed. See also `NOITEM`
- `DIFFICULT_Z` Most zombies will not be able to follow you up this terrain ( i.e a ladder )
- `DIGGABLE_CAN_DEEPEN` Diggable location can be dug again to make deeper (e.g. shallow pit to deep
Expand Down
4 changes: 4 additions & 0 deletions src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,10 @@ void avatar_action::swim( map &m, avatar &you, const tripoint &p )
add_msg( _( "The water washes off the glowing goo!" ) );
you.remove_effect( effect_glowing );
}
if( m.has_flag( TFLAG_WATER_CUBE, p ) && !you.is_underwater() ) {
you.oxygen = 30 + 2 * you.str_cur;
you.set_underwater( true );
}
int movecost = you.swim_speed();
you.practice( skill_swimming, you.is_underwater() ? 2 : 1 );
if( movecost >= 500 ) {
Expand Down
136 changes: 105 additions & 31 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10032,38 +10032,12 @@ void game::vertical_move( int movez, bool force, bool peeking )
}
}

// > and < are used for diving underwater.
if( m.has_flag( "SWIMMABLE", u.pos() ) && m.has_flag( TFLAG_DEEP_WATER, u.pos() ) ) {
if( movez == -1 ) {
if( u.is_underwater() ) {
add_msg( m_info, _( "You are already underwater!" ) );
return;
}
if( u.worn_with_flag( flag_FLOTATION ) ) {
add_msg( m_info, _( "You can't dive while wearing a flotation device." ) );
return;
}
u.set_underwater( true );
///\EFFECT_STR increases breath-holding capacity while diving
u.oxygen = 30 + 2 * u.str_cur;
add_msg( _( "You dive underwater!" ) );
} else {
if( u.swim_speed() < 500 || u.shoe_type_count( itype_swim_fins ) ) {
u.set_underwater( false );
add_msg( _( "You surface." ) );
} else {
add_msg( m_info, _( "You try to surface but can't!" ) );
}
}
u.moves -= 100;
return;
}

// Force means we're going down, even if there's no staircase, etc.
bool climbing = false;
int move_cost = 100;
tripoint stairs( u.posx(), u.posy(), u.posz() + movez );
if( m.has_zlevels() && !force && movez == 1 && !m.has_flag( "GOES_UP", u.pos() ) ) {
if( m.has_zlevels() && !force && movez == 1 && !m.has_flag( "GOES_UP", u.pos() ) &&
!u.is_underwater() ) {
// Climbing
if( m.has_floor_or_support( stairs ) ) {
add_msg( m_info, _( "You can't climb here - there's a ceiling above your head." ) );
Expand Down Expand Up @@ -10126,10 +10100,12 @@ void game::vertical_move( int movez, bool force, bool peeking )
}
}

if( !force && movez == -1 && !m.has_flag( "GOES_DOWN", u.pos() ) ) {
if( !force && movez == -1 && !m.has_flag( "GOES_DOWN", u.pos() ) &&
!u.is_underwater() ) {
add_msg( m_info, _( "You can't go down here!" ) );
return;
} else if( !climbing && !force && movez == 1 && !m.has_flag( "GOES_UP", u.pos() ) ) {
} else if( !climbing && !force && movez == 1 && !m.has_flag( "GOES_UP", u.pos() ) &&
!u.is_underwater() ) {
add_msg( m_info, _( "You can't go up here!" ) );
return;
}
Expand Down Expand Up @@ -10205,10 +10181,101 @@ void game::vertical_move( int movez, bool force, bool peeking )
maybetmp.load( tripoint( get_levx(), get_levy(), z_after ), false );
}

bool swimming = false;
bool surfacing = false;
bool submerging = false;
// > and < are used for diving underwater.
if( m.has_flag( TFLAG_SWIMMABLE, u.pos() ) ) {
swimming = true;
const ter_id &target_ter = m.ter( u.pos() + tripoint( 0, 0, movez ) );

// If we're in a water tile that has both air above and deep enough water to submerge in...
if( m.has_flag( TFLAG_DEEP_WATER, u.pos() ) &&
!m.has_flag( TFLAG_WATER_CUBE, u.pos() ) ) {
// ...and we're trying to swim down
if( movez == -1 ) {
// ...and we're already submerged
if( u.is_underwater() ) {
// ...and there's more water beneath us.
if( target_ter->has_flag( TFLAG_WATER_CUBE ) ) {
// Then go ahead and move down.
add_msg( _( "You swim down." ) );
} else {
// There's no more water beneath us.
add_msg( m_info,
_( "You are already underwater and there is no more water beneath you to swim down!" ) );
return;
}
}
// ...and we're not already submerged.
else {
// Check for a flotation device first before allowing us to submerge.
if( u.worn_with_flag( flag_FLOTATION ) ) {
add_msg( m_info, _( "You can't dive while wearing a flotation device." ) );
return;
}

// Then dive under the surface.
u.oxygen = 30 + 2 * u.str_cur;
u.set_underwater( true );
add_msg( _( "You dive underwater!" ) );
submerging = true;
}
}
// ...and we're trying to surface
else if( movez == 1 ) {
// ... and we're already submerged
if( u.is_underwater() ) {
if( u.swim_speed() < 500 || u.shoe_type_count( itype_swim_fins ) ) {
u.set_underwater( false );
add_msg( _( "You surface." ) );
surfacing = true;
} else {
add_msg( m_info, _( "You try to surface but can't!" ) );
return;
}
}
}
}
// If we're in a water tile that is entirely water
else if( m.has_flag( TFLAG_WATER_CUBE, u.pos() ) ) {
// If you're at this point, you should already be underwater, but force that to be the case.
if( !u.is_underwater() ) {
u.oxygen = 30 + 2 * u.str_cur;
u.set_underwater( true );
}

// ...and we're trying to swim down
if( movez == -1 ) {
// ...and there's more water beneath us.
if( target_ter->has_flag( TFLAG_WATER_CUBE ) ) {
// Then go ahead and move down.
add_msg( _( "You swim down." ) );
} else {
add_msg( m_info,
_( "You are already underwater and there is no more water beneath you to swim down!" ) );
return;
}
}
// ...and we're trying to move up
else if( movez == 1 ) {
// ...and there's more water above us us.
if( target_ter->has_flag( TFLAG_WATER_CUBE ) ||
target_ter->has_flag( TFLAG_DEEP_WATER ) ) {
// Then go ahead and move up.
add_msg( _( "You swim up." ) );
} else {
add_msg( m_info, _( "You are already underwater and there is no water above you to swim up!" ) );
return;
}
}
}
}

// Find the corresponding staircase
bool rope_ladder = false;
// TODO: Remove the stairfinding, make the mapgen gen aligned maps
if( !force && !climbing ) {
if( !force && !climbing && !swimming ) {
const std::optional<tripoint> pnt = find_or_make_stairs( maybetmp, z_after, rope_ladder, peeking );
if( !pnt ) {
return;
Expand Down Expand Up @@ -10300,6 +10367,13 @@ void game::vertical_move( int movez, bool force, bool peeking )
m.unboard_vehicle( np->pos() );
}
}

if( surfacing || submerging ) {
// Surfacing and submerging don't actually move us anywhere, and just
// toggle our underwater state in the same location.
return;
}

const tripoint old_pos = g->u.pos();
point submap_shift;
vertical_shift( z_after );
Expand Down
1 change: 1 addition & 0 deletions src/mapdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ static const std::unordered_map<std::string, ter_bitflags> ter_bitflags_map = {
{ "WALL", TFLAG_WALL }, // Badly defined. Used for roof support, mapgen, and fungalization result.
{ "NO_SCENT", TFLAG_NO_SCENT }, // cannot have scent values, which prevents scent diffusion through this tile
{ "DEEP_WATER", TFLAG_DEEP_WATER }, // Deep enough to submerge things
{ "WATER_CUBE", TFLAG_WATER_CUBE }, // Water tile that is entirely water
{ "CURRENT", TFLAG_CURRENT }, // Water is flowing.
{ "HARVESTED", TFLAG_HARVESTED }, // harvested. will not bear fruit.
{ "PERMEABLE", TFLAG_PERMEABLE }, // gases can flow through.
Expand Down
1 change: 1 addition & 0 deletions src/mapdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ enum ter_bitflags : int {
TFLAG_UNSTABLE,
TFLAG_WALL,
TFLAG_DEEP_WATER,
TFLAG_WATER_CUBE,
TFLAG_CURRENT,
TFLAG_HARVESTED,
TFLAG_PERMEABLE,
Expand Down
22 changes: 22 additions & 0 deletions tests/map_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ void build_test_map( const ter_id &terrain )
g->m.build_map_cache( 0, true );
}

void build_water_test_map( const ter_id &surface, const ter_id &mid, const ter_id &bottom )
{
constexpr int z_surface = 0;
constexpr int z_bottom = -2;

map &here = get_map();
for( const tripoint &p : here.points_in_rectangle( tripoint_zero,
tripoint( MAPSIZE * SEEX, MAPSIZE * SEEY, z_bottom ) ) ) {

if( p.z == z_surface ) {
here.ter_set( p, surface );
} else if( p.z < z_surface && p.z > z_bottom ) {
here.ter_set( p, mid );
} else if( p.z == z_bottom ) {
here.ter_set( p, bottom );
}
}

here.invalidate_map_cache( 0 );
here.build_map_cache( 0, true );
}

void set_time( const time_point &time )
{
calendar::turn = time;
Expand Down
1 change: 1 addition & 0 deletions tests/map_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ void put_player_underground();
monster &spawn_test_monster( const std::string &monster_type, const tripoint &start );
void clear_vehicles();
void build_test_map( const ter_id &terrain );
void build_water_test_map( const ter_id &surface, const ter_id &mid, const ter_id &bottom );
void set_time( const time_point &time );

#endif // CATA_TESTS_MAP_HELPERS_H
1 change: 1 addition & 0 deletions tests/player_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ void clear_character( player &dummy, bool debug_storage )
// Make sure we don't carry around weird effects.
dummy.clear_effects(); // mark effects for removal
dummy.process_effects(); // actually remove them
dummy.set_underwater( false );

// Make stats nominal.
dummy.str_max = 8;
Expand Down
2 changes: 2 additions & 0 deletions tests/visitable_remove_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "item_contents.h"
#include "itype.h"
#include "map.h"
#include "map_helpers.h"
#include "map_selector.h"
#include "player.h"
#include "point.h"
Expand Down Expand Up @@ -55,6 +56,7 @@ TEST_CASE( "visitable_remove", "[visitable]" )
p.inv_clear();
p.remove_primary_weapon();
p.wear_item( item::spawn( "backpack" ) ); // so we don't drop anything
clear_map();

// check if all tiles within radius are loaded within current submap and passable
const auto suitable = []( const tripoint & pos, const int radius ) {
Expand Down
Loading

0 comments on commit 3c060a0

Please sign in to comment.