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