Skip to content

Commit

Permalink
feat: crude working vehicle elevator
Browse files Browse the repository at this point in the history
(with debug warnings)
  • Loading branch information
scarf005 committed Sep 15, 2023
1 parent 781ecc4 commit 7d705cc
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 96 deletions.
96 changes: 0 additions & 96 deletions src/iexamine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ static const std::string flag_SPLINT( "SPLINT" );
static const std::string flag_VARSIZE( "VARSIZE" );
static const std::string flag_WALL( "WALL" );
static const std::string flag_WRITE_MESSAGE( "WRITE_MESSAGE" );
static const std::string flag_ELEVATOR( "ELEVATOR" );

// @TODO maybe make this a property of the item (depend on volume/type)
static const time_duration milling_time = 6_hours;
Expand Down Expand Up @@ -879,101 +878,6 @@ void iexamine::toilet( player &p, const tripoint &examp )
}
}

/**
* If underground, move 2 levels up else move 2 levels down. Stable movement between levels 0 and -2.
*/
void iexamine::elevator( player &p, const tripoint &examp )
{
map &here = get_map();
if( !query_yn( _( "Use the %s?" ), here.tername( examp ) ) ) {
return;
}
int movez = ( examp.z < 0 ? 2 : -2 );

tripoint original_floor_omt = ms_to_omt_copy( here.getabs( examp ) );
tripoint new_floor_omt = original_floor_omt + tripoint( point_zero, movez );


// first find critters in the destination elevator and move them out of the way
for( Creature &critter : g->all_creatures() ) {
if( critter.is_player() ) {
continue;
}

if( !here.has_flag( flag_ELEVATOR, critter.pos() ) ) {
continue;
}

tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) );
if( critter_omt != new_floor_omt ) {
continue;
}

for( const tripoint &candidate : closest_points_first( critter.pos(), 10 ) ) {
if( !here.has_flag( flag_ELEVATOR, candidate ) &&
here.passable( candidate ) &&
!g->critter_at( candidate ) ) {
critter.setpos( candidate );
break;
}
}
}

// TODO: do we have struct or pair to indicate from -> to?
const auto move_item = [&]( map_stack & items, const tripoint & src, const tripoint & dest ) {
for( auto it = items.begin(); it != items.end(); ) {
here.add_item_or_charges( dest, *it );
it = here.i_rem( src, it );
}
};

const auto first_elevator_tile = [&]( const tripoint & pos ) -> tripoint {
for( const tripoint &candidate : closest_points_first( pos, 10 ) )
{
if( here.has_flag( flag_ELEVATOR, candidate ) ) {
return candidate;
}
}
return pos;
};

// move along every item in the elevator
for( const tripoint &pos : closest_points_first( p.pos(), 10 ) ) {
if( here.has_flag( flag_ELEVATOR, pos ) ) {
map_stack items = here.i_at( pos );
tripoint dest = first_elevator_tile( pos + tripoint( 0, 0, movez ) );
move_item( items, pos, dest );
}
}

// move the player
g->vertical_move( movez, false );

// finally, bring along everyone who was in the elevator with the player
for( Creature &critter : g->all_creatures() ) {
if( critter.is_player() ) {
continue;
}

if( !here.has_flag( flag_ELEVATOR, critter.pos() ) ) {
continue;
}

tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) );
if( critter_omt != original_floor_omt ) {
continue;
}

for( const tripoint &candidate : closest_points_first( p.pos(), 10 ) ) {
if( here.has_flag( flag_ELEVATOR, candidate ) && candidate != p.pos() &&
!g->critter_at( candidate ) ) {
critter.setpos( candidate );
break;
}
}
}
}

/**
* Open or close gate.
*/
Expand Down
183 changes: 183 additions & 0 deletions src/iexamine_elevator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#include "game.h"
#include "iexamine.h"
#include "mapdata.h"
#include "output.h"
#include "player.h"
#include "coordinates.h"
#include "map.h"
#include "point.h"
#include "vpart_range.h"

namespace
{

using elevator_tiles = std::vector<tripoint>;
auto get_elevator_tiles( const Character &you ) -> elevator_tiles
{
const auto &here = get_map();
const auto &points = closest_points_first( you.pos(), SEEX - 1 );

elevator_tiles tiles;
std::copy_if( points.begin(), points.end(), std::back_inserter( tiles ),
[&here]( const tripoint & pos ) {
return here.has_flag( TFLAG_ELEVATOR, pos );
} );

return tiles;
}

enum class overlap_status { outside, inside, overlap };
auto vehicle_status( const wrapped_vehicle &veh, const elevator_tiles &tiles ) -> overlap_status
{
const auto &ps = veh.v->get_all_parts();
const int all_vparts_count = ps.part_count();
const int vparts_inside = std::count_if( ps.begin(), ps.end(), [&]( const vpart_reference & vp ) {
const tripoint p = veh.pos + vp.part().precalc[0];
const auto eit = std::find( tiles.cbegin(), tiles.cend(), p );
return eit != tiles.cend();
} );

if( vparts_inside == all_vparts_count ) {
return overlap_status::inside;
} else if( vparts_inside == 0 ) {
return overlap_status::outside;
} else {
return overlap_status::overlap;
}
}

struct elevator_vehicles {
bool blocking = false;
std::vector<vehicle *> v;
};

auto get_vehicles_on_elevator( const elevator_tiles &tiles ) -> elevator_vehicles
{
const VehicleList vehs = get_map().get_vehicles();
std::vector<vehicle *> ret;

for( const wrapped_vehicle &veh : vehs ) {
const auto status = vehicle_status( veh, tiles );
if( status == overlap_status::overlap ) {
return { true, { veh.v } };
}
if( status == overlap_status::inside ) {
ret.push_back( veh.v );
}
}
return { false, ret };
}

// auto choose_elevator_destination

} // namespace


