diff --git a/src/avatar.h b/src/avatar.h index 51b41de161352..f1957c04a5db6 100644 --- a/src/avatar.h +++ b/src/avatar.h @@ -202,7 +202,7 @@ class avatar : public Character // Dialogue and bartering--see npctalk.cpp void talk_to( std::unique_ptr talk_with, bool radio_contact = false, - bool is_computer = false, bool is_not_conversation = false ); + bool is_computer = false, bool is_not_conversation = false, const std::string &debug_topic = "" ); /** * Try to disarm the NPC. May result in fail attempt, you receiving the weapon and instantly wielding it, diff --git a/src/debug_menu.cpp b/src/debug_menu.cpp index ad99e7230cd46..a0cefcabc3365 100644 --- a/src/debug_menu.cpp +++ b/src/debug_menu.cpp @@ -89,6 +89,7 @@ #include "mutation.h" #include "npc.h" #include "npc_class.h" +#include "npctalk.h" #include "omdata.h" #include "options.h" #include "output.h" @@ -270,6 +271,7 @@ std::string enum_to_string( debug_menu::debug_menu case debug_menu::debug_menu_index::SIX_MILLION_DOLLAR_SURVIVOR: return "SIX_MILLION_DOLLAR_SURVIVOR"; case debug_menu::debug_menu_index::EDIT_FACTION: return "EDIT_FACTION"; case debug_menu::debug_menu_index::WRITE_CITY_LIST: return "WRITE_CITY_LIST"; + case debug_menu::debug_menu_index::TALK_TOPIC: return "TALK_TOPIC"; // *INDENT-ON* case debug_menu::debug_menu_index::last: break; @@ -915,7 +917,14 @@ static int faction_uilist() return uilist( _( "Faction" ), uilist_initializer ); } +static int dialogue_uilist() +{ + const std::vector uilist_initializer = { + { uilist_entry( debug_menu_index::TALK_TOPIC, true, 't', _( "Display talk topic" ) ) } + }; + return uilist( _( "Dialogue…" ), uilist_initializer ); +} /** * Create the debug menu UI list. @@ -926,7 +935,7 @@ static int faction_uilist() static std::optional debug_menu_uilist( bool display_all_entries = true ) { enum { - D_INFO, D_GAME, D_SPAWNING, D_PLAYER, D_MONSTER, D_FACTION, D_VEHICLE, D_TELEPORT, D_MAP, D_QUICK_SETUP + D_INFO, D_GAME, D_SPAWNING, D_PLAYER, D_MONSTER, D_FACTION, D_VEHICLE, D_TELEPORT, D_MAP, D_DIALOGUE, D_QUICK_SETUP }; std::vector menu = { @@ -943,6 +952,7 @@ static std::optional debug_menu_uilist( bool display_all_entri { uilist_entry( D_VEHICLE, true, 'v', _( "Vehicle…" ) ) }, { uilist_entry( D_TELEPORT, true, 't', _( "Teleport…" ) ) }, { uilist_entry( D_MAP, true, 'm', _( "Map…" ) ) }, + { uilist_entry( D_DIALOGUE, true, 'd', _( "Dialogue…" ) ) }, { uilist_entry( D_QUICK_SETUP, true, 'q', _( "Quick setup…" ) ) }, }; @@ -998,6 +1008,9 @@ static std::optional debug_menu_uilist( bool display_all_entri case D_VEHICLE: action = vehicle_uilist(); break; + case D_DIALOGUE: + action = dialogue_uilist(); + break; case D_QUICK_SETUP: action = quick_setup_uilist(); break; @@ -3055,6 +3068,43 @@ static void debug_menu_spawn_vehicle() } } +static void display_talk_topic() +{ + avatar &a = get_avatar(); + int menu_ind = 0; + uilist npc_menu; + npc_menu.text = _( "Choose NPC to hold topic:" ); + std::vector visible_npcs = g->get_npcs_if( [&]( const npc & n ) { + return a.sees( n ); + } ); + int npc_count = static_cast( visible_npcs.size() ); + if( npc_count > 0 ) { + for( npc *n : visible_npcs ) { + npc_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, n->disp_name() ); + } + npc_menu.query(); + if( npc_menu.ret >= 0 && npc_menu.ret < npc_count ) { + npc *selected_npc = visible_npcs[npc_menu.ret]; + std::vector dialogue_ids = get_all_talk_topic_ids(); + std::sort( dialogue_ids.begin(), dialogue_ids.end(), localized_compare ); + uilist talk_topic_menu; + talk_topic_menu.text = _( "Choose talk topic to display:" ); + int menu_ind = 0; + for( auto &elem : dialogue_ids ) { + talk_topic_menu.addentry( menu_ind, true, MENU_AUTOASSIGN, elem ); + ++menu_ind; + } + talk_topic_menu.query(); + if( talk_topic_menu.ret >= 0 && talk_topic_menu.ret < static_cast( dialogue_ids.size() ) ) { + const std::string selected_topic = dialogue_ids[talk_topic_menu.ret]; + a.talk_to( get_talker_for( selected_npc ), false, false, false, selected_topic ); + } + } + } else { + add_msg( m_bad, _( "You need an NPC to add a talk topic to." ) ); + } +} + static void debug_menu_force_temperature() { uilist tempmenu; @@ -4167,6 +4217,11 @@ void debug() case debug_menu_index::WRITE_CITY_LIST: write_city_list(); + break; + + case debug_menu_index::TALK_TOPIC: + display_talk_topic(); + break; case debug_menu_index::last: return; diff --git a/src/debug_menu.h b/src/debug_menu.h index 9d8e3bbe6bd94..cc03db9e5cae4 100644 --- a/src/debug_menu.h +++ b/src/debug_menu.h @@ -113,6 +113,7 @@ enum class debug_menu_index : int { SIX_MILLION_DOLLAR_SURVIVOR, EDIT_FACTION, WRITE_CITY_LIST, + TALK_TOPIC, last }; diff --git a/src/npctalk.cpp b/src/npctalk.cpp index d7761b3968f95..cbda6f9462ff0 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -1369,10 +1369,11 @@ void npc::handle_sound( const sounds::sound_t spriority, const std::string &desc } void avatar::talk_to( std::unique_ptr talk_with, bool radio_contact, - bool is_computer, bool is_not_conversation ) + bool is_computer, bool is_not_conversation, const std::string &debug_topic ) { const bool has_mind_control = has_trait( trait_DEBUG_MIND_CONTROL ); - if( !talk_with->will_talk_to_u( *this, has_mind_control ) ) { + const bool force_topic = !debug_topic.empty(); + if( !talk_with->will_talk_to_u( *this, has_mind_control || force_topic ) ) { return; } dialogue d( get_talker_for( *this ), std::move( talk_with ), {} ); @@ -1384,11 +1385,15 @@ void avatar::talk_to( std::unique_ptr talk_with, bool radio_contact, d.missions_assigned.push_back( mission ); } } - for( const std::string &topic_id : d.actor( true )->get_topics( radio_contact ) ) { - d.add_topic( topic_id ); - } - for( const std::string &topic_id : d.actor( true )->get_topics( radio_contact ) ) { - d.add_topic( topic_id ); + if( !force_topic ) { + for( const std::string &topic_id : d.actor( true )->get_topics( radio_contact ) ) { + d.add_topic( topic_id ); + } + for( const std::string &topic_id : d.actor( true )->get_topics( radio_contact ) ) { + d.add_topic( topic_id ); + } + } else { + d.add_topic( debug_topic ); } dialogue_window d_win; d_win.is_computer = is_computer; @@ -7668,3 +7673,13 @@ const json_talk_topic *get_talk_topic( const std::string &id ) return &it->second; } +std::vector get_all_talk_topic_ids() +{ + std::vector dialogue_ids; + dialogue_ids.reserve( json_talk_topics.size() ); + for( auto &elem : json_talk_topics ) { + dialogue_ids.push_back( elem.first ); + } + return dialogue_ids; +} + diff --git a/src/npctalk.h b/src/npctalk.h index 9d8c61ac34d96..d1a5437059763 100644 --- a/src/npctalk.h +++ b/src/npctalk.h @@ -137,6 +137,8 @@ int calc_spell_training_cost( const Character &teacher, const Character &student const json_talk_topic *get_talk_topic( const std::string &id ); +std::vector get_all_talk_topic_ids(); + std::vector npcs_select_menu( const std::vector &npc_list, const std::string &prompt, const std::function &exclude_func );