Skip to content

Commit 8d23907

Browse files
committed
Path Manager: walk from middle of a path
1 parent 864a61a commit 8d23907

File tree

2 files changed

+108
-13
lines changed

2 files changed

+108
-13
lines changed

data/raw/keybindings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3421,6 +3421,12 @@
34213421
"category": "PATH_MANAGER",
34223422
"name": "Walk path"
34233423
},
3424+
{
3425+
"type": "keybinding",
3426+
"id": "WALK_PATH_FROM_MIDDLE",
3427+
"category": "PATH_MANAGER",
3428+
"name": "Walk path from middle"
3429+
},
34243430
{
34253431
"type": "keybinding",
34263432
"id": "START_RECORDING",

src/path_manager.cpp

Lines changed: 102 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class path
6060
* Avatar must be at one of the ends of the path.
6161
*/
6262
void set_avatar_path() const;
63+
/**
64+
* Avatar stands in the middle of the path, so go towards the end or start selected by `towards_end`.
65+
*/
66+
void set_avatar_path( bool towards_end ) const;
6367
void set_name_start();
6468
void set_name_end();
6569
/**
@@ -105,6 +109,13 @@ class path_manager_impl
105109
* Crash on fail <==> when avatar_at_what_start_or_end returns -1.
106110
*/
107111
void auto_route_from_path() const;
112+
/**
113+
* Let the player choose on what path to walk and in what direction.
114+
* Set avatars auto route to the selected path.
115+
*
116+
* Return true if path was selected, false otherwise.
117+
*/
118+
bool auto_route_from_path_middle() const;
108119
/**
109120
* Start recording a new path.
110121
*/
@@ -134,6 +145,10 @@ class path_manager_impl
134145
* -1 if the avatar stands at no start or end.
135146
*/
136147
int avatar_at_what_start_or_end() const;
148+
/**
149+
* Return indexes of paths the avatar stands on.
150+
*/
151+
std::vector<int> avatar_at_what_paths() const;
137152
private:
138153
bool is_recording_path() const;
139154
/**
@@ -203,22 +218,40 @@ void path::record_step( const tripoint_abs_ms &new_pos )
203218
}
204219

205220
void path::set_avatar_path() const
221+
{
222+
if( is_avatar_at_start() || is_avatar_at_end() ) {
223+
set_avatar_path( is_avatar_at_start() );
224+
} else {
225+
debugmsg( "Tried to set auto route but the player character doesn't stand at path start or end." );
226+
return;
227+
}
228+
}
229+
230+
void path::set_avatar_path( bool towards_end ) const
206231
{
207232
avatar &player_character = get_avatar();
208233
std::vector<tripoint_bub_ms> route;
234+
std::string from;
209235
if( is_avatar_at_start() ) {
210-
add_msg( m_info, _( string_format( "Auto path: Go from %s to %s.", name_start, name_end ) ) );
211-
for( auto it = std::next( recorded_path.begin() ); it != recorded_path.end(); ++it ) {
212-
route.emplace_back( get_map().bub_from_abs( *it ) );
213-
}
236+
from = name_start;
214237
} else if( is_avatar_at_end() ) {
215-
add_msg( m_info, _( string_format( "Auto path: Go from %s to %s.", name_end, name_start ) ) );
216-
for( auto it = std::next( recorded_path.rbegin() ); it != recorded_path.rend(); ++it ) {
238+
from = name_end;
239+
} else {
240+
from = _( "the middle of path" );
241+
}
242+
243+
int avatar_at = avatar_closest_i_approximate();
244+
if( towards_end ) {
245+
add_msg( m_info, _( string_format( "Auto path: Go from %s to %s.", from, name_end ) ) );
246+
for( auto it = std::next( recorded_path.begin() + avatar_at ); it != recorded_path.end(); ++it ) {
217247
route.emplace_back( get_map().bub_from_abs( *it ) );
218248
}
219249
} else {
220-
debugmsg( "Tried to set auto route but the player character doesn't stand at path start or end." );
221-
return;
250+
add_msg( m_info, _( string_format( "Auto path: Go from %s to %s.", from, name_start ) ) );
251+
for( auto it = std::next( recorded_path.rbegin() + recorded_path.size() - avatar_at - 1 );
252+
it != recorded_path.rend(); ++it ) {
253+
route.emplace_back( get_map().bub_from_abs( *it ) );
254+
}
222255
}
223256
player_character.set_destination( route );
224257
}
@@ -266,7 +299,7 @@ bool path::is_avatar_at_end() const
266299
int path::avatar_closest_i_approximate() const
267300
{
268301
cata_assert( !recorded_path.empty() );
269-
tripoint_abs_ms avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
302+
const tripoint_abs_ms &avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
270303
// Check start and end so that the path is not further away than either of those.
271304
int closest_i = recorded_path.size() - 1;
272305
int closest_dist = square_dist( recorded_path.back(), avatar_pos );
@@ -393,6 +426,18 @@ int path_manager_impl::avatar_at_what_start_or_end() const
393426
return -1;
394427
}
395428

429+
std::vector<int> path_manager_impl::avatar_at_what_paths() const
430+
{
431+
std::vector<int> ret;
432+
const tripoint_abs_ms &avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
433+
for( auto it = paths.begin(); it != paths.end(); ++it ) {
434+
if( avatar_pos == it->recorded_path[it->avatar_closest_i_approximate()] ) {
435+
ret.emplace_back( static_cast<int>( it - paths.begin() ) );
436+
}
437+
}
438+
return ret;
439+
}
440+
396441
bool path_manager_impl::is_recording_path() const
397442
{
398443
return recording_path_index != -1;
@@ -405,6 +450,35 @@ void path_manager_impl::auto_route_from_path() const
405450
paths[p_index].set_avatar_path();
406451
}
407452

453+
bool path_manager_impl::auto_route_from_path_middle() const
454+
{
455+
const tripoint_abs_ms &avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
456+
uilist path_selection;
457+
path_selection.text = _( "Select path and direction to walk in." );
458+
for( int i : avatar_at_what_paths() ) {
459+
const path &curr_path = paths[i];
460+
const std::string from_to = string_format( "from %s (%s) to %s (%s)",
461+
curr_path.name_start,
462+
direction_suffix( avatar_pos, curr_path.recorded_path.front() ),
463+
curr_path.name_end,
464+
direction_suffix( avatar_pos, curr_path.recorded_path.back() ) );
465+
const int avatar_at_i = curr_path.avatar_closest_i_approximate();
466+
const int start_steps = avatar_at_i;
467+
const int end_steps = curr_path.recorded_path.size() - avatar_at_i - 1;
468+
const std::string start = string_format( "%s (%d steps)", curr_path.name_start, avatar_at_i );
469+
const std::string end = string_format( "%s (%d steps)", curr_path.name_end, end_steps );
470+
path_selection.addentry( -1, false, MENU_AUTOASSIGN, from_to );
471+
path_selection.addentry( i << 1, start_steps > 0, MENU_AUTOASSIGN, start );
472+
path_selection.addentry( ( i << 1 ) + 1, end_steps > 0, MENU_AUTOASSIGN, end );
473+
}
474+
path_selection.query();
475+
if( path_selection.ret < 0 ) {
476+
return false;
477+
}
478+
paths[path_selection.ret >> 1].set_avatar_path( path_selection.ret % 2 );
479+
return true;
480+
}
481+
408482
void path_manager_impl::set_recording_path( int p_index )
409483
{
410484
cata_assert( -1 <= p_index && p_index < static_cast<int>( paths.size() ) );
@@ -431,7 +505,7 @@ void path_manager_ui::enabled_active_button( const std::string action, bool enab
431505

432506
static void draw_distance_from_tile( const tripoint_abs_ms &tile )
433507
{
434-
const tripoint_abs_ms avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
508+
const tripoint_abs_ms &avatar_pos = get_map().getglobal( get_avatar().pos_bub() );
435509
if( avatar_pos == tile ) {
436510
cataimgui::draw_colored_text( _( "It's under your feet." ), c_light_green );
437511
} else {
@@ -442,18 +516,25 @@ static void draw_distance_from_tile( const tripoint_abs_ms &tile )
442516

443517
void path_manager_ui::draw_controls()
444518
{
445-
// general buttons
519+
// walk buttons
520+
cataimgui::draw_colored_text( _( "Walk:" ) );
521+
ImGui::SameLine();
446522
enabled_active_button( "WALK_PATH", pimpl->avatar_at_what_start_or_end() != -1 );
447523
ImGui::SameLine();
524+
enabled_active_button( "WALK_PATH_FROM_MIDDLE", !pimpl->avatar_at_what_paths().empty() );
525+
526+
// recording buttons
527+
cataimgui::draw_colored_text( _( "Recording:" ) );
528+
ImGui::SameLine();
448529
enabled_active_button( "START_RECORDING", !pimpl->is_recording_path() );
449530
ImGui::SameLine();
450531
enabled_active_button( "CONTINUE_RECORDING", !pimpl->is_recording_path()
451532
&& pimpl->avatar_at_what_start_or_end() != -1 );
452533
ImGui::SameLine();
453534
enabled_active_button( "STOP_RECORDING", pimpl->is_recording_path() );
454535

455-
// buttons related to selected path
456-
cataimgui::draw_colored_text( _( "Selected path:" ), c_white );
536+
// manage buttons
537+
cataimgui::draw_colored_text( _( "Manage:" ) );
457538
ImGui::SameLine();
458539
enabled_active_button( "DELETE_PATH", pimpl->selected_id != -1 );
459540
ImGui::SameLine();
@@ -462,6 +543,9 @@ void path_manager_ui::draw_controls()
462543
enabled_active_button( "MOVE_PATH_DOWN", pimpl->selected_id != -1 &&
463544
pimpl->selected_id + 1 < static_cast<int>( pimpl->paths.size() ) );
464545

546+
// name buttons
547+
cataimgui::draw_colored_text( _( "Rename:" ) );
548+
ImGui::SameLine();
465549
enabled_active_button( "RENAME_START", pimpl->selected_id != -1 );
466550
ImGui::SameLine();
467551
enabled_active_button( "RENAME_END", pimpl->selected_id != -1 );
@@ -524,6 +608,7 @@ void path_manager_ui::run()
524608
ctxt.register_action( "HELP_KEYBINDINGS" );
525609

526610
ctxt.register_action( "WALK_PATH" );
611+
ctxt.register_action( "WALK_PATH_FROM_MIDDLE" );
527612
ctxt.register_action( "START_RECORDING" );
528613
ctxt.register_action( "STOP_RECORDING" );
529614
ctxt.register_action( "CONTINUE_RECORDING" );
@@ -548,6 +633,10 @@ void path_manager_ui::run()
548633
if( action == "WALK_PATH" && pimpl->avatar_at_what_start_or_end() != -1 ) {
549634
pimpl->auto_route_from_path();
550635
break;
636+
} else if( action == "WALK_PATH_FROM_MIDDLE" && !pimpl->avatar_at_what_paths().empty() ) {
637+
if( pimpl->auto_route_from_path_middle() ) {
638+
break;
639+
}
551640
} else if( action == "START_RECORDING" && !pimpl->is_recording_path() ) {
552641
pimpl->start_recording();
553642
break;

0 commit comments

Comments
 (0)