/**
* If underground, move 2 levels up else move 2 levels down. Stable movement between levels 0 and -2.
*/
void iexamine::elevator( player &p, const tripoint &examp )
{
map &here = get_map();

const auto elevator_here = get_elevator_tiles( p );
const auto vehs = get_vehicles_on_elevator( elevator_here );
if( vehs.blocking ) {
popup( string_format( _( "The %s is blocking the elevator." ), vehs.v.front()->name ) );
return;
}

if( !query_yn( _( "Use the %s?" ), here.tername( examp ) ) ) {
return;
}

// TODO: port z level selection in
// https://github.com/CleverRaven/Cataclysm-DDA/pull/58840
const auto movez = tripoint( point_zero, examp.z < 0 ? 2 : -2 );

tripoint original_floor_omt = ms_to_omt_copy( here.getabs( examp ) );
tripoint new_floor_omt = original_floor_omt + movez;

// first find critters in the destination elevator and move them out of the way
for( Creature &critter : g->all_creatures() ) {
if( critter.is_player() ) {
continue;
}

if( !here.has_flag( TFLAG_ELEVATOR, critter.pos() ) ) {
continue;
}

tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) );
if( critter_omt != new_floor_omt ) {
continue;
}

for( const tripoint &candidate : closest_points_first( critter.pos(), 10 ) ) {
if( !here.has_flag( TFLAG_ELEVATOR, candidate ) &&
here.passable( candidate ) &&
!g->critter_at( candidate ) ) {
critter.setpos( candidate );
break;
}
}
}

// TODO: do we have struct or pair to indicate from -> to?
const auto move_item = [&]( map_stack & items, const tripoint & src, const tripoint & dest ) {
for( auto it = items.begin(); it != items.end(); ) {
here.add_item_or_charges( dest, *it );
it = here.i_rem( src, it );
}
};

const auto first_elevator_tile = [&]( const tripoint & pos ) -> tripoint {
for( const tripoint &candidate : closest_points_first( pos, 10 ) )
{
if( here.has_flag( TFLAG_ELEVATOR, candidate ) ) {
return candidate;
}
}
return pos;
};

// move along every item in the elevator
for( const tripoint &pos : closest_points_first( p.pos(), 10 ) ) {
if( here.has_flag( TFLAG_ELEVATOR, pos ) ) {
map_stack items = here.i_at( pos );
tripoint dest = first_elevator_tile( pos + movez );
move_item( items, pos, dest );
}
}

// move the player
g->vertical_move( movez.z, false );

// bring along everyone who was in the elevator with the player
for( Creature &critter : g->all_creatures() ) {
if( critter.is_player() ) {
continue;
}

if( !here.has_flag( TFLAG_ELEVATOR, critter.pos() ) ) {
continue;
}

tripoint critter_omt = ms_to_omt_copy( here.getabs( critter.pos() ) );
if( critter_omt != original_floor_omt ) {
continue;
}

for( const tripoint &candidate : closest_points_first( p.pos(), 10 ) ) {
if( here.has_flag( TFLAG_ELEVATOR, candidate ) && candidate != p.pos() &&
!g->critter_at( candidate ) ) {
critter.setpos( candidate );
break;
}
}
}

for( vehicle *v : vehs.v ) {
here.displace_vehicle( *v, movez );
}
}
1 change: 1 addition & 0 deletions src/mapdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static const std::unordered_map<std::string, ter_bitflags> ter_bitflags_map = {
{ "SUSPENDED", TFLAG_SUSPENDED }, // This furniture is suspended between other terrain, and will cause a cascading failure on break.
{ "FRIDGE", TFLAG_FRIDGE }, // This is an active fridge.
{ "FREEZER", TFLAG_FREEZER }, // This is an active freezer.
{ "ELEVATOR", TFLAG_ELEVATOR }, // This is an elevator.
}
};

Expand Down
1 change: 1 addition & 0 deletions src/mapdata.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ enum ter_bitflags : int {
TFLAG_SUSPENDED,
TFLAG_FRIDGE,
TFLAG_FREEZER,
TFLAG_ELEVATOR,

NUM_TERFLAGS
};
Expand Down

0 comments on commit 7d705cc

Please sign in to comment.