forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnpc.h
1465 lines (1313 loc) · 53.4 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 <new>
#include <set>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "activity_type.h"
#include "auto_pickup.h"
#include "calendar.h"
#include "character.h"
#include "color.h"
#include "coordinates.h"
#include "creature.h"
#include "dialogue_chatbin.h"
#include "enums.h"
#include "faction.h"
#include "game_constants.h"
#include "inventory.h"
#include "item.h"
#include "item_location.h"
#include "line.h"
#include "lru_cache.h"
#include "memory_fast.h"
#include "npc_attack.h"
#include "optional.h"
#include "pimpl.h"
#include "point.h"
#include "sounds.h"
#include "string_formatter.h"
#include "translations.h"
#include "type_id.h"
#include "units_fwd.h"
class JsonObject;
class JsonOut;
class JsonValue;
class mission;
class monfaction;
class monster;
class npc_class;
class talker;
class vehicle;
namespace catacurses
{
class window;
} // namespace catacurses
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>;
using drop_location = std::pair<item_location, int>;
using drop_locations = std::list<drop_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 },
{ activity_id( "ACT_MULTIPLE_DIS" ), 0}
};
public:
bool set_task_priority( const activity_id &task, int new_priority ) {
auto it = task_priorities.find( task );
if( it != task_priorities.end() ) {
task_priorities[task] = new_priority;
return true;
}
return false;
}
void clear_all_priorities() {
for( auto &elem : task_priorities ) {
elem.second = 0;
}
}
bool has_job() const {
for( const auto &elem : task_priorities ) {
if( elem.second > 0 ) {
return true;
}
}
return false;
}
int get_priority_of_job( const activity_id &req_job ) const {
auto it = task_priorities.find( req_job );
if( it != task_priorities.end() ) {
return it->second;
} else {
return 0;
}
}
std::vector<activity_id> get_prioritised_vector() const {
std::vector<std::pair<activity_id, int>> pairs( begin( task_priorities ), end( task_priorities ) );
std::vector<activity_id> ret;
sort( begin( pairs ), end( pairs ), []( const std::pair<activity_id, int> &a,
const std::pair<activity_id, int> &b ) {
return a.second > b.second;
} );
ret.reserve( pairs.size() );
for( const std::pair<activity_id, int> &elem : pairs ) {
ret.push_back( elem.first );
}
return ret;
}
void serialize( JsonOut &json ) const;
void deserialize( const JsonValue &jv );
};
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;
cata::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( const JsonObject &data );
};
struct npc_opinion {
int trust;
int fear;
int value;
int anger;
int owed; // Positive when the npc owes the player. Negative if player owes them.
int sold; // Total value of goods sold/donated by player to the npc. Cannot be negative.
npc_opinion() {
trust = 0;
fear = 0;
value = 0;
anger = 0;
owed = 0;
sold = 0;
}
npc_opinion &operator+=( const npc_opinion &rhs ) {
trust += rhs.trust;
fear += rhs.fear;
value += rhs.value;
anger += rhs.anger;
owed += rhs.owed;
sold += rhs.sold;
return *this;
}
npc_opinion operator+( const npc_opinion &rhs ) {
return npc_opinion( *this ) += rhs;
}
void serialize( JsonOut &json ) const;
void deserialize( const JsonObject &data );
};
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 : int {
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;
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;
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; // NOLINT(cata-serialize)
ally_rule override_enable = ally_rule::DEFAULT; // NOLINT(cata-serialize)
ally_rule overrides = ally_rule::DEFAULT; // NOLINT(cata-serialize)
pimpl<auto_pickup::npc_settings> pickup_whitelist;
npc_follower_rules();
void serialize( JsonOut &json ) const;
void deserialize( const JsonObject &data );
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 = sounds::sound_t::_LAST;
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.0f;
float total_danger = 0.0f;
float danger_assessment = 0.0f;
// 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
cata::optional<tripoint> guard_pos;
double my_weapon_value = 0;
npc_attack_rating current_attack_evaluation;
std::shared_ptr<npc_attack> current_attack;
// Use weak_ptr to avoid circular references between Creatures
// attitude of creatures the npc can see
std::vector<weak_ptr_fast<Creature>> hostile_guys;
std::vector<weak_ptr_fast<Creature>> neutral_guys;
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;
// returns the value of the distance between a friendly creature and the closest enemy to that
// friendly creature.
// returns nullopt if not applicable
cata::optional<int> closest_enemy_to_friendly_distance() const;
};
struct npc_need_goal_cache {
tripoint_abs_omt goal;
tripoint_abs_omt omt_loc;
};
// 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 );
class npc_template;
class npc : public Character
{
public:
npc();
npc( const npc & ) = delete;
npc( npc && ) noexcept( map_is_noexcept );
npc &operator=( const npc & ) = delete;
npc &operator=( npc && ) noexcept( list_is_noexcept );
~npc() override;
bool is_avatar() 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();
void learn_ma_styles_from_traits();
// Faction version number
int get_faction_ver() const;
void set_faction_ver( int new_version );
bool has_faction_relationship( const Character &you,
npc_factions::relationship flag ) const;
void set_fac( const faction_id &id );
faction *get_faction() const override;
faction_id get_fac_id() const;
/**
* Spawns the NPC on a random square within the given OMT.
* @param p global omt coordinates.
*/
void spawn_at_omt( const tripoint_abs_omt &p );
/**
* Spawns the NPC on the specified map square.
*/
void spawn_at_precise( const tripoint_abs_ms &p );
/**
* 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 dialogue_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( const JsonObject &data ) override;
void serialize( JsonOut &json ) const override;
// Display
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;
std::string describe_mission() const;
std::string name_and_activity() const;
/// Returns current status (Sleeping, Guarding, In Combat, etc.), or current activity
std::string get_current_status() const;
/// Returns the current activity name (reading, disassembling, etc.), or "nothing"
std::string get_current_activity() const;
// Interaction with the player
void form_opinion( const Character &you );
std::string pick_talk_topic( const Character &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 Character &you ) const;
/**
* Proficiencies we know that the character doesn't
*/
std::vector<proficiency_id> proficiencies_offered_to( const Character &guy ) const;
/**
* Martial art styles that we known, but the player p doesn't.
*/
std::vector<matype_id> styles_offered_to( const Character &you ) const;
/**
* Spells that the NPC knows but that the player p doesn't.
* not const because get_spell isn't const and both this and p call it
*/
std::vector<spell_id> spells_offered_to( Character &you );
// 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;
// true if the NPC isn't actually real
bool is_hallucination() const override {
return hallucination;
}
// true if the NPC produces electrical radiation
// TODO: make this way less hard coded
bool is_electrical() const override {
// only beep on Rubik for now
return has_trait( trait_id( "EXODII_BODY_1" ) );
}
// 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 override;
// What happens when the player makes a request
// How closely do we follow the player?
int follow_distance() const;
// 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 );
bool can_read( const item &book, std::vector<std::string> &fail_reasons );
int time_to_read( const item &book, const Character &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( item &it );
bool has_identified( const itype_id & ) const override {
return true;
}
void identify( const item & ) override {
// Do nothing
}
/**
* Is the item safe or does the NPC trust you enough?
* Is not recursive, only checks the item that is the parameter.
* to check contents, call this on the items inside the item.
*/
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;