1 #pragma once 2 #ifndef CATA_SRC_DIALOGUE_H 3 #define CATA_SRC_DIALOGUE_H 4 5 #include <functional> 6 #include <iosfwd> 7 #include <memory> 8 #include <set> 9 #include <string> 10 #include <type_traits> 11 #include <utility> 12 #include <vector> 13 14 #include "dialogue_win.h" 15 #include "npc.h" 16 #include "talker.h" 17 #include "translations.h" 18 #include "type_id.h" 19 20 class JsonArray; 21 class JsonObject; 22 class martialart; 23 class mission; 24 struct dialogue; 25 struct input_event; 26 27 enum talk_trial_type : unsigned char { 28 TALK_TRIAL_NONE, // No challenge here! 29 TALK_TRIAL_LIE, // Straight up lying 30 TALK_TRIAL_PERSUADE, // Convince them 31 TALK_TRIAL_INTIMIDATE, // Physical intimidation 32 TALK_TRIAL_CONDITION, // Some other condition 33 NUM_TALK_TRIALS 34 }; 35 36 enum dialogue_consequence : unsigned char { 37 none = 0, 38 hostile, 39 helpless, 40 action 41 }; 42 43 using talkfunction_ptr = std::add_pointer<void ( npc & )>::type; 44 using dialogue_fun_ptr = std::add_pointer<void( npc & )>::type; 45 46 using trial_mod = std::pair<std::string, int>; 47 48 /** 49 * If not TALK_TRIAL_NONE, it defines how to decide whether the responses succeeds (e.g. the 50 * NPC believes the lie). The difficulty is a 0...100 percent chance of success (!), 100 means 51 * always success, 0 means never. It is however affected by mutations/traits/bionics/etc. of 52 * the player character. 53 */ 54 struct talk_trial { 55 talk_trial_type type = TALK_TRIAL_NONE; 56 int difficulty = 0; 57 std::function<bool( const dialogue & )> condition; 58 59 int calc_chance( const dialogue &d ) const; 60 /** 61 * Returns a user-friendly representation of @ref type 62 */ 63 std::string name() const; 64 std::vector<trial_mod> modifiers; 65 explicit operator bool() const { 66 return type != TALK_TRIAL_NONE; 67 } 68 /** 69 * Roll for success or failure of this trial. 70 */ 71 bool roll( dialogue &d ) const; 72 73 talk_trial() = default; 74 explicit talk_trial( const JsonObject & ); 75 }; 76 77 struct talk_topic { talk_topictalk_topic78 explicit talk_topic( const std::string &i ) : id( i ) { } 79 80 std::string id; 81 /** If we're talking about an item, this should be its type. */ 82 itype_id item_type = itype_id::NULL_ID(); 83 /** Reason for denying a request. */ 84 std::string reason; 85 }; 86 87 struct talk_effect_fun_t { 88 private: 89 std::function<void( const dialogue &d )> function; 90 std::vector<std::pair<int, itype_id>> likely_rewards; 91 92 public: 93 talk_effect_fun_t() = default; 94 explicit talk_effect_fun_t( const talkfunction_ptr & ); 95 explicit talk_effect_fun_t( const std::function<void( npc & )> & ); 96 explicit talk_effect_fun_t( const std::function<void( const dialogue &d )> & ); 97 void set_companion_mission( const std::string &role_id ); 98 void set_add_effect( const JsonObject &jo, const std::string &member, bool is_npc = false ); 99 void set_remove_effect( const JsonObject &jo, const std::string &member, bool is_npc = false ); 100 void set_add_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); 101 void set_remove_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); 102 void set_add_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); 103 void set_remove_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); 104 void set_adjust_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); 105 void set_u_buy_item( const itype_id &item_name, int cost, int count, 106 const std::string &container_name ); 107 void set_u_spend_cash( int amount ); 108 void set_u_sell_item( const itype_id &item_name, int cost, int count ); 109 void set_consume_item( const JsonObject &jo, const std::string &member, int count, 110 bool is_npc = false ); 111 void set_remove_item_with( const JsonObject &jo, const std::string &member, bool is_npc = false ); 112 void set_npc_change_faction( const std::string &faction_name ); 113 void set_npc_change_class( const std::string &class_name ); 114 void set_change_faction_rep( int rep_change ); 115 void set_add_debt( const std::vector<trial_mod> &debt_modifiers ); 116 void set_toggle_npc_rule( const std::string &rule ); 117 void set_set_npc_rule( const std::string &rule ); 118 void set_clear_npc_rule( const std::string &rule ); 119 void set_npc_engagement_rule( const std::string &setting ); 120 void set_npc_aim_rule( const std::string &setting ); 121 void set_npc_cbm_reserve_rule( const std::string &setting ); 122 void set_npc_cbm_recharge_rule( const std::string &setting ); 123 void set_mapgen_update( const JsonObject &jo, const std::string &member ); 124 void set_bulk_trade_accept( bool is_trade, int quantity, bool is_npc = false ); 125 void set_npc_gets_item( bool to_use ); 126 void set_add_mission( const std::string &mission_id ); 127 const std::vector<std::pair<int, itype_id>> &get_likely_rewards() const; 128 void set_u_buy_monster( const std::string &monster_type_id, int cost, int count, bool pacified, 129 const translation &name ); 130 void set_u_learn_recipe( const std::string &learned_recipe_id ); 131 void set_npc_first_topic( const std::string &chat_topic ); 132 operatortalk_effect_fun_t133 void operator()( const dialogue &d ) const { 134 if( !function ) { 135 return; 136 } 137 return function( d ); 138 } 139 }; 140 141 /** 142 * Defines what happens when the trial succeeds or fails. If trial is 143 * TALK_TRIAL_NONE it always succeeds. 144 */ 145 struct talk_effect_t { 146 /** 147 * How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u) 148 * will change. 149 */ 150 npc_opinion opinion; 151 /** 152 * How (if at all) the NPCs opinion of the player character (@ref npc::op_of_u) 153 * will change. These values are divisors of the mission value. 154 */ 155 npc_opinion mission_opinion; 156 /** 157 * Topic to switch to. TALK_DONE ends the talking, TALK_NONE keeps the current topic. 158 */ 159 talk_topic next_topic = talk_topic( "TALK_NONE" ); 160 161 talk_topic apply( dialogue &d ) const; 162 dialogue_consequence get_consequence( const dialogue &d ) const; 163 164 /** 165 * Sets an effect and consequence based on function pointer. 166 */ 167 void set_effect( talkfunction_ptr ); 168 void set_effect( const talk_effect_fun_t & ); 169 /** 170 * Sets an effect to a function object and consequence to explicitly given one. 171 */ 172 void set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ); 173 void set_effect_consequence( const std::function<void( npc &p )> &ptr, dialogue_consequence con ); 174 175 void load_effect( const JsonObject &jo ); 176 void parse_sub_effect( const JsonObject &jo ); 177 void parse_string_effect( const std::string &effect_id, const JsonObject &jo ); 178 179 talk_effect_t() = default; 180 explicit talk_effect_t( const JsonObject & ); 181 182 /** 183 * Functions that are called when the response is chosen. 184 */ 185 std::vector<talk_effect_fun_t> effects; 186 private: 187 dialogue_consequence guaranteed_consequence = dialogue_consequence::none; 188 }; 189 190 /** 191 * This defines possible responses from the player character. 192 */ 193 struct talk_response { 194 /** 195 * What the player character says (literally). Should already be translated and will be 196 * displayed. 197 */ 198 std::string text; 199 /* 200 * Optional responses from a true/false test that defaults to true. 201 */ 202 translation truetext; 203 translation falsetext; 204 std::function<bool( const dialogue & )> truefalse_condition; 205 206 talk_trial trial; 207 /** 208 * The following values are forwarded to the chatbin of the NPC (see @ref npc_chatbin). 209 */ 210 mission *mission_selected = nullptr; 211 skill_id skill = skill_id(); 212 matype_id style = matype_id(); 213 spell_id dialogue_spell = spell_id(); 214 proficiency_id proficiency = proficiency_id(); 215 216 talk_effect_t success; 217 talk_effect_t failure; 218 219 talk_data create_option_line( const dialogue &d, const input_event &hotkey ); 220 std::set<dialogue_consequence> get_consequences( const dialogue &d ) const; 221 222 talk_response(); 223 explicit talk_response( const JsonObject & ); 224 }; 225 226 struct dialogue { 227 /** 228 * The talker that speaks (almost certainly representing the avatar, ie get_avatar() ) 229 */ 230 std::unique_ptr<talker> alpha; 231 /** 232 * The talker responded to alpha, usually a talker_npc. 233 */ 234 std::unique_ptr<talker> beta; 235 /** 236 * If true, we are done talking and the dialog ends. 237 */ 238 bool done = false; 239 std::vector<talk_topic> topic_stack; 240 241 /** Missions that have been assigned by this npc to the player they currently speak to. */ 242 std::vector<mission *> missions_assigned; 243 244 talk_topic opt( dialogue_window &d_win, const std::string &npc_name, const talk_topic &topic ); 245 246 dialogue() = default; actordialogue247 talker *actor( const bool is_beta ) const { 248 return ( is_beta ? beta : alpha ).get(); 249 } 250 251 mutable itype_id cur_item; 252 mutable std::string reason; 253 254 std::string dynamic_line( const talk_topic &topic ) const; 255 void apply_speaker_effects( const talk_topic &the_topic ); 256 257 /** This dialogue is happening over a radio */ 258 bool by_radio = false; 259 /** 260 * Possible responses from the player character, filled in @ref gen_responses. 261 */ 262 std::vector<talk_response> responses; 263 void gen_responses( const talk_topic &topic ); 264 265 void add_topic( const std::string &topic ); 266 void add_topic( const talk_topic &topic ); 267 268 private: 269 /** 270 * Add a simple response that switches the topic to the new one. If first == true, force 271 * this topic to the front of the responses. 272 */ 273 talk_response &add_response( const std::string &text, const std::string &r, 274 bool first = false ); 275 /** 276 * Add a response with the result TALK_DONE. 277 */ 278 talk_response &add_response_done( const std::string &text ); 279 /** 280 * Add a response with the result TALK_NONE. 281 */ 282 talk_response &add_response_none( const std::string &text ); 283 /** 284 * Add a simple response that switches the topic to the new one and executes the given 285 * action. The response always succeeds. Consequence is based on function used. 286 */ 287 talk_response &add_response( const std::string &text, const std::string &r, 288 const dialogue_fun_ptr &effect_success, bool first = false ); 289 290 /** 291 * Add a simple response that switches the topic to the new one and executes the given 292 * action. The response always succeeds. Consequence must be explicitly specified. 293 */ 294 talk_response &add_response( const std::string &text, const std::string &r, 295 const std::function<void( npc & )> &effect_success, 296 dialogue_consequence consequence, bool first = false ); 297 /** 298 * Add a simple response that switches the topic to the new one and sets the currently 299 * talked about mission to the given one. The mission pointer must be valid. 300 */ 301 talk_response &add_response( const std::string &text, const std::string &r, mission *miss, 302 bool first = false ); 303 /** 304 * Add a simple response that switches the topic to the new one and sets the currently 305 * talked about skill to the given one. 306 */ 307 talk_response &add_response( const std::string &text, const std::string &r, const skill_id &skill, 308 bool first = false ); 309 /** 310 * Add a simple response that switches the topic to the new one and sets the currently 311 * talked about proficiency to the given one. 312 */ 313 talk_response &add_response( const std::string &text, const std::string &r, 314 const proficiency_id &proficiency, 315 bool first = false ); 316 /** 317 * Add a simple response that switches the topic to the new one and sets the currently 318 * talked about magic spell to the given one. 319 */ 320 talk_response &add_response( const std::string &text, const std::string &r, 321 const spell_id &sp, bool first = false ); 322 /** 323 * Add a simple response that switches the topic to the new one and sets the currently 324 * talked about martial art style to the given one. 325 */ 326 talk_response &add_response( const std::string &text, const std::string &r, 327 const martialart &style, bool first = false ); 328 /** 329 * Add a simple response that switches the topic to the new one and sets the currently 330 * talked about item type to the given one. 331 */ 332 talk_response &add_response( const std::string &text, const std::string &r, 333 const itype_id &item_type, bool first = false ); 334 }; 335 336 /** 337 * A dynamically generated line, spoken by the NPC. 338 * This struct only adds the constructors which will load the data from json 339 * into a lambda, stored in the std::function object. 340 * Invoking the function operator with a dialog reference (so the function can access the NPC) 341 * returns the actual line. 342 */ 343 struct dynamic_line_t { 344 private: 345 std::function<std::string( const dialogue & )> function; 346 347 public: 348 dynamic_line_t() = default; 349 explicit dynamic_line_t( const translation &line ); 350 explicit dynamic_line_t( const JsonObject &jo ); 351 explicit dynamic_line_t( const JsonArray &ja ); 352 static dynamic_line_t from_member( const JsonObject &jo, const std::string &member_name ); 353 operatordynamic_line_t354 std::string operator()( const dialogue &d ) const { 355 if( !function ) { 356 return std::string{}; 357 } 358 return function( d ); 359 } 360 }; 361 362 /** 363 * An extended response. It contains the response itself and a condition, so we can include the 364 * response if, and only if the condition is met. 365 */ 366 class json_talk_response 367 { 368 private: 369 talk_response actual_response; 370 std::function<bool( const dialogue & )> condition; 371 bool has_condition_ = false; 372 bool is_switch = false; 373 bool is_default = false; 374 375 void load_condition( const JsonObject &jo ); 376 bool test_condition( const dialogue &d ) const; 377 378 public: 379 json_talk_response() = default; 380 explicit json_talk_response( const JsonObject &jo ); 381 382 const talk_response &get_actual_response() const; has_condition()383 bool has_condition() const { 384 return has_condition_; 385 } 386 387 /** 388 * Callback from @ref json_talk_topic::gen_responses, see there. 389 */ 390 bool gen_responses( dialogue &d, bool switch_done ) const; 391 bool gen_repeat_response( dialogue &d, const itype_id &item_id, bool switch_done ) const; 392 }; 393 394 /** 395 * A structure for generating repeated responses 396 */ 397 class json_talk_repeat_response 398 { 399 public: 400 json_talk_repeat_response() = default; 401 explicit json_talk_repeat_response( const JsonObject &jo ); 402 bool is_npc = false; 403 bool include_containers = false; 404 std::vector<itype_id> for_item; 405 std::vector<item_category_id> for_category; 406 json_talk_response response; 407 }; 408 409 class json_dynamic_line_effect 410 { 411 private: 412 std::function<bool( const dialogue & )> condition; 413 talk_effect_t effect; 414 public: 415 json_dynamic_line_effect( const JsonObject &jo, const std::string &id ); 416 bool test_condition( const dialogue &d ) const; 417 void apply( dialogue &d ) const; 418 }; 419 420 /** 421 * Talk topic definitions load from json. 422 */ 423 class json_talk_topic 424 { 425 private: 426 bool replace_built_in_responses = false; 427 std::vector<json_talk_response> responses; 428 dynamic_line_t dynamic_line; 429 std::vector<json_dynamic_line_effect> speaker_effects; 430 std::vector<json_talk_repeat_response> repeat_responses; 431 432 public: 433 json_talk_topic() = default; 434 /** 435 * Load data from json. 436 * This will append responses (not change existing ones). 437 * It will override dynamic_line and replace_built_in_responses if those entries 438 * exist in the input, otherwise they will not be changed at all. 439 */ 440 void load( const JsonObject &jo ); 441 442 std::string get_dynamic_line( const dialogue &d ) const; 443 std::vector<json_dynamic_line_effect> get_speaker_effects() const; 444 445 void check_consistency() const; 446 /** 447 * Callback from @ref dialogue::gen_responses, it should add the response from here 448 * into the list of possible responses (that will be presented to the player). 449 * It may add an arbitrary number of responses (including none at all). 450 * @return true if built in response should excluded (not added). If false, built in 451 * responses will be added (behind those added here). 452 */ 453 bool gen_responses( dialogue &d ) const; 454 455 cata::flat_set<std::string> get_directly_reachable_topics( bool only_unconditional ) const; 456 }; 457 458 void unload_talk_topics(); 459 void load_talk_topic( const JsonObject &jo ); 460 461 #endif // CATA_SRC_DIALOGUE_H 462