-
Notifications
You must be signed in to change notification settings - Fork 277
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(port): move vehicles in elevator (#3151)
* refactor: flatten nested conditions * feat: utility function for point rotation * feat: add elevator to ter_bitflags * feat(port): move vehicles in elevator DDA PR: CleverRaven/Cataclysm-DDA#58840 Co-authored-by: andrei <[email protected]> * refactor: split into functions * fix: negative retval `-1`confuses uilist prevent exciting magic numbers from happening Co-authored-by: andrei <[email protected]> * fix: check vehicles in destination too prevents exciting amalgamations from happening * fix: include headers make MSYS2 happy --------- Co-authored-by: andrei <[email protected]> Co-authored-by: andrei <[email protected]>
- Loading branch information
1 parent
503798f
commit 4e48081
Showing
6 changed files
with
309 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#include "game.h" | ||
#include "iexamine.h" | ||
#include "mapdata.h" | ||
#include "output.h" | ||
#include "omdata.h" | ||
#include "overmapbuffer.h" | ||
#include "player.h" | ||
#include "coordinates.h" | ||
#include "map.h" | ||
#include "point.h" | ||
#include "ui.h" | ||
#include "vpart_range.h" | ||
#include "point_rotate.h" | ||
namespace | ||
{ | ||
|
||
// still not sure whether there's a utility function for this | ||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) | ||
auto move_item( map &here, const tripoint &src, const tripoint &dest ) -> void | ||
{ | ||
map_stack items = here.i_at( src ); | ||
for( auto it = items.begin(); it != items.end(); ) { | ||
here.add_item_or_charges( dest, *it ); | ||
it = here.i_rem( src, it ); | ||
} | ||
}; | ||
|
||
namespace elevator | ||
{ | ||
|
||
using tiles = std::vector<tripoint>; | ||
|
||
auto here( 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; | ||
} | ||
|
||
auto dest( const elevator::tiles &elevator_here, | ||
const tripoint &sm_orig, | ||
int turns, | ||
int movez ) -> elevator::tiles | ||
{ | ||
elevator::tiles tiles; | ||
std::transform( elevator_here.begin(), elevator_here.end(), std::back_inserter( tiles ), | ||
[turns, &sm_orig, movez]( tripoint const & p ) { | ||
return rotate_point_sm( { p.xy(), movez }, sm_orig, turns ); | ||
} ); | ||
|
||
return tiles; | ||
} | ||
|
||
auto choose_floor( const tripoint &examp, const tripoint_abs_omt &this_omt, | ||
const tripoint &sm_orig ) -> int | ||
{ | ||
constexpr int retval_offset = 10000; // workaround for uilist retval autoassign when retval == -1 | ||
const auto this_floor = _( " (this floor)" ); | ||
|
||
map &here = get_map(); | ||
uilist choice; | ||
choice.title = _( "Please select destination floor" ); | ||
for( int z = OVERMAP_HEIGHT; z >= -OVERMAP_DEPTH; z-- ) { | ||
const tripoint_abs_omt that_omt{ this_omt.xy(), z }; | ||
const int delta = get_rot_delta( this_omt, that_omt ); | ||
const tripoint zp = | ||
rotate_point_sm( { examp.xy(), z }, sm_orig, delta ); | ||
|
||
if( here.ter( zp )->examine != &iexamine::elevator ) { | ||
continue; | ||
} | ||
const std::string omt_name = overmap_buffer.ter_existing( that_omt )->get_name(); | ||
const auto floor_name = z == examp.z ? this_floor : ""; | ||
const std::string name = string_format( "%3iF %s%s", z, omt_name, floor_name ); | ||
|
||
choice.addentry( z + retval_offset, z != examp.z, MENU_AUTOASSIGN, name ); | ||
} | ||
choice.query(); | ||
return choice.ret - retval_offset; | ||
} | ||
|
||
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 vehicles_on( 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 warn_blocking( const elevator_vehicles &vehs, std::string_view location ) -> void | ||
{ | ||
const auto &first_veh_name = vehs.v.front()->name; | ||
popup( string_format( _( "%1$s %2$s is blocking the elevator." ), first_veh_name, location ) ); | ||
} | ||
|
||
auto move_creatures_away( const elevator::tiles &dest ) -> void | ||
{ | ||
map &here = get_map(); | ||
|
||
const auto is_movable = [&]( const tripoint & candidate ) { | ||
return !here.has_flag( TFLAG_ELEVATOR, candidate ) | ||
&& here.passable( candidate ) | ||
&& !g->critter_at( candidate ); | ||
}; | ||
|
||
for( Creature &critter : g->all_creatures() ) { | ||
const tripoint local_pos = here.getlocal( here.getglobal( critter.pos() ) ); | ||
|
||
const auto eit = std::find( dest.cbegin(), dest.cend(), local_pos ); | ||
if( eit == dest.cend() ) { | ||
continue; | ||
} | ||
|
||
const auto xs = closest_points_first( *eit, 10 ); | ||
const auto candidate = std::find_if( xs.begin(), xs.end(), is_movable ); | ||
if( candidate == xs.end() ) { | ||
continue; | ||
} | ||
critter.setpos( *candidate ); | ||
} | ||
} | ||
|
||
auto move_items( const elevator::tiles from, const elevator::tiles dest ) -> void | ||
{ | ||
map &here = get_map(); | ||
|
||
for( decltype( from )::size_type i = 0; i < from.size(); i++ ) { | ||
const tripoint &src = from[i]; | ||
move_item( here, src, dest[i] ); | ||
} | ||
} | ||
|
||
auto move_creatures( const elevator::tiles from, const elevator::tiles dest ) -> void | ||
{ | ||
for( Creature &critter : g->all_creatures() ) { | ||
const auto eit = std::find( from.cbegin(), from.cend(), critter.pos() ); | ||
if( eit != from.cend() ) { | ||
critter.setpos( dest[ std::distance( from.cbegin(), eit ) ] ); | ||
} | ||
} | ||
} | ||
|
||
auto move_vehicles( const elevator_vehicles &vehs, const tripoint &sm_orig, int movez, | ||
int turns ) -> void | ||
{ | ||
map &here = get_map(); | ||
|
||
for( vehicle *v : vehs.v ) { | ||
const tripoint p = rotate_point_sm( { v->global_pos3().xy(), movez }, sm_orig, turns ); | ||
here.displace_vehicle( *v, p - v->global_pos3() ); | ||
v->turn( turns * 90_degrees ); | ||
v->face = tileray( v->turn_dir ); | ||
v->precalc_mounts( 0, v->turn_dir, v->pivot_anchor[0] ); | ||
} | ||
here.reset_vehicle_cache(); | ||
} | ||
|
||
} //namespace elevator | ||
|
||
} // 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 tripoint_abs_ms old_abs_pos = here.getglobal( p.pos() ); | ||
const tripoint_abs_omt this_omt = project_to<coords::omt>( here.getglobal( examp ) ); | ||
const tripoint sm_orig = here.getlocal( project_to<coords::ms>( this_omt ) ); | ||
|
||
const auto elevator_here = elevator::here( p ); | ||
const auto vehs = elevator::vehicles_on( elevator_here ); | ||
if( vehs.blocking ) { | ||
return warn_blocking( vehs, _( "here" ) ); | ||
} | ||
|
||
const int movez = elevator::choose_floor( examp, this_omt, sm_orig ); | ||
if( movez < -OVERMAP_DEPTH ) { | ||
return; | ||
} | ||
|
||
const tripoint_abs_omt that_omt{ this_omt.xy(), movez }; | ||
const int turns = get_rot_delta( this_omt, that_omt ); | ||
|
||
const auto elevator_dest = elevator::dest( elevator_here, sm_orig, turns, movez ); | ||
const auto vehicles_dest = elevator::vehicles_on( elevator_dest ); | ||
if( !vehicles_dest.v.empty() ) { | ||
return warn_blocking( vehicles_dest, _( "at the destination floor" ) ); | ||
} | ||
|
||
elevator::move_creatures_away( elevator_dest ); | ||
elevator::move_items( elevator_here, elevator_dest ); | ||
elevator::move_creatures( elevator_here, elevator_dest ); | ||
elevator::move_vehicles( vehs, sm_orig, movez, turns ); | ||
|
||
g->vertical_shift( movez ); | ||
cata_event_dispatch::avatar_moves( *p.as_avatar(), here, old_abs_pos.raw() ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#include "point_rotate.h" | ||
#include "overmapbuffer.h" | ||
#include "omdata.h" | ||
#include "point.h" | ||
|
||
auto rotate( point p, point dim, int turns ) -> point | ||
{ | ||
switch( turns ) { | ||
case 1: | ||
return { dim.y - p.y - 1, p.x }; | ||
case 2: | ||
return { dim.x - p.x - 1, dim.y - p.y - 1 }; | ||
case 3: | ||
return { p.y, dim.x - p.x - 1 }; | ||
default: | ||
return p; | ||
} | ||
} | ||
|
||
auto rotate( const tripoint &p, point dim, int turns ) -> tripoint | ||
{ | ||
return { rotate( p.xy(), dim, turns ), p.z }; | ||
} | ||
|
||
auto rotate_point_sm( const tripoint &p, const tripoint &orig, int turns ) -> tripoint | ||
{ | ||
const tripoint p_sm{ p - orig.xy() }; | ||
const tripoint rd{ rotate( p_sm, { SEEX * 2, SEEY * 2 }, turns ) }; | ||
|
||
return tripoint{ rd + orig.xy() }; | ||
} | ||
|
||
auto get_rot_delta( const tripoint_abs_omt &here, const tripoint_abs_omt &there ) -> int | ||
{ | ||
const auto this_dir = overmap_buffer.ter( there )->get_dir(); | ||
const auto that_dir = overmap_buffer.ter( here )->get_dir(); | ||
|
||
int const diff = static_cast<int>( this_dir ) - static_cast<int>( that_dir ); | ||
return diff >= 0 ? diff : 4 + diff; | ||
} |
Oops, something went wrong.