forked from cataclysmbnteam/Cataclysm-BN
-
Notifications
You must be signed in to change notification settings - Fork 0
/
npc.h
1420 lines (1274 loc) · 51.5 KB
/
npc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#pragma once
#ifndef CATA_SRC_NPC_H
#define CATA_SRC_NPC_H
#include <algorithm>
#include <array>
#include <functional>
#include <iosfwd>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "auto_pickup.h"
#include "calendar.h"
#include "character.h"
#include "color.h"
#include "creature.h"
#include "cursesdef.h"
#include "enums.h"
#include "faction.h"
#include "game_constants.h"
#include "int_id.h"
#include "inventory.h"
#include "item.h"
#include "item_location.h"
#include "line.h"
#include "lru_cache.h"
#include "pimpl.h"
#include "player.h"
#include "point.h"
#include "sounds.h"
#include "string_formatter.h"
#include "string_id.h"
#include "translations.h"
#include "type_id.h"
#include "units.h"
class JsonIn;
class JsonObject;
class JsonOut;
class mission;
class monfaction;
class monster;
class npc_class;
class vehicle;
struct bionic_data;
struct mission_type;
struct overmap_location;
struct pathfinding_settings;
enum game_message_type : int;
class gun_mode;
using bionic_id = string_id<bionic_data>;
using npc_class_id = string_id<npc_class>;
using mission_type_id = string_id<mission_type>;
using mfaction_id = int_id<monfaction>;
using overmap_location_str_id = string_id<overmap_location>;
void parse_tags( std::string &phrase, const Character &u, const Character &me,
const itype_id &item_type = itype_id::NULL_ID() );
/*
* Talk: Trust midlow->high, fear low->mid, need doesn't matter
* Trade: Trust mid->high, fear low->midlow, need is a bonus
* Follow: Trust high, fear mid->high, need low->mid
* Defend: Trust mid->high, fear + need high
* Kill: Trust low->midlow, fear low->midlow, need low
* Flee: Trust low, fear mid->high, need low
*/
// Attitude is how we feel about the player, what we do around them
enum npc_attitude : int {
NPCATT_NULL = 0, // Don't care/ignoring player The places this is assigned is on shelter NPC generation, and when you order a NPC to stay in a location, and after talking to a NPC that wanted to talk to you.
NPCATT_TALK, // Move to and talk to player
NPCATT_LEGACY_1,
NPCATT_FOLLOW, // Follow the player
NPCATT_LEGACY_2,
NPCATT_LEAD, // Lead the player, wait for them if they're behind
NPCATT_WAIT, // Waiting for the player
NPCATT_LEGACY_6,
NPCATT_MUG, // Mug the player
NPCATT_WAIT_FOR_LEAVE, // Attack the player if our patience runs out
NPCATT_KILL, // Kill the player
NPCATT_FLEE, // Get away from the player; deprecated
NPCATT_LEGACY_3,
NPCATT_HEAL, // Get to the player and heal them
NPCATT_LEGACY_4,
NPCATT_LEGACY_5,
NPCATT_ACTIVITY, // Perform a mission activity
NPCATT_FLEE_TEMP, // Get away from the player for a while
NPCATT_RECOVER_GOODS, // Chase the player to demand stolen goods back
NPCATT_END
};
std::string npc_attitude_id( npc_attitude );
std::string npc_attitude_name( npc_attitude );
// Attitudes are grouped by overall behavior towards player
enum class attitude_group : int {
neutral = 0, // Doesn't particularly mind the player
hostile, // Not necessarily attacking, but also mugging, exploiting etc.
fearful, // Run
friendly // Follow, defend, listen
};
// jobs assigned to an NPC when they are stationed at a basecamp.
class job_data
{
private:
std::map<activity_id, int> task_priorities = {
{ activity_id( "ACT_MULTIPLE_BUTCHER" ), 0 },
{ activity_id( "ACT_MULTIPLE_CONSTRUCTION" ), 0 },
{ activity_id( "ACT_VEHICLE_REPAIR" ), 0 },
{ activity_id( "ACT_VEHICLE_DECONSTRUCTION" ), 0 },
{ activity_id( "ACT_MULTIPLE_FARM" ), 0 },
{ activity_id( "ACT_MULTIPLE_CHOP_TREES" ), 0 },
{ activity_id( "ACT_MULTIPLE_CHOP_PLANKS" ), 0 },
{ activity_id( "ACT_MULTIPLE_FISH" ), 0 },
{ activity_id( "ACT_MOVE_LOOT" ), 0 },
{ activity_id( "ACT_TIDY_UP" ), 0 },
};
public:
bool set_task_priority( const activity_id &task, int new_priority );
void clear_all_priorities();
bool has_job() const;
int get_priority_of_job( const activity_id &req_job ) const;
std::vector<activity_id> get_prioritised_vector() const;
void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
};
enum npc_mission : int {
NPC_MISSION_NULL = 0, // Nothing in particular
NPC_MISSION_LEGACY_1,
NPC_MISSION_SHELTER, // Stay in shelter, introduce player to game
NPC_MISSION_SHOPKEEP, // Stay still unless combat or something and sell stuff
NPC_MISSION_LEGACY_2,
NPC_MISSION_LEGACY_3,
NPC_MISSION_GUARD_ALLY, // Assigns an allied NPC to guard a position
NPC_MISSION_GUARD, // Assigns an non-allied NPC to remain in place
NPC_MISSION_GUARD_PATROL, // Assigns a non-allied NPC to guard and investigate
NPC_MISSION_ACTIVITY, // Perform a player_activity until it is complete
NPC_MISSION_TRAVELLING
};
struct npc_companion_mission {
std::string mission_id;
tripoint_abs_omt position;
std::string role_id;
std::optional<tripoint_abs_omt> destination;
};
std::string npc_class_name( const npc_class_id & );
std::string npc_class_name_str( const npc_class_id & );
enum npc_action : int;
enum npc_need {
need_none,
need_ammo, need_weapon, need_gun,
need_food, need_drink, need_safety,
num_needs
};
// TODO: Turn the personality struct into a vector/map?
enum npc_personality_type : int {
NPE_AGGRESSION,
NPE_BRAVERY,
NPE_COLLECTOR,
NPE_ALTRUISM,
NUM_NPE
};
struct npc_personality {
// All values should be in the -10 to 10 range.
signed char aggression;
signed char bravery;
signed char collector;
signed char altruism;
npc_personality() {
aggression = 0;
bravery = 0;
collector = 0;
altruism = 0;
}
void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
};
struct npc_opinion {
int trust = 0;
int fear = 0;
int value = 0;
int anger = 0;
int owed = 0; // Positive when the npc owes the player. Negative if player owes them.
npc_opinion() = default;
npc_opinion( int T, int F, int V, int A, int O ) :
trust( T ), fear( F ), value( V ), anger( A ), owed( O ) {
}
npc_opinion &operator+=( const npc_opinion &rhs ) {
trust += rhs.trust;
fear += rhs.fear;
value += rhs.value;
anger += rhs.anger;
owed += rhs.owed;
return *this;
}
npc_opinion operator+( const npc_opinion &rhs ) {
return npc_opinion( *this ) += rhs;
}
void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
};
enum class combat_engagement : int {
NONE = 0,
CLOSE,
WEAK,
HIT,
ALL,
FREE_FIRE,
NO_MOVE
};
const std::unordered_map<std::string, combat_engagement> combat_engagement_strs = { {
{ "ENGAGE_NONE", combat_engagement::NONE },
{ "ENGAGE_CLOSE", combat_engagement::CLOSE },
{ "ENGAGE_WEAK", combat_engagement::WEAK },
{ "ENGAGE_HIT", combat_engagement::HIT },
{ "ENGAGE_ALL", combat_engagement::ALL },
{ "ENGAGE_FREE_FIRE", combat_engagement::FREE_FIRE },
{ "ENGAGE_NO_MOVE", combat_engagement::NO_MOVE }
}
};
enum class aim_rule : int {
// Aim some
WHEN_CONVENIENT = 0,
// No concern for ammo efficiency
SPRAY,
// Aim when possible, then shoot
PRECISE,
// If you can't aim, don't shoot
STRICTLY_PRECISE
};
const std::unordered_map<std::string, aim_rule> aim_rule_strs = { {
{ "AIM_WHEN_CONVENIENT", aim_rule::WHEN_CONVENIENT },
{ "AIM_SPRAY", aim_rule::SPRAY },
{ "AIM_PRECISE", aim_rule::PRECISE },
{ "AIM_STRICTLY_PRECISE", aim_rule::STRICTLY_PRECISE }
}
};
// How much CBM power should remain before attempting to recharge, values are percents of power
enum class cbm_recharge_rule : int {
CBM_RECHARGE_ALL = 90,
CBM_RECHARGE_MOST = 75,
CBM_RECHARGE_SOME = 50,
CBM_RECHARGE_LITTLE = 25,
CBM_RECHARGE_NONE = 10
};
const std::unordered_map<std::string, cbm_recharge_rule> cbm_recharge_strs = { {
{ "CBM_RECHARGE_ALL", cbm_recharge_rule::CBM_RECHARGE_ALL },
{ "CBM_RECHARGE_MOST", cbm_recharge_rule::CBM_RECHARGE_MOST },
{ "CBM_RECHARGE_SOME", cbm_recharge_rule::CBM_RECHARGE_SOME },
{ "CBM_RECHARGE_LITTLE", cbm_recharge_rule::CBM_RECHARGE_LITTLE },
{ "CBM_RECHARGE_NONE", cbm_recharge_rule::CBM_RECHARGE_NONE }
}
};
// How much CBM power to reserve for defense, values are percents of total power
enum class cbm_reserve_rule : int {
CBM_RESERVE_ALL = 100,
CBM_RESERVE_MOST = 75,
CBM_RESERVE_SOME = 50,
CBM_RESERVE_LITTLE = 25,
CBM_RESERVE_NONE = 0
};
const std::unordered_map<std::string, cbm_reserve_rule> cbm_reserve_strs = { {
{ "CBM_RESERVE_ALL", cbm_reserve_rule::CBM_RESERVE_ALL },
{ "CBM_RESERVE_MOST", cbm_reserve_rule::CBM_RESERVE_MOST },
{ "CBM_RESERVE_SOME", cbm_reserve_rule::CBM_RESERVE_SOME },
{ "CBM_RESERVE_LITTLE", cbm_reserve_rule::CBM_RESERVE_LITTLE },
{ "CBM_RESERVE_NONE", cbm_reserve_rule::CBM_RESERVE_NONE }
}
};
enum class ally_rule {
DEFAULT = 0,
use_guns = 1,
use_grenades = 2,
use_silent = 4,
avoid_friendly_fire = 8,
allow_pick_up = 16,
allow_bash = 32,
allow_sleep = 64,
allow_complain = 128,
allow_pulp = 256,
close_doors = 512,
follow_close = 1024,
avoid_doors = 2048,
hold_the_line = 4096,
ignore_noise = 8192,
forbid_engage = 16384,
follow_distance_2 = 32768
};
struct ally_rule_data {
ally_rule rule = ally_rule::DEFAULT;
std::string rule_true_text;
std::string rule_false_text;
};
const std::unordered_map<std::string, ally_rule_data> ally_rule_strs = { {
{
"use_guns", {
ally_rule::use_guns,
"<ally_rule_use_guns_true_text>",
"<ally_rule_use_guns_false_text>"
}
},
{
"use_grenades", {
ally_rule::use_grenades,
"<ally_rule_use_grenades_true_text>",
"<ally_rule_use_grenades_false_text>"
}
},
{
"use_silent", {
ally_rule::use_silent,
"<ally_rule_use_silent_true_text>",
"<ally_rule_use_silent_false_text>"
}
},
{
"avoid_friendly_fire", {
ally_rule::avoid_friendly_fire,
"<ally_rule_avoid_friendly_fire_true_text>",
"<ally_rule_avoid_friendly_fire_false_text>"
}
},
{
"allow_pick_up", {
ally_rule::allow_pick_up,
"<ally_rule_allow_pick_up_true_text>",
"<ally_rule_allow_pick_up_false_text>"
}
},
{
"allow_bash", {
ally_rule::allow_bash,
"<ally_rule_allow_bash_true_text>",
"<ally_rule_allow_bash_false_text>"
}
},
{
"allow_sleep", {
ally_rule::allow_sleep,
"<ally_rule_allow_sleep_true_text>",
"<ally_rule_allow_sleep_false_text>"
}
},
{
"allow_complain", {
ally_rule::allow_complain,
"<ally_rule_allow_complain_true_text>",
"<ally_rule_allow_complain_false_text>"
}
},
{
"allow_pulp", {
ally_rule::allow_pulp,
"<ally_rule_allow_pulp_true_text>",
"<ally_rule_allow_pulp_false_text>"
}
},
{
"close_doors", {
ally_rule::close_doors,
"<ally_rule_close_doors_true_text>",
"<ally_rule_close_doors_false_text>"
}
},
{
"follow_close", {
ally_rule::follow_close,
"<ally_rule_follow_close_true_text>",
"<ally_rule_follow_close_false_text>"
}
},
{
"avoid_doors", {
ally_rule::avoid_doors,
"<ally_rule_avoid_doors_true_text>",
"<ally_rule_avoid_doors_false_text>"
}
},
{
"hold_the_line", {
ally_rule::hold_the_line,
"<ally_rule_hold_the_line_true_text>",
"<ally_rule_hold_the_line_false_text>"
}
},
{
"ignore_noise", {
ally_rule::ignore_noise,
"<ally_rule_ignore_noise_true_text>",
"<ally_rule_ignore_noise_false_text>"
}
},
{
"forbid_engage", {
ally_rule::forbid_engage,
"<ally_rule_forbid_engage_true_text>",
"<ally_rule_forbid_engage_false_text>"
}
},
{
"follow_distance_2", {
ally_rule::follow_distance_2,
"<ally_rule_follow_distance_2_true_text>",
"<ally_rule_follow_distance_2_false_text>"
}
}
}
};
struct npc_follower_rules {
combat_engagement engagement = combat_engagement::NONE;
aim_rule aim = aim_rule::WHEN_CONVENIENT;
cbm_recharge_rule cbm_recharge = cbm_recharge_rule::CBM_RECHARGE_SOME;
cbm_reserve_rule cbm_reserve = cbm_reserve_rule::CBM_RESERVE_SOME;
ally_rule flags = ally_rule::DEFAULT;
ally_rule override_enable = ally_rule::DEFAULT;
ally_rule overrides = ally_rule::DEFAULT;
pimpl<auto_pickup::npc_settings> pickup_whitelist;
npc_follower_rules();
void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
bool has_flag( ally_rule test, bool check_override = true ) const;
void set_flag( ally_rule setit );
void clear_flag( ally_rule clearit );
void toggle_flag( ally_rule toggle );
void set_specific_override_state( ally_rule, bool state );
void toggle_specific_override_state( ally_rule rule, bool state );
bool has_override_enable( ally_rule test ) const;
void enable_override( ally_rule setit );
void disable_override( ally_rule clearit );
bool has_override( ally_rule test ) const;
void set_override( ally_rule setit );
void clear_override( ally_rule clearit );
void set_danger_overrides();
void clear_overrides();
};
struct dangerous_sound {
tripoint abs_pos;
sounds::sound_t type;
int volume = 0;
};
const direction npc_threat_dir[8] = { direction::NORTHWEST, direction::NORTH, direction::NORTHEAST, direction::EAST,
direction::SOUTHEAST, direction::SOUTH, direction::SOUTHWEST, direction::WEST
};
struct healing_options {
bool bandage = false;
bool disinfect = false;
bool bleed = false;
bool bite = false;
bool infect = false;
void clear_all();
void set_all();
bool any_true();
bool all_false();
};
// Data relevant only for this action
struct npc_short_term_cache {
float danger = 0;
float total_danger = 0;
float danger_assessment = 0;
// Use weak_ptr to avoid circular references between Creatures
weak_ptr_fast<Creature> target;
// target is hostile, ally is for aiding actions
weak_ptr_fast<Creature> ally;
healing_options can_heal;
// map of positions / type / volume of suspicious sounds
std::vector<dangerous_sound> sound_alerts;
// current sound position being investigated
tripoint s_abs_pos;
// number of times we haven't moved when investigating a sound
int stuck = 0;
// Position to return to guarding
std::optional<tripoint> guard_pos;
double my_weapon_value = 0;
// Use weak_ptr to avoid circular references between Creatures
std::vector<weak_ptr_fast<Creature>> friends;
std::vector<sphere> dangerous_explosives;
std::map<direction, float> threat_map;
// Cache of locations the NPC has searched recently in npc::find_item()
lru_cache<tripoint, int> searched_tiles;
};
// DO NOT USE! This is old, use strings as talk topic instead, e.g. "TALK_AGREE_FOLLOW" instead of
// TALK_AGREE_FOLLOW. There is also convert_talk_topic which can convert the enumeration values to
// the new string values (used to load old saves).
enum talk_topic_enum {
TALK_NONE = 0, // Used to go back to last subject
TALK_DONE, // Used to end the conversation
TALK_GUARD, // End conversation, nothing to be said
TALK_MISSION_LIST, // List available missions. Intentionally placed above START
TALK_MISSION_LIST_ASSIGNED, // Same, but for assigned missions.
TALK_MISSION_START, // NOT USED; start of mission topics
TALK_MISSION_DESCRIBE, // Describe a mission
TALK_MISSION_OFFER, // Offer a mission
TALK_MISSION_ACCEPTED,
TALK_MISSION_REJECTED,
TALK_MISSION_ADVICE,
TALK_MISSION_INQUIRE,
TALK_MISSION_SUCCESS,
TALK_MISSION_SUCCESS_LIE, // Lie caught!
TALK_MISSION_FAILURE,
TALK_MISSION_END, // NOT USED: end of mission topics
TALK_MISSION_REWARD, // Intentionally placed below END
TALK_EVAC_MERCHANT, //17, Located in Refugee Center
TALK_EVAC_MERCHANT_NEW,
TALK_EVAC_MERCHANT_PLANS,
TALK_EVAC_MERCHANT_PLANS2,
TALK_EVAC_MERCHANT_PLANS3,
TALK_EVAC_MERCHANT_WORLD,
TALK_EVAC_MERCHANT_HORDES,
TALK_EVAC_MERCHANT_PRIME_LOOT,
TALK_EVAC_MERCHANT_ASK_JOIN,
TALK_EVAC_MERCHANT_NO,
TALK_EVAC_MERCHANT_HELL_NO,
TALK_FREE_MERCHANT_STOCKS,//28, Located in Refugee Center
TALK_FREE_MERCHANT_STOCKS_NEW,
TALK_FREE_MERCHANT_STOCKS_WHY,
TALK_FREE_MERCHANT_STOCKS_ALL,
TALK_FREE_MERCHANT_STOCKS_JERKY,
TALK_FREE_MERCHANT_STOCKS_CORNMEAL,
TALK_FREE_MERCHANT_STOCKS_FLOUR,
TALK_FREE_MERCHANT_STOCKS_SUGAR,
TALK_FREE_MERCHANT_STOCKS_WINE,
TALK_FREE_MERCHANT_STOCKS_BEER,
TALK_FREE_MERCHANT_STOCKS_SMMEAT,
TALK_FREE_MERCHANT_STOCKS_SMFISH,
TALK_FREE_MERCHANT_STOCKS_OIL,
TALK_FREE_MERCHANT_STOCKS_DELIVERED,
TALK_EVAC_GUARD1,//42, Located in Refugee Center
TALK_EVAC_GUARD1_PLACE,
TALK_EVAC_GUARD1_GOVERNMENT,
TALK_EVAC_GUARD1_TRADE,
TALK_EVAC_GUARD1_JOIN,
TALK_EVAC_GUARD1_JOIN2,
TALK_EVAC_GUARD1_JOIN3,
TALK_EVAC_GUARD1_ATTITUDE,
TALK_EVAC_GUARD1_JOB,
TALK_EVAC_GUARD1_OLDGUARD,
TALK_EVAC_GUARD1_BYE,
TALK_EVAC_GUARD2,//53, Located in Refugee Center
TALK_EVAC_GUARD2_NEW,
TALK_EVAC_GUARD2_RULES,
TALK_EVAC_GUARD2_RULES_BASEMENT,
TALK_EVAC_GUARD2_WHO,
TALK_EVAC_GUARD2_TRADE,
TALK_EVAC_GUARD3,//59, Located in Refugee Center
TALK_EVAC_GUARD3_NEW,
TALK_EVAC_GUARD3_RULES,
TALK_EVAC_GUARD3_HIDE1,
TALK_EVAC_GUARD3_HIDE2,
TALK_EVAC_GUARD3_WASTE,
TALK_EVAC_GUARD3_DEAD,
TALK_EVAC_GUARD3_HOSTILE,
TALK_EVAC_GUARD3_INSULT,
TALK_EVAC_HUNTER,//68, Located in Refugee Center
TALK_EVAC_HUNTER_SMELL,
TALK_EVAC_HUNTER_DO,
TALK_EVAC_HUNTER_LIFE,
TALK_EVAC_HUNTER_HUNT,
TALK_EVAC_HUNTER_SALE,
TALK_EVAC_HUNTER_ADVICE,
TALK_EVAC_HUNTER_BYE,
TALK_OLD_GUARD_REP,//76, Located in Refugee Center
TALK_OLD_GUARD_REP_NEW,
TALK_OLD_GUARD_REP_NEW_DOING,
TALK_OLD_GUARD_REP_NEW_DOWNSIDE,
TALK_OLD_GUARD_REP_WORLD,
TALK_OLD_GUARD_REP_WORLD_2NDFLEET,
TALK_OLD_GUARD_REP_WORLD_FOOTHOLDS,
TALK_OLD_GUARD_REP_ASK_JOIN,
TALK_ARSONIST,//84, Located in Refugee Center
TALK_ARSONIST_NEW,
TALK_ARSONIST_DOING,
TALK_ARSONIST_DOING_REBAR,
TALK_ARSONIST_WORLD,
TALK_ARSONIST_WORLD_OPTIMISTIC,
TALK_ARSONIST_JOIN,
TALK_ARSONIST_MUTATION,
TALK_ARSONIST_MUTATION_INSULT,
TALK_SCAVENGER_MERC,//93, Located in Refugee Center
TALK_SCAVENGER_MERC_NEW,
TALK_SCAVENGER_MERC_TIPS,
TALK_SCAVENGER_MERC_HIRE,
TALK_SCAVENGER_MERC_HIRE_SUCCESS,
TALK_SHELTER,
TALK_SHELTER_PLANS,
TALK_SHARE_EQUIPMENT,
TALK_GIVE_EQUIPMENT,
TALK_DENY_EQUIPMENT,
TALK_TRAIN,
TALK_TRAIN_START,
TALK_TRAIN_FORCE,
TALK_SUGGEST_FOLLOW,
TALK_AGREE_FOLLOW,
TALK_DENY_FOLLOW,
TALK_SHOPKEEP,
TALK_LEADER,
TALK_LEAVE,
TALK_PLAYER_LEADS,
TALK_LEADER_STAYS,
TALK_HOW_MUCH_FURTHER,
TALK_FRIEND,
TALK_FRIEND_GUARD,
TALK_DENY_GUARD,
TALK_DENY_TRAIN,
TALK_DENY_PERSONAL,
TALK_FRIEND_UNCOMFORTABLE,
TALK_COMBAT_COMMANDS,
TALK_COMBAT_ENGAGEMENT,
TALK_STRANGER_NEUTRAL,
TALK_STRANGER_WARY,
TALK_STRANGER_SCARED,
TALK_STRANGER_FRIENDLY,
TALK_STRANGER_AGGRESSIVE,
TALK_MUG,
TALK_DESCRIBE_MISSION,
TALK_WEAPON_DROPPED,
TALK_DEMAND_LEAVE,
TALK_SIZE_UP,
TALK_LOOK_AT,
TALK_OPINION,
NUM_TALK_TOPICS
};
// Function for conversion of legacy topics, defined in savegame_legacy.cpp
std::string convert_talk_topic( talk_topic_enum old_value );
struct npc_chatbin {
/**
* Add a new mission to the available missions (@ref missions). For compatibility it silently
* ignores null pointers passed to it.
*/
void add_new_mission( mission *miss );
/**
* Check that assigned missions are still assigned if not move them back to the
* unassigned vector. This is called directly before talking.
*/
void check_missions();
/**
* Missions that the NPC can give out. All missions in this vector should be unassigned,
* when given out, they should be moved to @ref missions_assigned.
*/
std::vector<mission *> missions;
/**
* Mission that have been assigned by this NPC to a player character.
*/
std::vector<mission *> missions_assigned;
/**
* The mission (if any) that we talk about right now. Can be null. Should be one of the
* missions in @ref missions or @ref missions_assigned.
*/
mission *mission_selected = nullptr;
/**
* The skill this NPC offers to train.
*/
skill_id skill = skill_id::NULL_ID();
/**
* The martial art style this NPC offers to train.
*/
matype_id style;
/**
* The spell this NPC offers to train
*/
spell_id dialogue_spell;
std::string first_topic = "TALK_NONE";
npc_chatbin() = default;
void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
};
class npc_template;
class npc : public player
{
public:
npc();
npc( const npc & ) = delete;
npc( npc && );
npc &operator=( const npc & ) = delete;
npc &operator=( npc && );
~npc() override;
bool is_player() const override {
return false;
}
bool is_npc() const override {
return true;
}
npc *as_npc() override {
return this;
}
const npc *as_npc() const override {
return this;
}
void load_npc_template( const string_id<npc_template> &ident );
void npc_dismount();
weak_ptr_fast<monster> chosen_mount;
// Generating our stats, etc.
void randomize( const npc_class_id &type = npc_class_id::NULL_ID() );
void randomize_from_faction( faction *fac );
void apply_ownership_to_inv();
// Faction version number
int get_faction_ver() const;
void set_faction_ver( int new_version );
bool has_faction_relationship( const player &p,
npc_factions::relationship flag ) const;
void set_fac( const faction_id &id );
faction *get_faction() const override;
faction_id get_fac_id() const;
/**
* Set @ref submap_coords and @ref pos.
* @param m global submap coordinates.
*/
void spawn_at_sm( const tripoint &p );
/**
* As spawn_at, but also sets position within the submap.
* Note: final submap may differ from submap_offset if @ref square has
* x/y values outside [0, SEEX-1]/[0, SEEY-1] range.
*/
void spawn_at_precise( point submap_offset, const tripoint &square );
/**
* Places the NPC on the @ref map. This update its
* pos values to fit the current offset of
* map (g->levx, g->levy).
* If the square on the map where the NPC would go is not empty
* a spiral search for an empty square around it is performed.
*/
void place_on_map();
/**
* See @ref npc_chatbin::add_new_mission
*/
void add_new_mission( mission *miss );
skill_id best_skill() const;
int best_skill_level() const;
void starting_weapon( const npc_class_id &type );
// Save & load
void deserialize( JsonIn &jsin ) override;
void serialize( JsonOut &json ) const override;
nc_color basic_symbol_color() const override;
int print_info( const catacurses::window &w, int line, int vLines, int column ) const override;
std::string opinion_text() const;
int faction_display( const catacurses::window &fac_w, int width ) const;
// Interaction with the player
void form_opinion( const player &u );
std::string pick_talk_topic( const player &u );
float character_danger( const Character &u ) const;
float vehicle_danger( int radius ) const;
void pretend_fire( npc *source, int shots, item &gun ); // fake ranged attack for hallucination
// True if our anger is at least equal to...
bool turned_hostile() const;
// ... this value!
int hostile_anger_level() const;
// Called if the player attacks us
void make_angry();
/*
* Angers and makes the NPC consider the creature an attacker
* if the creature is a player and the NPC is not already hostile
* towards the player.
*/
void on_attacked( const Creature &attacker );
int assigned_missions_value();
/**
* @return Skills of which this NPC has a higher level than the given player. In other
* words: skills this NPC could teach the player.
*/
std::vector<skill_id> skills_offered_to( const player &p ) const;
/**
* Martial art styles that we known, but the player p doesn't.
*/
std::vector<matype_id> styles_offered_to( const player &p ) const;
// State checks
// We want to kill/mug/etc the player
bool is_enemy() const;
// Traveling w/ player (whether as a friend or a slave)
bool is_following() const;
bool is_obeying( const Character &p ) const;
bool is_hallucination() const override; // true if the NPC isn't actually real
// Ally of or traveling with p
bool is_friendly( const Character &p ) const;
// Leading the player
bool is_leader() const;
// Leading, following, or waiting for the player
bool is_walking_with() const;
// In the same faction
bool is_ally( const Character &p ) const;
// Is an ally of the player
bool is_player_ally() const;
// Isn't moving
bool is_stationary( bool include_guards = true ) const;
// Has a guard mission
bool is_guarding() const;
// Has a guard patrol mission
bool is_patrolling() const;
bool within_boundaries_of_camp() const;
/** is performing a player_activity */
bool has_player_activity() const;
bool is_travelling() const;
/** Trusts you a lot. */
bool is_minion() const;
/** Is enemy or will turn into one (can't be convinced not to attack). */
bool guaranteed_hostile() const;
Attitude attitude_to( const Creature &other ) const override;
/* player allies that become guaranteed hostile should mutiny first */
void mutiny();
/** For mutant NPCs. Returns how monsters perceive said NPC. Doesn't imply NPC sees them the same. */
mfaction_id get_monster_faction() const;
// What happens when the player makes a request
// How closely do we follow the player?
int follow_distance() const;
// Dialogue and bartering--see npctalk.cpp
void talk_to_u( bool radio_contact = false );
// Re-roll the inventory of a shopkeeper
void shop_restock();
// Use and assessment of items
// The minimum value to want to pick up an item
int minimum_item_value() const;
// Find the worst value in our inventory
void update_worst_item_value();
int value( const item &it ) const;
int value( const item &it, int market_price ) const;
bool wear_if_wanted( const item &it, std::string &reason );
void start_read( item_location loc, player *pl );
void finish_read( item_location loc );
bool can_read( const item &book, std::vector<std::string> &fail_reasons );
int time_to_read( const item &book, const player &reader ) const;
void do_npc_read();
void stow_item( item &it );
bool wield( item &it ) override;
void drop( const drop_locations &what, const tripoint &target,
bool stash ) override;
bool adjust_worn();
bool has_healing_item( healing_options try_to_fix );
healing_options patient_assessment( const Character &c );
healing_options has_healing_options();
healing_options has_healing_options( healing_options try_to_fix );
item &get_healing_item( healing_options try_to_fix, bool first_best = false );
bool has_painkiller();
bool took_painkiller() const;
void use_painkiller();
void activate_item( int item_index );
bool has_artifact_with( const art_effect_passive ) const override {
return false;
}
/** Is the item safe or does the NPC trust you enough? */
bool will_accept_from_player( const item &it ) const;
bool wants_to_sell( const item &it ) const;
bool wants_to_sell( const item &/*it*/, int at_price, int market_price ) const;
bool wants_to_buy( const item &it ) const;
bool wants_to_buy( const item &/*it*/, int at_price, int /*market_price*/ ) const;
bool will_exchange_items_freely() const;
int max_credit_extended() const;
int max_willing_to_owe() const;
// AI helpers
void regen_ai_cache();
const Creature *current_target() const;
Creature *current_target();
const Creature *current_ally() const;
Creature *current_ally();
tripoint good_escape_direction( bool include_pos = true );
// Interaction and assessment of the world around us
float danger_assessment();
// Our guess at how much damage we can deal
float average_damage_dealt();
bool bravery_check( int diff );
bool emergency() const;
bool emergency( float danger ) const;
bool is_active() const;
template<typename ...Args>
void say( const char *const line, Args &&... args ) const {
return say( string_format( line, std::forward<Args>( args )... ) );
}
void say( const std::string &line, sounds::sound_t spriority = sounds::sound_t::speech ) const;
void decide_needs();
void reboot();
void die( Creature *killer ) override;
bool is_dead() const;
// How well we smash terrain (not corpses!)
int smash_ability() const;
/*
* CBM management functions
*/
void adjust_power_cbms();
void activate_combat_cbms();
void deactivate_combat_cbms();
// find items that can be used to fuel CBM rechargers
// can't use can_feed_*_with because they're private to player and too general
bool consume_cbm_items( const std::function<bool( const item & )> &filter );
// returns true if fuel resources are consumed
bool recharge_cbm();
// power is below the requested levels
bool wants_to_recharge_cbm();
// has power available to use offensive CBMs
bool can_use_offensive_cbm() const;
// return false if not present or can't be activated; true if present and already active
// or if the call activates it
bool use_bionic_by_id( const bionic_id &cbm_id, bool eff_only = false );
// return false if not present, can't be activated, or is already active; returns true if
// present and the call activates it
bool activate_bionic_by_id( const bionic_id &cbm_id, bool eff_only = false );
bool deactivate_bionic_by_id( const bionic_id &cbm_id, bool eff_only = false );
// in bionics.cpp
// can't use bionics::activate because it calls plfire directly
void discharge_cbm_weapon();
// check if an NPC has activated bionic weapons and queue them for use if applicable
void check_or_use_weapon_cbm();
// check if an NPC has toggled bionic weapon and return a map to compare
const std::map<item, bionic_id> check_toggle_cbm();
// complain about a specific issue if enough time has passed
// @param issue string identifier of the issue
// @param dur time duration between complaints
// @param force true if the complaint should happen even if not enough time has elapsed since last complaint
// @param speech words of this complaint
bool complain_about( const std::string &issue, const time_duration &dur,
const std::string &speech, bool force = false,
sounds::sound_t priority = sounds::sound_t::speech );