From b363fb91a61d40d0949d40741b052770a80539b2 Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Tue, 8 Oct 2019 06:13:39 -0500 Subject: [PATCH] basecamps: add an emergency recall option Fixes #31872 Add the option to recall any NPC that has been on a mission for more than 24 hours. This cancels the mission without refunding any resources, but can be used to recover NPCs that are otherwise stuck. --- src/basecamp.h | 5 +++- src/faction_camp.cpp | 57 ++++++++++++++++++++++++++++++++++----- src/mission_companion.cpp | 5 ++-- src/mission_companion.h | 3 ++- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/basecamp.h b/src/basecamp.h index a1aae7e813559..28597471da9b6 100644 --- a/src/basecamp.h +++ b/src/basecamp.h @@ -283,11 +283,14 @@ class basecamp /// called with a companion @ref comp who is not the camp manager, finishes updating their /// skills, consuming food, and returning them to the base. void finish_return( npc &comp, bool fixed_time, const std::string &return_msg, - const std::string &skill, int difficulty ); + const std::string &skill, int difficulty, bool cancel = false ); /// a wrapper function for @ref companion_choose_return and @ref finish_return npc_ptr mission_return( const std::string &miss_id, time_duration min_duration, bool fixed_time, const std::string &return_msg, const std::string &skill, int difficulty ); + /// select a companion for any mission to return to base + npc_ptr emergency_recall(); + /// Called to close upgrade missions, @ref miss is the name of the mission id /// and @ref dir is the direction of the location to be upgraded bool upgrade_return( const point &dir, const std::string &miss ); diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index 8ffd3404b02df..b76bddf4f603c 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -125,6 +125,13 @@ std::map miss_info = {{ "Recover Ally from Upgrading", to_translation( "Recover Ally from Upgrading" ) } }, + { + "_faction_camp_recall", { + "Emergency Recall", to_translation( "Emergency Recall" ), + to_translation( "Lost in the ether!\n" ), + "Emergency Recall", to_translation( "Emergency Recall" ) + } + }, { "_faction_camp_crafting_", { "Craft Item", to_translation( "Craft Item" ), @@ -1265,6 +1272,22 @@ void basecamp::get_available_missions( mission_data &mission_key, bool by_radio } } } + + if( !camp_workers.empty() ) { + const base_camps::miss_data &miss_info = base_camps::miss_info[ "_faction_camp_recall" ]; + entry = string_format( _( "Notes:\n" + "Cancel a current mission and force the immediate return of a " + "companion. No work will be done on the mission and all " + "resources used on the mission will be lost.\n\n" + "WARNING: All resources used on the mission will be lost and " + "no work will be done. Only use this mission to recover a " + "companion who cannot otherwise be recovered.\n\n" + "Companions must be on missions for at least 24 hours before " + "emergency recall becomes available." ) ); + bool avail = update_time_fixed( entry, camp_workers, 24_hours ); + mission_key.add_return( miss_info.ret_miss_id, miss_info.ret_desc.translated(), + cata::nullopt, entry, avail ); + } } bool basecamp::handle_mission( const std::string &miss_id, const cata::optional miss_dir, @@ -1480,6 +1503,10 @@ bool basecamp::handle_mission( const std::string &miss_id, const cata::optional< } } + if( miss_id == "Emergency Recall" ) { + emergency_recall(); + } + g->draw_ter(); wrefresh( g->w_terrain ); g->draw_panels( true ); @@ -2156,8 +2183,8 @@ npc_ptr basecamp::companion_choose_return( const std::string &miss_id, return talk_function::companion_choose_return( omt_pos, base_camps::id, miss_id, calendar::turn - min_duration ); } -void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &return_msg, - const std::string &skill, int difficulty ) +void basecamp::finish_return( npc &comp, const bool fixed_time, const std::string &return_msg, + const std::string &skill, int difficulty, const bool cancel ) { popup( "%s %s", comp.name, return_msg ); // this is the time the mission was expected to take, or did take for fixed time missions @@ -2166,7 +2193,9 @@ void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &ret if( !fixed_time ) { mission_time = calendar::turn - comp.companion_mission_time; } - talk_function::companion_skill_trainer( comp, skill, mission_time, difficulty ); + if( !cancel ) { + talk_function::companion_skill_trainer( comp, skill, mission_time, difficulty ); + } // companions subtracted food when they started the mission, but didn't mod their hunger for // that food. so add it back in. @@ -2181,10 +2210,12 @@ void basecamp::finish_return( npc &comp, bool fixed_time, const std::string &ret comp.companion_mission_time = calendar::before_time_starts; comp.companion_mission_time_ret = calendar::before_time_starts; bool by_radio = g->u.global_omt_location() != comp.global_omt_location(); - for( size_t i = 0; i < comp.companion_mission_inv.size(); i++ ) { - for( const auto &it : comp.companion_mission_inv.const_stack( i ) ) { - if( !it.count_by_charges() || it.charges > 0 ) { - place_results( it, by_radio ); + if( !cancel ) { + for( size_t i = 0; i < comp.companion_mission_inv.size(); i++ ) { + for( const auto &it : comp.companion_mission_inv.const_stack( i ) ) { + if( !it.count_by_charges() || it.charges > 0 ) { + place_results( it, by_radio ); + } } } } @@ -2215,6 +2246,18 @@ npc_ptr basecamp::mission_return( const std::string &miss_id, time_duration min_ return comp; } +npc_ptr basecamp::emergency_recall() +{ + npc_ptr comp = talk_function::companion_choose_return( omt_pos, base_camps::id, "", + calendar::turn - 24_hours, false ); + if( comp != nullptr ) { + const std::string return_msg = _( "responds to the emergency recall..." ); + finish_return( *comp, false, return_msg, "menial", 0, true ); + } + return comp; + +} + bool basecamp::upgrade_return( const point &dir, const std::string &miss ) { const std::string bldg = next_upgrade( dir, 1 ); diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 411259d15ac96..9a3157ad67f3f 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -1998,13 +1998,14 @@ npc_ptr talk_function::companion_choose_return( const npc &p, const std::string npc_ptr talk_function::companion_choose_return( const tripoint &omt_pos, const std::string &role_id, const std::string &mission_id, - const time_point &deadline ) + const time_point &deadline, + const bool by_mission ) { std::vector available; for( npc_ptr &guy : overmap_buffer.get_companion_mission_npcs() ) { npc_companion_mission c_mission = guy->get_companion_mission(); if( c_mission.position != omt_pos || - c_mission.mission_id != mission_id || c_mission.role_id != role_id ) { + ( by_mission && c_mission.mission_id != mission_id ) || c_mission.role_id != role_id ) { continue; } if( g->u.has_trait( trait_id( "DEBUG_HS" ) ) ) { diff --git a/src/mission_companion.h b/src/mission_companion.h index 526007e4aa00b..3646e22a52068 100644 --- a/src/mission_companion.h +++ b/src/mission_companion.h @@ -140,7 +140,8 @@ npc_ptr companion_choose( const std::string &skill_tested = "", int skill_level npc_ptr companion_choose_return( const npc &p, const std::string &mission_id, const time_point &deadline ); npc_ptr companion_choose_return( const tripoint &omt_pos, const std::string &role_id, - const std::string &mission_id, const time_point &deadline ); + const std::string &mission_id, const time_point &deadline, + bool by_mission = true ); //Return NPC to your party void companion_return( npc &comp );