1 #include "npc.h"
2
3 #include <algorithm>
4 #include <climits>
5 #include <cmath>
6 #include <cstdlib>
7 #include <functional>
8 #include <limits>
9 #include <memory>
10 #include <ostream>
11
12 #include "activity_type.h"
13 #include "auto_pickup.h"
14 #include "basecamp.h"
15 #include "bodypart.h"
16 #include "catacharset.h"
17 #include "character.h"
18 #include "character_id.h"
19 #include "character_martial_arts.h"
20 #include "clzones.h"
21 #include "coordinate_conversions.h"
22 #include "cursesdef.h"
23 #include "damage.h"
24 #include "debug.h"
25 #include "dialogue.h"
26 #include "dialogue_chatbin.h"
27 #include "effect.h"
28 #include "enums.h"
29 #include "event.h"
30 #include "event_bus.h"
31 #include "faction.h"
32 #include "flag.h"
33 #include "game.h"
34 #include "game_constants.h"
35 #include "game_inventory.h"
36 #include "item.h"
37 #include "item_group.h"
38 #include "itype.h"
39 #include "iuse.h"
40 #include "iuse_actor.h"
41 #include "json.h"
42 #include "magic.h"
43 #include "make_static.h"
44 #include "map.h"
45 #include "map_iterator.h"
46 #include "mapdata.h"
47 #include "messages.h"
48 #include "mission.h"
49 #include "monster.h"
50 #include "morale_types.h"
51 #include "mtype.h"
52 #include "mutation.h"
53 #include "npc_class.h"
54 #include "npctalk.h"
55 #include "options.h"
56 #include "output.h"
57 #include "overmap.h"
58 #include "overmapbuffer.h"
59 #include "pathfinding.h"
60 #include "player_activity.h"
61 #include "ret_val.h"
62 #include "rng.h"
63 #include "skill.h"
64 #include "sounds.h"
65 #include "stomach.h"
66 #include "string_formatter.h"
67 #include "talker.h"
68 #include "talker_npc.h"
69 #include "text_snippets.h"
70 #include "tileray.h"
71 #include "trait_group.h"
72 #include "translations.h"
73 #include "units.h"
74 #include "value_ptr.h"
75 #include "veh_type.h"
76 #include "vehicle.h"
77 #include "viewer.h"
78 #include "visitable.h"
79 #include "vpart_position.h"
80 #include "vpart_range.h"
81
82 static const activity_id ACT_READ( "ACT_READ" );
83
84 static const efftype_id effect_bouldering( "bouldering" );
85 static const efftype_id effect_contacts( "contacts" );
86 static const efftype_id effect_controlled( "controlled" );
87 static const efftype_id effect_drunk( "drunk" );
88 static const efftype_id effect_high( "high" );
89 static const efftype_id effect_infection( "infection" );
90 static const efftype_id effect_mending( "mending" );
91 static const efftype_id effect_npc_flee_player( "npc_flee_player" );
92 static const efftype_id effect_npc_suspend( "npc_suspend" );
93 static const efftype_id effect_pkill_l( "pkill_l" );
94 static const efftype_id effect_pkill1( "pkill1" );
95 static const efftype_id effect_pkill2( "pkill2" );
96 static const efftype_id effect_pkill3( "pkill3" );
97 static const efftype_id effect_ridden( "ridden" );
98 static const efftype_id effect_riding( "riding" );
99
100 static const itype_id itype_UPS_off( "UPS_off" );
101
102 static const skill_id skill_archery( "archery" );
103 static const skill_id skill_bashing( "bashing" );
104 static const skill_id skill_cutting( "cutting" );
105 static const skill_id skill_pistol( "pistol" );
106 static const skill_id skill_rifle( "rifle" );
107 static const skill_id skill_shotgun( "shotgun" );
108 static const skill_id skill_smg( "smg" );
109 static const skill_id skill_speech( "speech" );
110 static const skill_id skill_stabbing( "stabbing" );
111 static const skill_id skill_throw( "throw" );
112
113 static const bionic_id bio_memory( "bio_memory" );
114
115 static const trait_id trait_BEE( "BEE" );
116 static const trait_id trait_CANNIBAL( "CANNIBAL" );
117 static const trait_id trait_DEBUG_MIND_CONTROL( "DEBUG_MIND_CONTROL" );
118 static const trait_id trait_HALLUCINATION( "HALLUCINATION" );
119 static const trait_id trait_HYPEROPIC( "HYPEROPIC" );
120 static const trait_id trait_ILLITERATE( "ILLITERATE" );
121 static const trait_id trait_MUTE( "MUTE" );
122 static const trait_id trait_PROF_DICEMASTER( "PROF_DICEMASTER" );
123 static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" );
124 static const trait_id trait_SAPIOVORE( "SAPIOVORE" );
125 static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" );
126 static const trait_id trait_TERRIFYING( "TERRIFYING" );
127
128 class monfaction;
129
130 static void starting_clothes( npc &who, const npc_class_id &type, bool male );
131 static void starting_inv( npc &who, const npc_class_id &type );
132
npc()133 npc::npc()
134 : restock( calendar::turn_zero )
135 , companion_mission_time( calendar::before_time_starts )
136 , companion_mission_time_ret( calendar::before_time_starts )
137 {
138 last_updated = calendar::turn;
139 submap_coords = point_zero;
140 position.x = -1;
141 position.y = -1;
142 position.z = 500;
143 last_player_seen_pos = cata::nullopt;
144 last_seen_player_turn = 999;
145 wanted_item_pos = tripoint_min;
146 guard_pos = tripoint_min;
147 goal = tripoint_abs_omt( tripoint_min );
148 fetching_item = false;
149 has_new_items = true;
150 worst_item_value = 0;
151 str_max = 0;
152 dex_max = 0;
153 int_max = 0;
154 per_max = 0;
155 marked_for_death = false;
156 death_drops = true;
157 dead = false;
158 hit_by_player = false;
159 hallucination = false;
160 moves = 100;
161 mission = NPC_MISSION_NULL;
162 myclass = npc_class_id::NULL_ID();
163 fac_id = faction_id::NULL_ID();
164 patience = 0;
165 attitude = NPCATT_NULL;
166
167 *path_settings = pathfinding_settings( 0, 1000, 1000, 10, true, true, true, false, true );
168 for( direction threat_dir : npc_threat_dir ) {
169 ai_cache.threat_map[ threat_dir ] = 0.0f;
170 }
171 }
172
standard_npc(const std::string & name,const tripoint & pos,const std::vector<std::string> & clothing,int sk_lvl,int s_str,int s_dex,int s_int,int s_per)173 standard_npc::standard_npc( const std::string &name, const tripoint &pos,
174 const std::vector<std::string> &clothing,
175 int sk_lvl, int s_str, int s_dex, int s_int, int s_per )
176 {
177 this->name = name;
178 position = pos;
179
180 str_cur = std::max( s_str, 0 );
181 str_max = std::max( s_str, 0 );
182 dex_cur = std::max( s_dex, 0 );
183 dex_max = std::max( s_dex, 0 );
184 per_cur = std::max( s_per, 0 );
185 per_max = std::max( s_per, 0 );
186 int_cur = std::max( s_int, 0 );
187 int_max = std::max( s_int, 0 );
188
189 set_body();
190 recalc_hp();
191
192 for( const Skill &e : Skill::skills ) {
193 set_skill_level( e.ident(), std::max( sk_lvl, 0 ) );
194 }
195
196 for( const std::string &e : clothing ) {
197 wear_item( item( e ), false );
198 }
199
200 for( item &e : worn ) {
201 if( e.has_flag( flag_VARSIZE ) ) {
202 e.set_flag( flag_FIT );
203 }
204 }
205 }
206
207 npc::npc( npc && ) = default;
208 npc &npc::operator=( npc && ) = default;
209
210 static std::map<string_id<npc_template>, npc_template> npc_templates;
211
load(const JsonObject & jsobj)212 void npc_template::load( const JsonObject &jsobj )
213 {
214 npc_template tem;
215 npc &guy = tem.guy;
216 guy.idz = jsobj.get_string( "id" );
217 guy.name.clear();
218 jsobj.read( "name_unique", tem.name_unique );
219 jsobj.read( "name_suffix", tem.name_suffix );
220 if( jsobj.has_string( "gender" ) ) {
221 if( jsobj.get_string( "gender" ) == "male" ) {
222 tem.gender_override = gender::male;
223 } else {
224 tem.gender_override = gender::female;
225 }
226 } else {
227 tem.gender_override = gender::random;
228 }
229 if( jsobj.has_string( "faction" ) ) {
230 guy.set_fac_id( jsobj.get_string( "faction" ) );
231 }
232
233 if( jsobj.has_int( "class" ) ) {
234 guy.myclass = npc_class::from_legacy_int( jsobj.get_int( "class" ) );
235 } else if( jsobj.has_string( "class" ) ) {
236 guy.myclass = npc_class_id( jsobj.get_string( "class" ) );
237 }
238
239 guy.set_attitude( static_cast<npc_attitude>( jsobj.get_int( "attitude" ) ) );
240 guy.mission = static_cast<npc_mission>( jsobj.get_int( "mission" ) );
241 guy.chatbin.first_topic = jsobj.get_string( "chat" );
242 if( jsobj.has_string( "mission_offered" ) ) {
243 guy.miss_ids.emplace_back( mission_type_id( jsobj.get_string( "mission_offered" ) ) );
244 } else if( jsobj.has_array( "mission_offered" ) ) {
245 for( const std::string line : jsobj.get_array( "mission_offered" ) ) {
246 guy.miss_ids.emplace_back( mission_type_id( line ) );
247 }
248 }
249 npc_templates.emplace( string_id<npc_template>( guy.idz ), std::move( tem ) );
250 }
251
reset()252 void npc_template::reset()
253 {
254 npc_templates.clear();
255 }
256
check_consistency()257 void npc_template::check_consistency()
258 {
259 for( const auto &e : npc_templates ) {
260 const auto &guy = e.second.guy;
261 if( !guy.myclass.is_valid() ) {
262 debugmsg( "Invalid NPC class %s", guy.myclass.c_str() );
263 }
264 std::string first_topic = guy.chatbin.first_topic;
265 if( const json_talk_topic *topic = get_talk_topic( first_topic ) ) {
266 cata::flat_set<std::string> reachable_topics =
267 topic->get_directly_reachable_topics( true );
268 if( reachable_topics.count( "TALK_MISSION_OFFER" ) ) {
269 debugmsg(
270 "NPC template \"%s\" has dialogue \"%s\" which leads unconditionally to "
271 "\"TALK_MISSION_OFFER\", which doesn't check for an available mission. "
272 "You should probably prefer \"TALK_MISSION_LIST\"",
273 e.first.str(), first_topic );
274 }
275 }
276 }
277 }
278
279 template<>
is_valid() const280 bool string_id<npc_template>::is_valid() const
281 {
282 return npc_templates.count( *this ) > 0;
283 }
284
285 template<>
obj() const286 const npc_template &string_id<npc_template>::obj() const
287 {
288 const auto found = npc_templates.find( *this );
289 if( found == npc_templates.end() ) {
290 debugmsg( "Tried to get invalid npc: %s", c_str() );
291 static const npc_template dummy{};
292 return dummy;
293 }
294 return found->second;
295 }
296
load_npc_template(const string_id<npc_template> & ident)297 void npc::load_npc_template( const string_id<npc_template> &ident )
298 {
299 auto found = npc_templates.find( ident );
300 if( found == npc_templates.end() ) {
301 debugmsg( "Tried to get invalid npc: %s", ident.c_str() );
302 return;
303 }
304 const npc_template &tem = found->second;
305 const npc &tguy = tem.guy;
306
307 idz = tguy.idz;
308 myclass = npc_class_id( tguy.myclass );
309 randomize( myclass );
310 if( !tem.name_unique.empty() ) {
311 name = tem.name_unique.translated();
312 }
313 if( !tem.name_suffix.empty() ) {
314 //~ %1$s: npc name, %2$s: name suffix
315 name = string_format( pgettext( "npc name", "%1$s, %2$s" ), name, tem.name_suffix );
316 }
317 if( tem.gender_override != npc_template::gender::random ) {
318 male = tem.gender_override == npc_template::gender::male;
319 }
320 fac_id = tguy.fac_id;
321 set_fac( fac_id );
322 attitude = tguy.attitude;
323 mission = tguy.mission;
324 chatbin.first_topic = tguy.chatbin.first_topic;
325 for( const mission_type_id &miss_id : tguy.miss_ids ) {
326 add_new_mission( mission::reserve_new( miss_id, getID() ) );
327 }
328 }
329
330 npc::~npc() = default;
331
randomize(const npc_class_id & type)332 void npc::randomize( const npc_class_id &type )
333 {
334 if( !getID().is_valid() ) {
335 setID( g->assign_npc_id() );
336 }
337
338 weapon = item( "null", calendar::turn_zero );
339 inv->clear();
340 personality.aggression = rng( -10, 10 );
341 personality.bravery = rng( -3, 10 );
342 personality.collector = rng( -1, 10 );
343 personality.altruism = rng( -10, 10 );
344 moves = 100;
345 mission = NPC_MISSION_NULL;
346 male = one_in( 2 );
347 pick_name();
348
349 if( !type.is_valid() ) {
350 debugmsg( "Invalid NPC class %s", type.c_str() );
351 myclass = npc_class_id::NULL_ID();
352 } else if( type.is_null() ) {
353 myclass = npc_class::random_common();
354 } else {
355 myclass = type;
356 }
357
358 const auto &the_class = myclass.obj();
359 str_max = the_class.roll_strength();
360 dex_max = the_class.roll_dexterity();
361 int_max = the_class.roll_intelligence();
362 per_max = the_class.roll_perception();
363
364 for( auto &skill : Skill::skills ) {
365 int level = myclass->roll_skill( skill.ident() );
366
367 set_skill_level( skill.ident(), level );
368 }
369
370 if( type.is_null() ) { // Untyped; no particular specialization
371 } else if( type == NC_EVAC_SHOPKEEP ) {
372 personality.collector += rng( 1, 5 );
373
374 } else if( type == NC_BARTENDER ) {
375 personality.collector += rng( 1, 5 );
376
377 } else if( type == NC_JUNK_SHOPKEEP ) {
378 personality.collector += rng( 1, 5 );
379
380 } else if( type == NC_ARSONIST ) {
381 personality.aggression += rng( 0, 1 );
382 personality.collector += rng( 0, 2 );
383
384 } else if( type == NC_SOLDIER ) {
385 personality.aggression += rng( 1, 3 );
386 personality.bravery += rng( 0, 5 );
387
388 } else if( type == NC_HACKER ) {
389 personality.bravery -= rng( 1, 3 );
390 personality.aggression -= rng( 0, 2 );
391
392 } else if( type == NC_DOCTOR ) {
393 personality.aggression -= rng( 0, 4 );
394 cash += 10000 * rng( 0, 3 ) * rng( 0, 3 );
395
396 } else if( type == NC_TRADER ) {
397 personality.collector += rng( 1, 5 );
398 cash += 25000 * rng( 1, 10 );
399
400 } else if( type == NC_NINJA ) {
401 personality.bravery += rng( 0, 3 );
402 personality.collector -= rng( 1, 6 );
403 // TODO: give ninja his styles back
404
405 } else if( type == NC_COWBOY ) {
406 personality.aggression += rng( 0, 2 );
407 personality.bravery += rng( 1, 5 );
408
409 } else if( type == NC_SCIENTIST ) {
410 personality.aggression -= rng( 1, 5 );
411 personality.bravery -= rng( 2, 8 );
412 personality.collector += rng( 0, 2 );
413
414 } else if( type == NC_BOUNTY_HUNTER ) {
415 personality.aggression += rng( 1, 6 );
416 personality.bravery += rng( 0, 5 );
417
418 } else if( type == NC_THUG ) {
419 personality.aggression += rng( 1, 6 );
420 personality.bravery += rng( 0, 5 );
421
422 } else if( type == NC_SCAVENGER ) {
423 personality.aggression += rng( 1, 3 );
424 personality.bravery += rng( 1, 4 );
425
426 }
427 //A universal barter boost to keep NPCs competitive with players
428 //The int boost from trade wasn't active... now that it is, most
429 //players will vastly outclass npcs in trade without a little help.
430 mod_skill_level( skill_speech, rng( 2, 4 ) );
431
432 set_body();
433 recalc_hp();
434
435 starting_weapon( myclass );
436 starting_clothes( *this, myclass, male );
437 starting_inv( *this, myclass );
438 has_new_items = true;
439 clear_mutations();
440
441 // Add fixed traits
442 for( const auto &tid : trait_group::traits_from( myclass->traits ) ) {
443 set_mutation( tid );
444 }
445
446 // Run mutation rounds
447 for( const auto &mr : type->mutation_rounds ) {
448 int rounds = mr.second.roll();
449 for( int i = 0; i < rounds; ++i ) {
450 mutate_category( mr.first );
451 }
452 }
453 // Add bionics
454 for( const auto &bl : type->bionic_list ) {
455 int chance = bl.second;
456 if( rng( 0, 100 ) <= chance ) {
457 add_bionic( bl.first );
458 }
459 }
460 // Add proficiencies
461 for( const proficiency_id &prof : type->_starting_proficiencies ) {
462 add_proficiency( prof );
463 }
464 // Add spells for magiclysm mod
465 for( std::pair<spell_id, int> spell_pair : type->_starting_spells ) {
466 this->magic->learn_spell( spell_pair.first, *this, true );
467 spell &sp = this->magic->get_spell( spell_pair.first );
468 while( sp.get_level() < spell_pair.second && !sp.is_max_level() ) {
469 sp.gain_level();
470 }
471 }
472 }
473
randomize_from_faction(faction * fac)474 void npc::randomize_from_faction( faction *fac )
475 {
476 // Personality = aggression, bravery, altruism, collector
477 set_fac( fac->id );
478 randomize( npc_class_id::NULL_ID() );
479 }
480
set_fac(const faction_id & id)481 void npc::set_fac( const faction_id &id )
482 {
483 if( my_fac ) {
484 my_fac->remove_member( getID() );
485 }
486 my_fac = g->faction_manager_ptr->get( id );
487 if( my_fac ) {
488 if( !is_fake() && !is_hallucination() ) {
489 my_fac->add_to_membership( getID(), disp_name(), known_to_u );
490 }
491 fac_id = my_fac->id;
492 } else {
493 return;
494 }
495 apply_ownership_to_inv();
496 }
497
apply_ownership_to_inv()498 void npc::apply_ownership_to_inv()
499 {
500 for( auto &e : inv_dump() ) {
501 e->set_owner( *this );
502 }
503 }
504
get_fac_id() const505 faction_id npc::get_fac_id() const
506 {
507 return fac_id;
508 }
509
get_faction() const510 faction *npc::get_faction() const
511 {
512 if( !my_fac ) {
513 return g->faction_manager_ptr->get( faction_id( "no_faction" ) );
514 }
515 return my_fac;
516 }
517
518 // item id from group "<class-name>_<what>" or from fallback group
519 // may still be a null item!
random_item_from(const npc_class_id & type,const std::string & what,const item_group_id & fallback)520 static item random_item_from( const npc_class_id &type, const std::string &what,
521 const item_group_id &fallback )
522 {
523 item result = item_group::item_from( item_group_id( type.str() + "_" + what ), calendar::turn );
524 if( result.is_null() ) {
525 result = item_group::item_from( fallback, calendar::turn );
526 }
527 return result;
528 }
529
530 // item id from "<class-name>_<what>" or from "npc_<what>"
random_item_from(const npc_class_id & type,const std::string & what)531 static item random_item_from( const npc_class_id &type, const std::string &what )
532 {
533 return random_item_from( type, what, item_group_id( "npc_" + what ) );
534 }
535
536 // item id from "<class-name>_<what>_<gender>" or from "npc_<what>_<gender>"
get_clothing_item(const npc_class_id & type,const std::string & what,bool male)537 static item get_clothing_item( const npc_class_id &type, const std::string &what, bool male )
538 {
539 item result;
540 //Check if class has gendered clothing
541 //Then check if it has an ungendered version
542 //Only if all that fails, grab from the default class.
543 if( male ) {
544 result = random_item_from( type, what + "_male", item_group_id::NULL_ID() );
545 } else {
546 result = random_item_from( type, what + "_female", item_group_id::NULL_ID() );
547 }
548 if( result.is_null() ) {
549 if( male ) {
550 result = random_item_from( type, what, item_group_id( "npc_" + what + "_male" ) );
551 } else {
552 result = random_item_from( type, what, item_group_id( "npc_" + what + "_female" ) );
553 }
554 }
555
556 return result;
557 }
558
starting_clothes(npc & who,const npc_class_id & type,bool male)559 void starting_clothes( npc &who, const npc_class_id &type, bool male )
560 {
561 std::vector<item> ret;
562 if( item_group::group_is_defined( type->worn_override ) ) {
563 ret = item_group::items_from( type->worn_override );
564 } else {
565 ret.push_back( get_clothing_item( type, "pants", male ) );
566 ret.push_back( get_clothing_item( type, "shirt", male ) );
567 ret.push_back( get_clothing_item( type, "underwear_top", male ) );
568 ret.push_back( get_clothing_item( type, "underwear_bottom", male ) );
569 ret.push_back( get_clothing_item( type, "underwear_feet", male ) );
570 ret.push_back( get_clothing_item( type, "shoes", male ) );
571 ret.push_back( random_item_from( type, "gloves" ) );
572 ret.push_back( random_item_from( type, "coat" ) );
573 ret.push_back( random_item_from( type, "vest" ) );
574 ret.push_back( random_item_from( type, "masks" ) );
575 // Why is the alternative group not named "npc_glasses" but "npc_eyes"?
576 ret.push_back( random_item_from( type, "glasses", item_group_id( "npc_eyes" ) ) );
577 ret.push_back( random_item_from( type, "hat" ) );
578 ret.push_back( random_item_from( type, "scarf" ) );
579 ret.push_back( random_item_from( type, "storage" ) );
580 ret.push_back( random_item_from( type, "holster" ) );
581 ret.push_back( random_item_from( type, "belt" ) );
582 ret.push_back( random_item_from( type, "wrist" ) );
583 ret.push_back( random_item_from( type, "extra" ) );
584 }
585
586 for( item &it : who.worn ) {
587 it.on_takeoff( who );
588 }
589 who.worn.clear();
590 for( item &it : ret ) {
591 if( it.has_flag( flag_VARSIZE ) ) {
592 it.set_flag( flag_FIT );
593 }
594 if( who.can_wear( it ).success() ) {
595 it.on_wear( who );
596 who.worn.push_back( it );
597 it.set_owner( who );
598 }
599 }
600 }
601
starting_inv(npc & who,const npc_class_id & type)602 void starting_inv( npc &who, const npc_class_id &type )
603 {
604 std::list<item> res;
605 who.inv->clear();
606 if( item_group::group_is_defined( type->carry_override ) ) {
607 *who.inv += item_group::items_from( type->carry_override );
608 return;
609 }
610
611 item lighter( "lighter" );
612 // Set lighter ammo
613 if( !lighter.ammo_default().is_null() ) {
614 lighter.ammo_set( lighter.ammo_default(), rng( 10, 100 ) );
615 }
616 res.emplace_back( lighter );
617 // If wielding a gun, get some additional ammo for it
618 if( who.weapon.is_gun() ) {
619 item ammo;
620 if( !who.weapon.magazine_default().is_null() ) {
621 item mag( who.weapon.magazine_default() );
622 mag.ammo_set( mag.ammo_default() );
623 ammo = item( mag.ammo_default() );
624 res.push_back( mag );
625 } else if( !who.weapon.ammo_default().is_null() ) {
626 ammo = item( who.weapon.ammo_default() );
627 // TODO: Move to npc_class
628 // NC_COWBOY and NC_BOUNTY_HUNTER get 5-15 whilst all others get 3-6
629 int qty = 1 + ( type == NC_COWBOY ||
630 type == NC_BOUNTY_HUNTER );
631 qty = rng( qty, qty * 2 );
632
633 while( qty-- != 0 && who.can_stash( ammo ) ) {
634 res.push_back( ammo );
635 }
636 }
637 }
638
639 if( type == NC_ARSONIST ) {
640 res.emplace_back( "molotov" );
641 }
642
643 int qty = ( type == NC_EVAC_SHOPKEEP ||
644 type == NC_TRADER ) ? 5 : 2;
645 qty = rng( qty, qty * 3 );
646
647 while( qty-- != 0 ) {
648 item tmp = random_item_from( type, "misc" ).in_its_container();
649 if( !tmp.is_null() ) {
650 if( !one_in( 3 ) && tmp.has_flag( flag_VARSIZE ) ) {
651 tmp.set_flag( flag_FIT );
652 }
653 if( who.can_pickVolume( tmp ) ) {
654 res.push_back( tmp );
655 }
656 }
657 }
658
659 res.erase( std::remove_if( res.begin(), res.end(), [&]( const item & e ) {
660 return e.has_flag( flag_TRADER_AVOID );
661 } ), res.end() );
662 for( auto &it : res ) {
663 it.set_owner( who );
664 }
665 *who.inv += res;
666 }
667
revert_after_activity()668 void npc::revert_after_activity()
669 {
670 mission = previous_mission;
671 attitude = previous_attitude;
672 activity = player_activity();
673 current_activity_id = activity_id::NULL_ID();
674 clear_destination();
675 backlog.clear();
676 }
677
get_previous_mission()678 npc_mission npc::get_previous_mission()
679 {
680 return previous_mission;
681 }
682
get_previous_attitude()683 npc_attitude npc::get_previous_attitude()
684 {
685 return previous_attitude;
686 }
687
get_known_to_u()688 bool npc::get_known_to_u()
689 {
690 return known_to_u;
691 }
692
set_known_to_u(bool known)693 void npc::set_known_to_u( bool known )
694 {
695 known_to_u = known;
696 if( my_fac ) {
697 my_fac->add_to_membership( getID(), disp_name(), known_to_u );
698 }
699 }
700
setpos(const tripoint & pos)701 void npc::setpos( const tripoint &pos )
702 {
703 position = pos;
704 const point_abs_om pos_om_old( sm_to_om_copy( submap_coords ) );
705 submap_coords = get_map().get_abs_sub().xy() + point( pos.x / SEEX, pos.y / SEEY );
706 // TODO: fix point types
707 const point_abs_om pos_om_new( sm_to_om_copy( submap_coords ) );
708 if( !is_fake() && pos_om_old != pos_om_new ) {
709 overmap &om_old = overmap_buffer.get( pos_om_old );
710 overmap &om_new = overmap_buffer.get( pos_om_new );
711 if( const auto ptr = om_old.erase_npc( getID() ) ) {
712 om_new.insert_npc( ptr );
713 } else {
714 // Don't move the npc pointer around to avoid having two overmaps
715 // with the same npc pointer
716 debugmsg( "could not find npc %s on its old overmap", name );
717 }
718 }
719 }
720
travel_overmap(const tripoint & pos)721 void npc::travel_overmap( const tripoint &pos )
722 {
723 // TODO: fix point types
724 const point_abs_om pos_om_old( sm_to_om_copy( submap_coords ) );
725 spawn_at_sm( pos );
726 const point_abs_om pos_om_new( sm_to_om_copy( submap_coords ) );
727 if( global_omt_location() == goal ) {
728 reach_omt_destination();
729 }
730 if( !is_fake() && pos_om_old != pos_om_new ) {
731 overmap &om_old = overmap_buffer.get( pos_om_old );
732 overmap &om_new = overmap_buffer.get( pos_om_new );
733 if( const auto ptr = om_old.erase_npc( getID() ) ) {
734 om_new.insert_npc( ptr );
735 } else {
736 // Don't move the npc pointer around to avoid having two overmaps
737 // with the same npc pointer
738 debugmsg( "could not find npc %s on its old overmap", name );
739 }
740 }
741 }
742
spawn_at_sm(const tripoint & p)743 void npc::spawn_at_sm( const tripoint &p )
744 {
745 spawn_at_precise( p.xy(), tripoint( rng( 0, SEEX - 1 ), rng( 0, SEEY - 1 ), p.z ) );
746 }
747
spawn_at_precise(const point & submap_offset,const tripoint & square)748 void npc::spawn_at_precise( const point &submap_offset, const tripoint &square )
749 {
750 submap_coords = submap_offset;
751 submap_coords.x += square.x / SEEX;
752 submap_coords.y += square.y / SEEY;
753 position.x = square.x % SEEX;
754 position.y = square.y % SEEY;
755 position.z = square.z;
756 }
757
global_square_location() const758 tripoint npc::global_square_location() const
759 {
760 return sm_to_ms_copy( submap_coords ) + tripoint( posx() % SEEX, posy() % SEEY, position.z );
761 }
762
place_on_map()763 void npc::place_on_map()
764 {
765 // The global absolute position (in map squares) of the npc is *always*
766 // "submap_coords.x * SEEX + posx() % SEEX" (analog for y).
767 // The main map assumes that pos is in its own (local to the main map)
768 // coordinate system. We have to change pos to match that assumption
769 const point dm( submap_coords - get_map().get_abs_sub().xy() );
770 const point offset( position.x % SEEX, position.y % SEEY );
771 // value of "submap_coords.x * SEEX + posx()" is unchanged
772 setpos( tripoint( offset.x + dm.x * SEEX, offset.y + dm.y * SEEY, posz() ) );
773
774 if( g->is_empty( pos() ) || is_mounted() ) {
775 return;
776 }
777
778 for( const tripoint &p : closest_points_first( pos(), SEEX + 1 ) ) {
779 if( g->is_empty( p ) ) {
780 setpos( p );
781 return;
782 }
783 }
784
785 debugmsg( "Failed to place NPC in a valid location near (%d,%d,%d)", posx(), posy(), posz() );
786 }
787
best_skill() const788 skill_id npc::best_skill() const
789 {
790 int highest_level = std::numeric_limits<int>::min();
791 skill_id highest_skill( skill_id::NULL_ID() );
792
793 for( const auto &p : *_skills ) {
794 if( p.first.obj().is_combat_skill() ) {
795 const int level = p.second.level();
796 if( level > highest_level ) {
797 highest_level = level;
798 highest_skill = p.first;
799 }
800 }
801 }
802
803 return highest_skill;
804 }
805
best_skill_level() const806 int npc::best_skill_level() const
807 {
808 int highest_level = std::numeric_limits<int>::min();
809
810 for( const auto &p : *_skills ) {
811 if( p.first.obj().is_combat_skill() ) {
812 const int level = p.second.level();
813 if( level > highest_level ) {
814 highest_level = level;
815 }
816 }
817 }
818
819 return highest_level;
820 }
821
starting_weapon(const npc_class_id & type)822 void npc::starting_weapon( const npc_class_id &type )
823 {
824 if( item_group::group_is_defined( type->weapon_override ) ) {
825 weapon = item_group::item_from( type->weapon_override, calendar::turn );
826 return;
827 }
828
829 const skill_id best = best_skill();
830
831 // if NPC has no suitable skills default to stabbing weapon
832 if( !best || best == skill_stabbing ) {
833 weapon = random_item_from( type, "stabbing", item_group_id( "survivor_stabbing" ) );
834 } else if( best == skill_bashing ) {
835 weapon = random_item_from( type, "bashing", item_group_id( "survivor_bashing" ) );
836 } else if( best == skill_cutting ) {
837 weapon = random_item_from( type, "cutting", item_group_id( "survivor_cutting" ) );
838 } else if( best == skill_throw ) {
839 weapon = random_item_from( type, "throw" );
840 } else if( best == skill_archery ) {
841 weapon = random_item_from( type, "archery" );
842 } else if( best == skill_pistol ) {
843 weapon = random_item_from( type, "pistol", item_group_id( "guns_pistol_common" ) );
844 } else if( best == skill_shotgun ) {
845 weapon = random_item_from( type, "shotgun", item_group_id( "guns_shotgun_common" ) );
846 } else if( best == skill_smg ) {
847 weapon = random_item_from( type, "smg", item_group_id( "guns_smg_common" ) );
848 } else if( best == skill_rifle ) {
849 weapon = random_item_from( type, "rifle", item_group_id( "guns_rifle_common" ) );
850 }
851
852 if( weapon.is_gun() ) {
853 if( !weapon.magazine_default().is_null() ) {
854 weapon.ammo_set( weapon.magazine_default()->magazine->default_ammo );
855 } else if( !weapon.ammo_default().is_null() ) {
856 weapon.ammo_set( weapon.ammo_default() );
857 } else {
858 debugmsg( "tried setting ammo for %s which has no magazine or ammo", weapon.typeId().c_str() );
859 }
860 //You should be able to wield your starting weapon
861 if( !meets_stat_requirements( weapon ) ) {
862 if( weapon.get_min_str() > get_str() ) {
863 str_max = weapon.get_min_str();
864 }
865 if( weapon.type->min_dex > get_dex() ) {
866 dex_max = weapon.type->min_dex;
867 }
868 if( weapon.type->min_int > get_int() ) {
869 int_max = weapon.type->min_int;
870 }
871 if( weapon.type->min_per > get_per() ) {
872 per_max = weapon.type->min_per;
873 }
874 }
875 }
876
877 get_event_bus().send<event_type::character_wields_item>( getID(), weapon.typeId() );
878
879 weapon.set_owner( get_faction()->id );
880 }
881
can_read(const item & book,std::vector<std::string> & fail_reasons)882 bool npc::can_read( const item &book, std::vector<std::string> &fail_reasons )
883 {
884 if( !book.is_book() ) {
885 fail_reasons.push_back( string_format( _( "This %s is not good reading material." ),
886 book.tname() ) );
887 return false;
888 }
889 player *pl = dynamic_cast<player *>( this );
890 if( !pl ) {
891 return false;
892 }
893 const auto &type = book.type->book;
894 const skill_id &skill = type->skill;
895 const int skill_level = pl->get_skill_level( skill );
896 if( skill && skill_level < type->req ) {
897 fail_reasons.push_back( string_format( _( "I'm not smart enough to read this book." ) ) );
898 return false;
899 }
900 if( !skill || skill_level >= type->level ) {
901 fail_reasons.push_back( string_format( _( "I won't learn anything from this book." ) ) );
902 return false;
903 }
904
905 // Check for conditions that disqualify us
906 if( type->intel > 0 && has_trait( trait_ILLITERATE ) ) {
907 fail_reasons.emplace_back( _( "I can't read!" ) );
908 } else if( has_trait( trait_HYPEROPIC ) && !worn_with_flag( flag_FIX_FARSIGHT ) &&
909 !has_effect( effect_contacts ) &&
910 !has_flag( STATIC( json_character_flag( "ENHANCED_VISION" ) ) ) ) {
911 fail_reasons.emplace_back( _( "I can't read without my glasses." ) );
912 } else if( fine_detail_vision_mod() > 4 ) {
913 // Too dark to read only applies if the player can read to himself
914 fail_reasons.emplace_back( _( "It's too dark to read!" ) );
915 return false;
916 }
917 return true;
918 }
919
time_to_read(const item & book,const player & reader) const920 int npc::time_to_read( const item &book, const player &reader ) const
921 {
922 const auto &type = book.type->book;
923 const skill_id &skill = type->skill;
924 // The reader's reading speed has an effect only if they're trying to understand the book as they read it
925 // Reading speed is assumed to be how well you learn from books (as opposed to hands-on experience)
926 const bool try_understand = reader.fun_to_read( book ) ||
927 reader.get_skill_level( skill ) < type->level;
928 int reading_speed = try_understand ? std::max( reader.read_speed(), read_speed() ) : read_speed();
929
930 int retval = type->time * reading_speed;
931 retval *= std::min( fine_detail_vision_mod(), reader.fine_detail_vision_mod() );
932
933 if( type->intel > reader.get_int() && !reader.has_trait( trait_PROF_DICEMASTER ) ) {
934 retval += type->time * ( type->intel - reader.get_int() ) * 100;
935 }
936 return retval;
937 }
938
finish_read(item & book)939 void npc::finish_read( item &book )
940 {
941 const auto &reading = book.type->book;
942 if( !reading ) {
943 revert_after_activity();
944 return;
945 }
946 const skill_id &skill = reading->skill;
947 // NPCs don't need to identify the book or learn recipes yet.
948 // NPCs don't read to other NPCs yet.
949 const bool display_messages = my_fac->id == faction_id( "your_followers" ) &&
950 get_player_view().sees( pos() );
951 bool continuous = false; //whether to continue reading or not
952
953 if( book_fun_for( book, *this ) != 0 ) {
954 //Fun bonus is no longer calculated here.
955 add_morale( MORALE_BOOK, book_fun_for( book, *this ) * 5, book_fun_for( book,
956 *this ) * 15, 1_hours, 30_minutes, true,
957 book.type );
958 }
959
960 book.mark_chapter_as_read( *this );
961
962 if( skill && get_skill_level( skill ) < reading->level &&
963 get_skill_level_object( skill ).can_train() ) {
964 SkillLevel &skill_level = get_skill_level_object( skill );
965 const int originalSkillLevel = skill_level.level();
966
967 // Calculate experience gained
968 /** @EFFECT_INT increases reading comprehension */
969 // Enhanced Memory Banks modestly boosts experience
970 int min_ex = std::max( 1, reading->time / 10 + get_int() / 4 );
971 int max_ex = reading->time / 5 + get_int() / 2 - originalSkillLevel;
972 if( has_active_bionic( bio_memory ) ) {
973 min_ex += 2;
974 }
975 if( max_ex < 2 ) {
976 max_ex = 2;
977 }
978 if( max_ex > 10 ) {
979 max_ex = 10;
980 }
981 if( max_ex < min_ex ) {
982 max_ex = min_ex;
983 }
984 const std::string &s = activity.get_str_value( 0, "1" );
985 double penalty = strtod( s.c_str(), nullptr );
986 min_ex *= ( originalSkillLevel + 1 ) * penalty;
987 min_ex = std::max( min_ex, 1 );
988 max_ex *= ( originalSkillLevel + 1 ) * penalty;
989 max_ex = std::max( min_ex, max_ex );
990
991 skill_level.readBook( min_ex, max_ex, reading->level );
992 const std::string skill_name = skill.obj().name();
993 if( skill_level != originalSkillLevel ) {
994 get_event_bus().send<event_type::gains_skill_level>( getID(), skill, skill_level.level() );
995 if( display_messages ) {
996 add_msg( m_good, _( "%s increases their %s level." ), disp_name(), skill_name );
997 // NPC reads until they gain a level, then stop.
998 revert_after_activity();
999 return;
1000 }
1001 } else {
1002 continuous = true;
1003 if( display_messages ) {
1004 add_msg( m_info, _( "%s learns a little about %s!" ), disp_name(), skill_name );
1005 }
1006 }
1007
1008 if( ( skill_level == reading->level || !skill_level.can_train() ) ||
1009 ( has_trait( trait_SCHIZOPHRENIC ) && one_in( 25 ) ) ) {
1010 if( display_messages ) {
1011 add_msg( m_info, _( "%s can no longer learn from %s." ), disp_name(), book.type_name() );
1012 }
1013 }
1014 } else if( skill ) {
1015 if( display_messages ) {
1016 add_msg( m_info, _( "%s can no longer learn from %s." ), disp_name(), book.type_name() );
1017 }
1018 }
1019
1020 // NPCs can't learn martial arts from manuals (yet)
1021
1022 if( continuous ) {
1023 activity.set_to_null();
1024 player *pl = dynamic_cast<player *>( this );
1025 if( pl ) {
1026 start_read( book, pl );
1027 }
1028 if( activity ) {
1029 return;
1030 }
1031 }
1032 activity.set_to_null();
1033 revert_after_activity();
1034 }
1035
start_read(item & chosen,player * pl)1036 void npc::start_read( item &chosen, player *pl )
1037 {
1038 const int time_taken = time_to_read( chosen, *pl );
1039 const double penalty = static_cast<double>( time_taken ) / time_to_read( chosen, *pl );
1040 player_activity act( ACT_READ, time_taken, 0, pl->getID().get_value() );
1041 act.targets.emplace_back( item_location( *this, &chosen ) );
1042 act.str_values.push_back( std::to_string( penalty ) );
1043 // push an identifier of martial art book to the action handling
1044 if( chosen.type->use_methods.count( "MA_MANUAL" ) ) {
1045 act.str_values.clear();
1046 act.str_values.emplace_back( "martial_art" );
1047 }
1048 assign_activity( act );
1049 }
1050
do_npc_read()1051 void npc::do_npc_read()
1052 {
1053 // Can read items from inventory or within one tile (including in vehicles)
1054 player *pl = dynamic_cast<player *>( this );
1055 if( !pl ) {
1056 return;
1057 }
1058 item_location loc = game_menus::inv::read( *pl );
1059
1060 if( loc ) {
1061 std::vector<std::string> fail_reasons;
1062 Character *ch = dynamic_cast<Character *>( pl );
1063 if( !ch ) {
1064 return;
1065 }
1066 item &chosen = *loc.obtain( *ch );
1067 if( can_read( chosen, fail_reasons ) ) {
1068 if( get_player_view().sees( pos() ) ) {
1069 add_msg( m_info, _( "%s starts reading." ), disp_name() );
1070 }
1071 start_read( chosen, pl );
1072 } else {
1073 for( const auto &elem : fail_reasons ) {
1074 say( elem );
1075 }
1076 }
1077 } else {
1078 add_msg( _( "Never mind." ) );
1079 }
1080 }
1081
wear_if_wanted(const item & it,std::string & reason)1082 bool npc::wear_if_wanted( const item &it, std::string &reason )
1083 {
1084 // Note: this function isn't good enough to use with NPC AI alone
1085 // Restrict it to player's orders for now
1086 if( !it.is_armor() ) {
1087 reason = _( "This can't be worn." );
1088 return false;
1089 }
1090
1091 // Splints ignore limits, but only when being equipped on a broken part
1092 // TODO: Drop splints when healed
1093 if( it.has_flag( flag_SPLINT ) ) {
1094 for( const bodypart_id &bp : get_all_body_parts( get_body_part_flags::only_main ) ) {
1095 if( is_limb_broken( bp ) && !has_effect( effect_mending, bp.id() ) &&
1096 it.covers( bp ) ) {
1097 reason = _( "Thanks, I'll wear that now." );
1098 return !!wear_item( it, false );
1099 }
1100 }
1101 }
1102
1103 while( !worn.empty() ) {
1104 size_t size_before = worn.size();
1105 // Strip until we can put the new item on
1106 // This is one of the reasons this command is not used by the AI
1107 if( can_wear( it ).success() ) {
1108 // TODO: Hazmat/power armor makes this not work due to 1 boots/headgear limit
1109
1110 if( !!wear_item( it, false ) ) {
1111 reason = _( "Thanks, I'll wear that now." );
1112 return true;
1113 } else {
1114 reason = _( "I tried but couldn't wear it." );
1115 return false;
1116 }
1117 }
1118 // Otherwise, maybe we should take off one or more items and replace them
1119 bool took_off = false;
1120 for( const bodypart_id &bp : get_all_body_parts() ) {
1121 if( !it.covers( bp ) ) {
1122 continue;
1123 }
1124 // Find an item that covers the same body part as the new item
1125 auto iter = std::find_if( worn.begin(), worn.end(), [bp]( const item & armor ) {
1126 return armor.covers( bp );
1127 } );
1128 if( iter != worn.end() && !( is_limb_broken( bp ) && iter->has_flag( flag_SPLINT ) ) ) {
1129 took_off = takeoff( *iter );
1130 break;
1131 }
1132 }
1133
1134 if( !took_off || worn.size() >= size_before ) {
1135 // Shouldn't happen, but does
1136 reason = _( "I tried but couldn't wear it." );
1137 return false;
1138 }
1139 }
1140 reason = _( "Thanks, I'll wear that now." );
1141 return worn.empty() && wear_item( it, false );
1142 }
1143
stow_item(item & it)1144 void npc::stow_item( item &it )
1145 {
1146 bool avatar_sees = get_player_view().sees( pos() );
1147 if( wear_item( it, false ) ) {
1148 // Wearing the item was successful, remove weapon and post message.
1149 if( avatar_sees ) {
1150 add_msg_if_npc( m_info, _( "<npcname> wears the %s." ), it.tname() );
1151 }
1152 remove_item( it );
1153 moves -= 15;
1154 // Weapon cannot be worn or wearing was not successful. Store it in inventory if possible,
1155 // otherwise drop it.
1156 } else if( can_stash( it ) ) {
1157 item &ret = i_add( remove_item( it ), true, nullptr, true, false );
1158 if( avatar_sees ) {
1159 add_msg_if_npc( m_info, _( "<npcname> puts away the %s." ), ret.tname() );
1160 }
1161 moves -= 15;
1162 } else { // No room for weapon, so we drop it
1163 if( avatar_sees ) {
1164 add_msg_if_npc( m_info, _( "<npcname> drops the %s." ), it.tname() );
1165 }
1166 get_map().add_item_or_charges( pos(), remove_item( it ) );
1167 }
1168 }
1169
wield(item & it)1170 bool npc::wield( item &it )
1171 {
1172 // sanity check: exit early if we're trying to wield the current weapon
1173 // needed for ranged_balance_test
1174 if( is_wielding( it ) ) {
1175 return true;
1176 }
1177
1178 item to_wield;
1179 if( has_item( it ) ) {
1180 to_wield = remove_item( it );
1181 } else {
1182 to_wield = it;
1183 }
1184
1185 invalidate_inventory_validity_cache();
1186 cached_info.erase( "weapon_value" );
1187 if( has_wield_conflicts( to_wield ) ) {
1188 stow_item( weapon );
1189 }
1190
1191 if( to_wield.is_null() ) {
1192 weapon = item();
1193 get_event_bus().send<event_type::character_wields_item>( getID(), weapon.typeId() );
1194 return true;
1195 }
1196
1197 moves -= 15;
1198 if( to_wield.can_combine( weapon ) ) {
1199 weapon.combine( to_wield );
1200 } else {
1201 weapon = to_wield;
1202 }
1203
1204 get_event_bus().send<event_type::character_wields_item>( getID(), weapon.typeId() );
1205
1206 if( get_player_view().sees( pos() ) ) {
1207 add_msg_if_npc( m_info, _( "<npcname> wields a %s." ), weapon.tname() );
1208 }
1209 invalidate_range_cache();
1210 return true;
1211 }
1212
drop(const drop_locations & what,const tripoint & target,bool stash)1213 void npc::drop( const drop_locations &what, const tripoint &target,
1214 bool stash )
1215 {
1216 Character::drop( what, target, stash );
1217 // TODO: Remove the hack. Its here because npcs didn't process activities, but they do now
1218 // so is this necessary?
1219 activity.do_turn( *this );
1220 }
1221
invalidate_range_cache()1222 void npc::invalidate_range_cache()
1223 {
1224 if( weapon.is_gun() ) {
1225 confident_range_cache = confident_shoot_range( weapon, get_most_accurate_sight( weapon ) );
1226 } else {
1227 confident_range_cache = weapon.reach_range( *this );
1228 }
1229 }
1230
form_opinion(const player & u)1231 void npc::form_opinion( const player &u )
1232 {
1233 // FEAR
1234 if( u.weapon.is_gun() ) {
1235 // TODO: Make bows not guns
1236 if( weapon.is_gun() ) {
1237 op_of_u.fear += 2;
1238 } else {
1239 op_of_u.fear += 6;
1240 }
1241 } else if( u.weapon_value( u.weapon ) > 20 ) {
1242 op_of_u.fear += 2;
1243 } else if( !u.is_armed() ) {
1244 // Unarmed, but actually unarmed ("unarmed weapons" are not unarmed)
1245 op_of_u.fear -= 3;
1246 }
1247
1248 ///\EFFECT_STR increases NPC fear of the player
1249 if( u.str_max >= 16 ) {
1250 op_of_u.fear += 2;
1251 } else if( u.str_max >= 12 ) {
1252 op_of_u.fear += 1;
1253 } else if( u.str_max <= 3 ) {
1254 op_of_u.fear -= 3;
1255 } else if( u.str_max <= 5 ) {
1256 op_of_u.fear -= 1;
1257 }
1258
1259 // is your health low
1260 for( const std::pair<const bodypart_str_id, bodypart> &elem : get_player_character().get_body() ) {
1261 const int hp_max = elem.second.get_hp_max();
1262 const int hp_cur = elem.second.get_hp_cur();
1263 if( hp_cur <= hp_max / 2 ) {
1264 op_of_u.fear--;
1265 }
1266 }
1267
1268 // is my health low
1269 for( const std::pair<const bodypart_str_id, bodypart> &elem : get_body() ) {
1270 const int hp_max = elem.second.get_hp_max();
1271 const int hp_cur = elem.second.get_hp_cur();
1272 if( hp_cur <= hp_max / 2 ) {
1273 op_of_u.fear++;
1274 }
1275 }
1276
1277 if( u.has_trait( trait_SAPIOVORE ) ) {
1278 op_of_u.fear += 10; // Sapiovores = Scary
1279 }
1280 if( u.has_trait( trait_TERRIFYING ) ) {
1281 op_of_u.fear += 6;
1282 }
1283
1284 int u_ugly = 0;
1285 for( trait_id &mut : u.get_mutations() ) {
1286 u_ugly += mut.obj().ugliness;
1287 }
1288 op_of_u.fear += u_ugly / 2;
1289 op_of_u.trust -= u_ugly / 3;
1290
1291 if( u.get_stim() > 20 ) {
1292 op_of_u.fear++;
1293 }
1294
1295 if( u.has_effect( effect_drunk ) ) {
1296 op_of_u.fear -= 2;
1297 }
1298
1299 // TRUST
1300 if( op_of_u.fear > 0 ) {
1301 op_of_u.trust -= 3;
1302 } else {
1303 op_of_u.trust += 1;
1304 }
1305
1306 if( u.weapon.is_gun() ) {
1307 op_of_u.trust -= 2;
1308 } else if( !u.is_armed() ) {
1309 op_of_u.trust += 2;
1310 }
1311
1312 // TODO: More effects
1313 if( u.has_effect( effect_high ) ) {
1314 op_of_u.trust -= 1;
1315 }
1316 if( u.has_effect( effect_drunk ) ) {
1317 op_of_u.trust -= 2;
1318 }
1319 if( u.get_stim() > 20 || u.get_stim() < -20 ) {
1320 op_of_u.trust -= 1;
1321 }
1322 if( u.get_painkiller() > 30 ) {
1323 op_of_u.trust -= 1;
1324 }
1325
1326 if( op_of_u.trust > 0 ) {
1327 // Trust is worth a lot right now
1328 op_of_u.trust /= 2;
1329 }
1330
1331 // VALUE
1332 op_of_u.value = 0;
1333 for( const std::pair<const bodypart_str_id, bodypart> &elem : get_body() ) {
1334 if( elem.second.get_hp_cur() < elem.second.get_hp_max() * 0.8f ) {
1335 op_of_u.value++;
1336 }
1337 }
1338 decide_needs();
1339 for( const npc_need &i : needs ) {
1340 if( i == need_food || i == need_drink ) {
1341 op_of_u.value += 2;
1342 }
1343 }
1344
1345 if( op_of_u.fear < personality.bravery + 10 &&
1346 op_of_u.fear - personality.aggression > -10 && op_of_u.trust > -8 ) {
1347 set_attitude( NPCATT_TALK );
1348 } else if( op_of_u.fear - 2 * personality.aggression - personality.bravery < -30 ) {
1349 set_attitude( NPCATT_KILL );
1350 } else if( my_fac && my_fac->likes_u < -10 ) {
1351 if( is_player_ally() ) {
1352 mutiny();
1353 }
1354 set_attitude( NPCATT_KILL );
1355 } else {
1356 set_attitude( NPCATT_FLEE_TEMP );
1357 }
1358
1359 add_msg_debug( "%s formed an opinion of u: %s", name, npc_attitude_id( attitude ) );
1360 }
1361
mutiny()1362 void npc::mutiny()
1363 {
1364 if( !my_fac || !is_player_ally() ) {
1365 return;
1366 }
1367 const bool seen = get_player_view().sees( pos() );
1368 if( seen ) {
1369 add_msg( m_bad, _( "%s is tired of your incompetent leadership and abuse!" ), disp_name() );
1370 }
1371 // NPCs leaving your faction due to mistreatment further reduce their opinion of you
1372 if( my_fac->likes_u < -10 ) {
1373 op_of_u.trust += my_fac->respects_u / 10;
1374 op_of_u.anger += my_fac->likes_u / 10;
1375 }
1376 // NPCs leaving your faction for abuse reduce the hatred your (remaining) followers
1377 // feel for you, but also reduces their respect for you.
1378 my_fac->likes_u = std::max( 0, my_fac->likes_u / 2 + 10 );
1379 my_fac->respects_u -= 5;
1380 g->remove_npc_follower( getID() );
1381 set_fac( faction_id( "amf" ) );
1382 job.clear_all_priorities();
1383 if( assigned_camp ) {
1384 assigned_camp = cata::nullopt;
1385 }
1386 chatbin.first_topic = "TALK_STRANGER_NEUTRAL";
1387 set_attitude( NPCATT_NULL );
1388 say( _( "<follower_mutiny> Adios, motherfucker!" ), sounds::sound_t::order );
1389 if( seen ) {
1390 my_fac->known_by_u = true;
1391 }
1392 }
1393
vehicle_danger(int radius) const1394 float npc::vehicle_danger( int radius ) const
1395 {
1396 const tripoint from( posx() - radius, posy() - radius, posz() );
1397 const tripoint to( posx() + radius, posy() + radius, posz() );
1398 VehicleList vehicles = get_map().get_vehicles( from, to );
1399
1400 int danger = 0;
1401
1402 // TODO: check for most dangerous vehicle?
1403 for( size_t i = 0; i < vehicles.size(); ++i ) {
1404 const wrapped_vehicle &wrapped_veh = vehicles[i];
1405 if( wrapped_veh.v->is_moving() ) {
1406 // FIXME: this can't be the right way to do this
1407 units::angle facing = wrapped_veh.v->face.dir();
1408
1409 point a( wrapped_veh.v->global_pos3().xy() );
1410 point b( static_cast<int>( a.x + units::cos( facing ) * radius ),
1411 static_cast<int>( a.y + units::sin( facing ) * radius ) );
1412
1413 // fake size
1414 /* This will almost certainly give the wrong size/location on customized
1415 * vehicles. This should just count frames instead. Or actually find the
1416 * size. */
1417 vehicle_part last_part;
1418 // vehicle_part_range is a forward only iterator, see comment in vpart_range.h
1419 for( const vpart_reference &vpr : wrapped_veh.v->get_all_parts() ) {
1420 last_part = vpr.part();
1421 }
1422 int size = std::max( last_part.mount.x, last_part.mount.y );
1423
1424 double normal = std::sqrt( static_cast<float>( ( b.x - a.x ) * ( b.x - a.x ) + ( b.y - a.y ) *
1425 ( b.y - a.y ) ) );
1426 int closest = static_cast<int>( std::abs( ( posx() - a.x ) * ( b.y - a.y ) - ( posy() - a.y ) *
1427 ( b.x - a.x ) ) / normal );
1428
1429 if( size > closest ) {
1430 danger = i;
1431 }
1432 }
1433 }
1434 return danger;
1435 }
1436
turned_hostile() const1437 bool npc::turned_hostile() const
1438 {
1439 return ( op_of_u.anger >= hostile_anger_level() );
1440 }
1441
hostile_anger_level() const1442 int npc::hostile_anger_level() const
1443 {
1444 return ( 20 + op_of_u.fear - personality.aggression );
1445 }
1446
make_angry()1447 void npc::make_angry()
1448 {
1449 if( is_enemy() ) {
1450 return; // We're already angry!
1451 }
1452
1453 // player allies that become angry should stop being player allies
1454 if( is_player_ally() ) {
1455 mutiny();
1456 }
1457
1458 // Make associated faction, if any, angry at the player too.
1459 if( my_fac && my_fac->id != faction_id( "no_faction" ) && my_fac->id != faction_id( "amf" ) ) {
1460 my_fac->likes_u = std::min( -15, my_fac->likes_u - 5 );
1461 my_fac->respects_u = std::min( -15, my_fac->respects_u - 5 );
1462 }
1463 if( op_of_u.fear > 10 + personality.aggression + personality.bravery ) {
1464 set_attitude( NPCATT_FLEE_TEMP ); // We don't want to take u on!
1465 } else {
1466 set_attitude( NPCATT_KILL ); // Yeah, we think we could take you!
1467 }
1468 }
1469
on_attacked(const Creature & attacker)1470 void npc::on_attacked( const Creature &attacker )
1471 {
1472 if( is_hallucination() ) {
1473 die( nullptr );
1474 }
1475 if( attacker.is_player() && !is_enemy() ) {
1476 make_angry();
1477 hit_by_player = true;
1478 }
1479 }
1480
assigned_missions_value()1481 int npc::assigned_missions_value()
1482 {
1483 int ret = 0;
1484 for( auto &m : chatbin.missions_assigned ) {
1485 ret += m->get_value();
1486 }
1487 return ret;
1488 }
1489
skills_offered_to(const player & p) const1490 std::vector<skill_id> npc::skills_offered_to( const player &p ) const
1491 {
1492 std::vector<skill_id> ret;
1493 for( const auto &pair : *_skills ) {
1494 const skill_id &id = pair.first;
1495 if( p.get_skill_level( id ) < pair.second.level() ) {
1496 ret.push_back( id );
1497 }
1498 }
1499 return ret;
1500 }
1501
proficiencies_offered_to(const Character & guy) const1502 std::vector<proficiency_id> npc::proficiencies_offered_to( const Character &guy ) const
1503 {
1504 std::vector<proficiency_id> ret;
1505 for( const proficiency_id &known : known_proficiencies() ) {
1506 if( !guy.has_proficiency( known ) ) {
1507 ret.push_back( known );
1508 }
1509 }
1510 return ret;
1511 }
1512
styles_offered_to(const player & p) const1513 std::vector<matype_id> npc::styles_offered_to( const player &p ) const
1514 {
1515 return p.martial_arts_data->get_unknown_styles( *martial_arts_data );
1516 }
1517
spells_offered_to(player & p)1518 std::vector<spell_id> npc::spells_offered_to( player &p )
1519 {
1520 std::vector<spell_id> teachable;
1521 for( const spell_id &sp : magic->spells() ) {
1522 const spell &teacher_spell = magic->get_spell( sp );
1523 if( p.magic->can_learn_spell( p, sp ) ) {
1524 if( p.magic->knows_spell( sp ) ) {
1525 const spell &student_spell = p.magic->get_spell( sp );
1526 if( student_spell.is_max_level() ||
1527 student_spell.get_level() >= teacher_spell.get_level() ) {
1528 continue;
1529 }
1530 }
1531 teachable.emplace_back( sp );
1532 }
1533 }
1534 return teachable;
1535 }
1536
decide_needs()1537 void npc::decide_needs()
1538 {
1539 double needrank[num_needs];
1540 for( auto &elem : needrank ) {
1541 elem = 20;
1542 }
1543 if( weapon.is_gun() ) {
1544 int ups_drain = weapon.get_gun_ups_drain();
1545 if( ups_drain > 0 ) {
1546 int ups_charges = charges_of( itype_UPS_off, ups_drain ) +
1547 charges_of( itype_UPS_off, ups_drain );
1548 needrank[need_ammo] = static_cast<double>( ups_charges ) / ups_drain;
1549 } else {
1550 const ammotype ammo_type = weapon.ammo_type();
1551 if( ammo_type != ammotype::NULL_ID() ) {
1552 needrank[need_ammo] = get_ammo( ammo_type ).size();
1553 }
1554 }
1555 needrank[need_ammo] *= 5;
1556 }
1557 if( !base_location ) {
1558 needrank[need_safety] = 1;
1559 }
1560
1561 needrank[need_weapon] = weapon_value( weapon );
1562 needrank[need_food] = 15 - get_hunger();
1563 needrank[need_drink] = 15 - get_thirst();
1564 const auto inv_food = items_with( []( const item & itm ) {
1565 return itm.is_food();
1566 } );
1567 for( const item *food : inv_food ) {
1568 needrank[ need_food ] += nutrition_for( *food ) / 4.0;
1569 needrank[ need_drink ] += food->get_comestible()->quench / 4.0;
1570 }
1571 needs.clear();
1572 size_t j;
1573 bool serious = false;
1574 for( int i = 1; i < num_needs; i++ ) {
1575 if( needrank[i] < 10 ) {
1576 serious = true;
1577 }
1578 }
1579 if( !serious ) {
1580 needs.push_back( need_none );
1581 needrank[0] = 10;
1582 }
1583 for( int i = 1; i < num_needs; i++ ) {
1584 if( needrank[i] < 20 ) {
1585 for( j = 0; j < needs.size(); j++ ) {
1586 if( needrank[i] < needrank[needs[j]] ) {
1587 needs.insert( needs.begin() + j, static_cast<npc_need>( i ) );
1588 j = needs.size() + 1;
1589 }
1590 }
1591 if( j == needs.size() ) {
1592 needs.push_back( static_cast<npc_need>( i ) );
1593 }
1594 }
1595 }
1596 }
1597
say(const std::string & line,const sounds::sound_t spriority) const1598 void npc::say( const std::string &line, const sounds::sound_t spriority ) const
1599 {
1600 std::string formatted_line = line;
1601 Character &player_character = get_player_character();
1602 parse_tags( formatted_line, player_character, *this );
1603 if( has_trait( trait_MUTE ) ) {
1604 return;
1605 }
1606
1607 std::string sound = string_format( _( "%1$s saying \"%2$s\"" ), name, formatted_line );
1608 if( player_character.is_deaf() ) {
1609 add_msg_if_player_sees( *this, m_warning, _( "%1$s says something but you can't hear it!" ), name );
1610 }
1611 if( player_character.is_mute() ) {
1612 add_msg_if_player_sees( *this, m_warning, _( "%1$s says something but you can't reply to it!" ),
1613 name );
1614 }
1615 // Hallucinations don't make noise when they speak
1616 if( is_hallucination() ) {
1617 add_msg( _( "%1$s saying \"%2$s\"" ), name, formatted_line );
1618 return;
1619 }
1620 // Sound happens even if we can't hear it
1621 if( spriority == sounds::sound_t::order || spriority == sounds::sound_t::alert ) {
1622 sounds::sound( pos(), get_shout_volume(), spriority, sound, false, "speech",
1623 male ? "NPC_m" : "NPC_f" );
1624 } else {
1625 sounds::sound( pos(), 16, sounds::sound_t::speech, sound, false, "speech",
1626 male ? "NPC_m_loud" : "NPC_f_loud" );
1627 }
1628 }
1629
wants_to_sell(const item & it) const1630 bool npc::wants_to_sell( const item &it ) const
1631 {
1632 if( !it.is_owned_by( *this ) ) {
1633 return false;
1634 }
1635 const int market_price = it.price( true );
1636 return wants_to_sell( it, value( it, market_price ), market_price );
1637 }
1638
wants_to_sell(const item & it,int at_price,int) const1639 bool npc::wants_to_sell( const item &it, int at_price, int /*market_price*/ ) const
1640 {
1641 if( will_exchange_items_freely() ) {
1642 return true;
1643 }
1644
1645 // Keep items that we never want to trade and the ones we don't want to trade while in use.
1646 if( it.has_flag( flag_TRADER_KEEP ) ||
1647 ( it.has_flag( flag_TRADER_KEEP_EQUIPPED ) && ( is_worn( it ) || is_wielding( it ) ) ) ) {
1648 return false;
1649 }
1650
1651 // TODO: Base on inventory
1652 return at_price >= 0;
1653 }
1654
wants_to_buy(const item & it) const1655 bool npc::wants_to_buy( const item &it ) const
1656 {
1657 const int market_price = it.price( true );
1658 return wants_to_buy( it, value( it, market_price ), market_price );
1659 }
1660
wants_to_buy(const item & it,int at_price,int) const1661 bool npc::wants_to_buy( const item &it, int at_price, int /*market_price*/ ) const
1662 {
1663 if( will_exchange_items_freely() ) {
1664 return true;
1665 }
1666
1667 if( it.has_flag( flag_TRADER_AVOID ) ) {
1668 return false;
1669 }
1670
1671 // TODO: Base on inventory
1672 return at_price > 0;
1673 }
1674
1675 // Will the NPC freely exchange items with the player?
will_exchange_items_freely() const1676 bool npc::will_exchange_items_freely() const
1677 {
1678 return is_player_ally();
1679 }
1680
1681 // What's the maximum credit the NPC is willing to extend to the player?
1682 // This is currently very scrooge-like; NPCs are only likely to extend a few dollars
1683 // of credit at most.
max_credit_extended() const1684 int npc::max_credit_extended() const
1685 {
1686 if( is_player_ally() ) {
1687 return INT_MAX;
1688 }
1689
1690 const int credit_trust = 50;
1691 const int credit_value = 50;
1692 const int credit_fear = 50;
1693 const int credit_altruism = 100;
1694 const int credit_anger = -200;
1695
1696 return std::max( 0,
1697 op_of_u.trust * credit_trust +
1698 op_of_u.value * credit_value +
1699 op_of_u.fear * credit_fear +
1700 personality.altruism * credit_altruism +
1701 op_of_u.anger * credit_anger
1702 );
1703 }
1704
1705 // How much is the NPC willing to owe the player?
1706 // This is much more generous, as it's the essentially the player holding the risk here.
max_willing_to_owe() const1707 int npc::max_willing_to_owe() const
1708 {
1709 if( is_player_ally() ) {
1710 return INT_MAX;
1711 }
1712
1713 const int credit_trust = 10000;
1714 const int credit_value = 10000;
1715 const int credit_fear = 10000;
1716 const int credit_altruism = 0;
1717 const int credit_anger = -10000;
1718
1719 return std::max( 0,
1720 op_of_u.trust * credit_trust +
1721 op_of_u.value * credit_value +
1722 op_of_u.fear * credit_fear +
1723 personality.altruism * credit_altruism +
1724 op_of_u.anger * credit_anger
1725 );
1726
1727 }
1728
shop_restock()1729 void npc::shop_restock()
1730 {
1731 if( ( restock != calendar::turn_zero ) && ( ( calendar::turn - restock ) < 3_days ) ) {
1732 return;
1733 }
1734
1735 restock = calendar::turn + 3_days;
1736 if( is_player_ally() ) {
1737 return;
1738 }
1739 const item_group_id &from = myclass->get_shopkeeper_items();
1740 if( from == item_group_id( "EMPTY_GROUP" ) ) {
1741 return;
1742 }
1743
1744 units::volume total_space = volume_capacity();
1745 if( mission == NPC_MISSION_SHOPKEEP ) {
1746 total_space = units::from_liter( 5000 );
1747 }
1748
1749 std::list<item> ret;
1750 int shop_value = 75000;
1751 if( my_fac ) {
1752 shop_value = my_fac->wealth * 0.0075;
1753 if( mission == NPC_MISSION_SHOPKEEP && !my_fac->currency.is_empty() ) {
1754 item my_currency( my_fac->currency );
1755 if( !my_currency.is_null() ) {
1756 my_currency.set_owner( *this );
1757 int my_amount = rng( 5, 15 ) * shop_value / 100 / my_currency.price( true );
1758 for( int lcv = 0; lcv < my_amount; lcv++ ) {
1759 ret.push_back( my_currency );
1760 }
1761 }
1762 }
1763 }
1764
1765 int count = 0;
1766 bool last_item = false;
1767 while( shop_value > 0 && total_space > 0_ml && !last_item ) {
1768 item tmpit = item_group::item_from( from, calendar::turn );
1769 if( !tmpit.is_null() && total_space >= tmpit.volume() ) {
1770 tmpit.set_owner( *this );
1771 ret.push_back( tmpit );
1772 shop_value -= tmpit.price( true );
1773 total_space -= tmpit.volume();
1774 count += 1;
1775 last_item = count > 10 && one_in( 100 );
1776 }
1777 }
1778
1779 // This removes some items according to item spawn scaling factor,
1780 const float spawn_rate = get_option<float>( "ITEM_SPAWNRATE" );
1781 if( spawn_rate < 1 ) {
1782 ret.remove_if( [spawn_rate]( auto & ) {
1783 return !( rng_float( 0, 1 ) < spawn_rate );
1784 } );
1785 }
1786
1787 has_new_items = true;
1788 inv->clear();
1789 inv->push_back( ret );
1790 }
1791
minimum_item_value() const1792 int npc::minimum_item_value() const
1793 {
1794 // TODO: Base on inventory
1795 int ret = 20;
1796 ret -= personality.collector;
1797 return ret;
1798 }
1799
update_worst_item_value()1800 void npc::update_worst_item_value()
1801 {
1802 worst_item_value = 99999;
1803 // TODO: Cache this
1804 int inv_val = inv->worst_item_value( this );
1805 if( inv_val < worst_item_value ) {
1806 worst_item_value = inv_val;
1807 }
1808 }
1809
value(const item & it) const1810 int npc::value( const item &it ) const
1811 {
1812 int market_price = it.price( true );
1813 return value( it, market_price );
1814 }
1815
value(const item & it,int market_price) const1816 int npc::value( const item &it, int market_price ) const
1817 {
1818 if( it.is_dangerous() || ( it.has_flag( flag_BOMB ) && it.active ) ||
1819 it.made_of( phase_id::LIQUID ) ) {
1820 // NPCs won't be interested in buying active explosives or spilled liquids
1821 return -1000;
1822 }
1823
1824 // faction currency trades at market price
1825 if( my_fac && my_fac->currency == it.typeId() ) {
1826 return market_price;
1827 }
1828
1829 int ret = 0;
1830 // TODO: Cache own weapon value (it can be a bit expensive to compute 50 times/turn)
1831 double weapon_val = weapon_value( it ) - weapon_value( weapon );
1832 if( weapon_val > 0 ) {
1833 ret += weapon_val;
1834 }
1835
1836 if( it.is_food() ) {
1837 int comestval = 0;
1838 if( nutrition_for( it ) > 0 || it.get_comestible()->quench > 0 ) {
1839 comestval++;
1840 }
1841 if( get_hunger() > 40 ) {
1842 comestval += ( nutrition_for( it ) + get_hunger() - 40 ) / 6;
1843 }
1844 if( get_thirst() > 40 ) {
1845 comestval += ( it.get_comestible()->quench + get_thirst() - 40 ) / 4;
1846 }
1847 if( comestval > 0 && will_eat( it ).success() ) {
1848 ret += comestval;
1849 }
1850 }
1851
1852 if( it.is_ammo() ) {
1853 if( weapon.is_gun() && weapon.ammo_types().count( it.ammo_type() ) ) {
1854 // TODO: magazines - don't count ammo as usable if the weapon isn't.
1855 ret += 14;
1856 }
1857
1858 if( has_gun_for_ammo( it.ammo_type() ) ) {
1859 // TODO: consider making this cumulative (once was)
1860 ret += 14;
1861 }
1862 }
1863
1864 if( it.is_book() ) {
1865 auto &book = *it.type->book;
1866 ret += book.fun;
1867 if( book.skill && get_skill_level( book.skill ) < book.level &&
1868 get_skill_level( book.skill ) >= book.req ) {
1869 ret += book.level * 3;
1870 }
1871 }
1872
1873 // Practical item value is more important than price
1874 ret *= 50;
1875
1876 // TODO: Sometimes we want more than one tool? Also we don't want EVERY tool.
1877 if( it.is_tool() && !has_amount( it.typeId(), 1 ) ) {
1878 ret += market_price * 0.2; // 20% premium for fresh tools
1879 }
1880 ret += market_price;
1881 return ret;
1882 }
1883
clear_all()1884 void healing_options::clear_all()
1885 {
1886 bandage = false;
1887 disinfect = false;
1888 bleed = false;
1889 bite = false;
1890 infect = false;
1891 }
1892
all_false()1893 bool healing_options::all_false()
1894 {
1895 return !any_true();
1896 }
1897
any_true()1898 bool healing_options::any_true()
1899 {
1900 return bandage || bleed || bite || infect || disinfect;
1901 }
1902
set_all()1903 void healing_options::set_all()
1904 {
1905 bandage = true;
1906 bleed = true;
1907 bite = true;
1908 infect = true;
1909 disinfect = true;
1910 }
1911
has_healing_item(healing_options try_to_fix)1912 bool npc::has_healing_item( healing_options try_to_fix )
1913 {
1914 return !get_healing_item( try_to_fix, true ).is_null();
1915 }
1916
has_healing_options()1917 healing_options npc::has_healing_options()
1918 {
1919 healing_options try_to_fix;
1920 try_to_fix.set_all();
1921 return has_healing_options( try_to_fix );
1922 }
1923
has_healing_options(healing_options try_to_fix)1924 healing_options npc::has_healing_options( healing_options try_to_fix )
1925 {
1926 healing_options can_fix;
1927 can_fix.clear_all();
1928 healing_options *fix_p = &can_fix;
1929
1930 visit_items( [&fix_p, try_to_fix]( item * node, item * ) {
1931 const use_function *use = node->type->get_use( "heal" );
1932 if( use == nullptr ) {
1933 return VisitResponse::NEXT;
1934 }
1935
1936 const heal_actor &actor = dynamic_cast<const heal_actor &>( *( use->get_actor_ptr() ) );
1937 if( try_to_fix.bandage && !fix_p->bandage && actor.bandages_power > 0.0f ) {
1938 fix_p->bandage = true;
1939 }
1940 if( try_to_fix.disinfect && !fix_p->disinfect && actor.disinfectant_power > 0.0f ) {
1941 fix_p->disinfect = true;
1942 }
1943 if( try_to_fix.bleed && !fix_p->bleed && actor.bleed > 0 ) {
1944 fix_p->bleed = true;
1945 }
1946 if( try_to_fix.bite && !fix_p->bite && actor.bite > 0 ) {
1947 fix_p->bite = true;
1948 }
1949 if( try_to_fix.infect && !fix_p->infect && actor.infect > 0 ) {
1950 fix_p->infect = true;
1951 }
1952 // if we've found items for everything we're looking for, we're done
1953 if( ( !try_to_fix.bandage || fix_p->bandage ) &&
1954 ( !try_to_fix.disinfect || fix_p->disinfect ) &&
1955 ( !try_to_fix.bleed || fix_p->bleed ) &&
1956 ( !try_to_fix.bite || fix_p->bite ) &&
1957 ( !try_to_fix.infect || fix_p->infect ) ) {
1958 return VisitResponse::ABORT;
1959 }
1960
1961 return VisitResponse::NEXT;
1962 } );
1963 return can_fix;
1964 }
1965
get_healing_item(healing_options try_to_fix,bool first_best)1966 item &npc::get_healing_item( healing_options try_to_fix, bool first_best )
1967 {
1968 item *best = &null_item_reference();
1969 visit_items( [&best, try_to_fix, first_best]( item * node, item * ) {
1970 const use_function *use = node->type->get_use( "heal" );
1971 if( use == nullptr ) {
1972 return VisitResponse::NEXT;
1973 }
1974
1975 const heal_actor &actor = dynamic_cast<const heal_actor &>( *( use->get_actor_ptr() ) );
1976 if( ( try_to_fix.bandage && actor.bandages_power > 0.0f ) ||
1977 ( try_to_fix.disinfect && actor.disinfectant_power > 0.0f ) ||
1978 ( try_to_fix.bleed && actor.bleed > 0 ) ||
1979 ( try_to_fix.bite && actor.bite > 0 ) ||
1980 ( try_to_fix.infect && actor.infect > 0 ) ) {
1981 best = node;
1982 if( first_best ) {
1983 return VisitResponse::ABORT;
1984 }
1985 }
1986
1987 return VisitResponse::NEXT;
1988 } );
1989
1990 return *best;
1991 }
1992
has_painkiller()1993 bool npc::has_painkiller()
1994 {
1995 return inv->has_enough_painkiller( get_pain() );
1996 }
1997
took_painkiller() const1998 bool npc::took_painkiller() const
1999 {
2000 return ( has_effect( effect_pkill1 ) || has_effect( effect_pkill2 ) ||
2001 has_effect( effect_pkill3 ) || has_effect( effect_pkill_l ) );
2002 }
2003
get_faction_ver() const2004 int npc::get_faction_ver() const
2005 {
2006 return faction_api_version;
2007 }
2008
set_faction_ver(int new_version)2009 void npc::set_faction_ver( int new_version )
2010 {
2011 faction_api_version = new_version;
2012 }
2013
has_faction_relationship(const player & p,const npc_factions::relationship flag) const2014 bool npc::has_faction_relationship( const player &p, const npc_factions::relationship flag ) const
2015 {
2016 faction *p_fac = p.get_faction();
2017 if( !my_fac || !p_fac ) {
2018 return false;
2019 }
2020
2021 return my_fac->has_relationship( p_fac->id, flag );
2022 }
2023
is_ally(const Character & p) const2024 bool npc::is_ally( const Character &p ) const
2025 {
2026 if( p.getID() == getID() ) {
2027 return true;
2028 }
2029 if( p.is_player() ) {
2030 if( my_fac && my_fac->id == faction_id( "your_followers" ) ) {
2031 return true;
2032 }
2033 if( faction_api_version < 2 ) {
2034 // legacy attitude support so let's be specific here
2035 if( attitude == NPCATT_FOLLOW || attitude == NPCATT_LEAD ||
2036 attitude == NPCATT_WAIT || mission == NPC_MISSION_ACTIVITY ||
2037 mission == NPC_MISSION_TRAVELLING || mission == NPC_MISSION_GUARD_ALLY ||
2038 has_companion_mission() ) {
2039 return true;
2040 }
2041 }
2042 } else {
2043 const npc &guy = dynamic_cast<const npc &>( p );
2044 if( my_fac && guy.get_faction() && my_fac->id == guy.get_faction()->id ) {
2045 return true;
2046 }
2047 if( faction_api_version < 2 ) {
2048 Character &player_character = get_player_character();
2049 if( is_ally( player_character ) && guy.is_ally( player_character ) ) {
2050 return true;
2051 } else if( get_attitude_group( get_attitude() ) ==
2052 guy.get_attitude_group( guy.get_attitude() ) ) {
2053 return true;
2054 }
2055 }
2056 }
2057 return false;
2058 }
2059
is_player_ally() const2060 bool npc::is_player_ally() const
2061 {
2062 return is_ally( get_player_character() );
2063 }
2064
is_friendly(const Character & p) const2065 bool npc::is_friendly( const Character &p ) const
2066 {
2067 return is_ally( p ) || ( p.is_player() && ( is_walking_with() || is_player_ally() ) );
2068 }
2069
is_minion() const2070 bool npc::is_minion() const
2071 {
2072 return is_player_ally() && op_of_u.trust >= 5;
2073 }
2074
guaranteed_hostile() const2075 bool npc::guaranteed_hostile() const
2076 {
2077 return is_enemy() || ( my_fac && my_fac->likes_u < -10 );
2078 }
2079
is_walking_with() const2080 bool npc::is_walking_with() const
2081 {
2082 return attitude == NPCATT_FOLLOW || attitude == NPCATT_LEAD || attitude == NPCATT_WAIT;
2083 }
2084
is_obeying(const Character & p) const2085 bool npc::is_obeying( const Character &p ) const
2086 {
2087 return ( p.is_player() && is_walking_with() && is_player_ally() ) ||
2088 ( is_ally( p ) && is_stationary( true ) );
2089 }
2090
is_following() const2091 bool npc::is_following() const
2092 {
2093 return attitude == NPCATT_FOLLOW || attitude == NPCATT_WAIT;
2094 }
2095
is_leader() const2096 bool npc::is_leader() const
2097 {
2098 return attitude == NPCATT_LEAD;
2099 }
2100
within_boundaries_of_camp() const2101 bool npc::within_boundaries_of_camp() const
2102 {
2103 const point_abs_omt p( global_omt_location().xy() );
2104 for( int x2 = -3; x2 < 3; x2++ ) {
2105 for( int y2 = -3; y2 < 3; y2++ ) {
2106 const point_abs_omt nearby = p + point( x2, y2 );
2107 cata::optional<basecamp *> bcp = overmap_buffer.find_camp( nearby );
2108 if( bcp ) {
2109 return true;
2110 }
2111 }
2112 }
2113 return false;
2114 }
2115
is_enemy() const2116 bool npc::is_enemy() const
2117 {
2118 return attitude == NPCATT_KILL || attitude == NPCATT_FLEE || attitude == NPCATT_FLEE_TEMP;
2119 }
2120
is_stationary(bool include_guards) const2121 bool npc::is_stationary( bool include_guards ) const
2122 {
2123 if( include_guards && is_guarding() ) {
2124 return true;
2125 }
2126 return mission == NPC_MISSION_SHELTER || mission == NPC_MISSION_SHOPKEEP ||
2127 has_effect( effect_infection );
2128 }
2129
is_guarding() const2130 bool npc::is_guarding( ) const
2131 {
2132 return mission == NPC_MISSION_GUARD || mission == NPC_MISSION_GUARD_ALLY || is_patrolling();
2133 }
2134
is_patrolling() const2135 bool npc::is_patrolling() const
2136 {
2137 return mission == NPC_MISSION_GUARD_PATROL;
2138 }
2139
has_player_activity() const2140 bool npc::has_player_activity() const
2141 {
2142 return activity && mission == NPC_MISSION_ACTIVITY && attitude == NPCATT_ACTIVITY;
2143 }
2144
is_travelling() const2145 bool npc::is_travelling() const
2146 {
2147 return mission == NPC_MISSION_TRAVELLING;
2148 }
2149
attitude_to(const Creature & other) const2150 Creature::Attitude npc::attitude_to( const Creature &other ) const
2151 {
2152 if( other.is_npc() || other.is_player() ) {
2153 const player &guy = dynamic_cast<const player &>( other );
2154 // check faction relationships first
2155 if( has_faction_relationship( guy, npc_factions::kill_on_sight ) ) {
2156 return Attitude::HOSTILE;
2157 } else if( has_faction_relationship( guy, npc_factions::watch_your_back ) ) {
2158 return Attitude::FRIENDLY;
2159 }
2160 }
2161
2162 Character &player_character = get_player_character();
2163 if( is_player_ally() ) {
2164 // Friendly NPCs share player's alliances
2165 return player_character.attitude_to( other );
2166 }
2167
2168 if( other.is_npc() ) {
2169 // Hostile NPCs are also hostile towards player's allies
2170 if( is_enemy() && other.attitude_to( player_character ) == Attitude::FRIENDLY ) {
2171 return Attitude::HOSTILE;
2172 }
2173
2174 return Attitude::NEUTRAL;
2175 } else if( other.is_player() ) {
2176 // For now, make it symmetric.
2177 return other.attitude_to( *this );
2178 }
2179
2180 // TODO: Get rid of the ugly cast without duplicating checks
2181 const monster &m = dynamic_cast<const monster &>( other );
2182 switch( m.attitude( this ) ) {
2183 case MATT_FOLLOW:
2184 case MATT_FPASSIVE:
2185 case MATT_IGNORE:
2186 case MATT_FLEE:
2187 return Attitude::NEUTRAL;
2188 case MATT_FRIEND:
2189 return Attitude::FRIENDLY;
2190 case MATT_ATTACK:
2191 return Attitude::HOSTILE;
2192 case MATT_NULL:
2193 case NUM_MONSTER_ATTITUDES:
2194 break;
2195 }
2196
2197 return Attitude::NEUTRAL;
2198 }
2199
npc_dismount()2200 void npc::npc_dismount()
2201 {
2202 if( !mounted_creature || !has_effect( effect_riding ) ) {
2203 add_msg_debug( "NPC %s tried to dismount, but they have no mount, or they are not riding",
2204 disp_name() );
2205 return;
2206 }
2207 cata::optional<tripoint> pnt;
2208 for( const auto &elem : get_map().points_in_radius( pos(), 1 ) ) {
2209 if( g->is_empty( elem ) ) {
2210 pnt = elem;
2211 break;
2212 }
2213 }
2214 if( !pnt ) {
2215 add_msg_debug( "NPC %s could not find a place to dismount.", disp_name() );
2216 return;
2217 }
2218 remove_effect( effect_riding );
2219 if( mounted_creature->has_flag( MF_RIDEABLE_MECH ) &&
2220 !mounted_creature->type->mech_weapon.is_empty() ) {
2221 remove_item( weapon );
2222 }
2223 mounted_creature->remove_effect( effect_ridden );
2224 mounted_creature->add_effect( effect_controlled, 5_turns );
2225 mounted_creature = nullptr;
2226 setpos( *pnt );
2227 mod_moves( -100 );
2228 }
2229
smash_ability() const2230 int npc::smash_ability() const
2231 {
2232 if( !is_hallucination() && ( !is_player_ally() || rules.has_flag( ally_rule::allow_bash ) ) ) {
2233 ///\EFFECT_STR_NPC increases smash ability
2234 return str_cur + weapon.damage_melee( damage_type::BASH );
2235 }
2236
2237 // Not allowed to bash
2238 return 0;
2239 }
2240
danger_assessment()2241 float npc::danger_assessment()
2242 {
2243 return ai_cache.danger_assessment;
2244 }
2245
average_damage_dealt()2246 float npc::average_damage_dealt()
2247 {
2248 return static_cast<float>( melee_value( weapon ) );
2249 }
2250
bravery_check(int diff)2251 bool npc::bravery_check( int diff )
2252 {
2253 return ( dice( 10 + personality.bravery, 6 ) >= dice( diff, 4 ) );
2254 }
2255
emergency() const2256 bool npc::emergency() const
2257 {
2258 return emergency( ai_cache.danger_assessment );
2259 }
2260
emergency(float danger) const2261 bool npc::emergency( float danger ) const
2262 {
2263 return ( danger > ( personality.bravery * 3 * hp_percentage() ) / 100.0 );
2264 }
2265
2266 //Check if this npc is currently in the list of active npcs.
2267 //Active npcs are the npcs near the player that are actively simulated.
is_active() const2268 bool npc::is_active() const
2269 {
2270 return g->critter_at<npc>( pos() ) == this;
2271 }
2272
follow_distance() const2273 int npc::follow_distance() const
2274 {
2275 Character &player_character = get_player_character();
2276 map &here = get_map();
2277 // HACK: If the player is standing on stairs, follow closely
2278 // This makes the stair hack less painful to use
2279 if( is_walking_with() &&
2280 ( here.has_flag( TFLAG_GOES_DOWN, player_character.pos() ) ||
2281 here.has_flag( TFLAG_GOES_UP, player_character.pos() ) ) ) {
2282 return 1;
2283 }
2284 // Uses ally_rule follow_distance_2 to determine if should follow by 2 or 4 tiles
2285 if( rules.has_flag( ally_rule::follow_distance_2 ) ) {
2286 return 2;
2287 }
2288 // If NPC doesn't see player, change follow distance to 2
2289 if( !sees( player_character ) ) {
2290 return 2;
2291 }
2292 return 4;
2293 }
2294
basic_symbol_color() const2295 nc_color npc::basic_symbol_color() const
2296 {
2297 if( attitude == NPCATT_KILL ) {
2298 return c_red;
2299 } else if( attitude == NPCATT_FLEE || attitude == NPCATT_FLEE_TEMP ) {
2300 return c_light_red;
2301 } else if( is_player_ally() ) {
2302 return c_green;
2303 } else if( is_walking_with() ) {
2304 return c_light_green;
2305 } else if( guaranteed_hostile() ) {
2306 return c_red;
2307 }
2308 return c_pink;
2309 }
2310
print_info(const catacurses::window & w,int line,int vLines,int column) const2311 int npc::print_info( const catacurses::window &w, int line, int vLines, int column ) const
2312 {
2313 const int last_line = line + vLines;
2314 const int iWidth = getmaxx( w ) - 1 - column;
2315 // First line of w is the border; the next 4 are terrain info, and after that
2316 // is a blank line. w is 13 characters tall, and we can't use the last one
2317 // because it's a border as well; so we have lines 6 through 11.
2318 // w is also 48 characters wide - 2 characters for border = 46 characters for us
2319
2320 // Print health bar and NPC name on the first line.
2321 std::pair<std::string, nc_color> bar = get_hp_bar( hp_percentage(), 100 );
2322 mvwprintz( w, point( column, line ), bar.second, bar.first );
2323 const int bar_max_width = 5;
2324 const int bar_width = utf8_width( bar.first );
2325 for( int i = 0; i < bar_max_width - bar_width; ++i ) {
2326 mvwprintz( w, point( column + 4 - i, line ), c_white, "." );
2327 }
2328 line += fold_and_print( w, point( column + bar_max_width + 1, line ),
2329 iWidth - bar_max_width - 1, basic_symbol_color(), name );
2330
2331 Character &player_character = get_player_character();
2332 // Hostility indicator in the second line.
2333 Attitude att = attitude_to( player_character );
2334 const std::pair<translation, nc_color> res = Creature::get_attitude_ui_data( att );
2335 mvwprintz( w, point( column, line++ ), res.second, res.first.translated() );
2336
2337 // Awareness indicator on the third line.
2338 std::string senses_str = sees( player_character ) ? _( "Aware of your presence" ) :
2339 _( "Unaware of you" );
2340 line += fold_and_print( w, point( column, line ), iWidth,
2341 sees( player_character ) ? c_yellow : c_green,
2342 senses_str );
2343
2344 // Print what item the NPC is holding if any on the fourth line.
2345 if( is_armed() ) {
2346 line += fold_and_print( w, point( column, line ), iWidth, c_red,
2347 std::string( "<color_light_gray>" ) + _( "Wielding: " ) + std::string( "</color>" ) +
2348 weapon.tname() );
2349 }
2350
2351 // Worn gear list on following lines.
2352 const std::string worn_str = enumerate_as_string( worn.begin(), worn.end(), []( const item & it ) {
2353 return it.tname();
2354 } );
2355 if( !worn_str.empty() ) {
2356 std::vector<std::string> worn_lines = foldstring( _( "Wearing: " ) + worn_str, iWidth );
2357 int worn_numlines = worn_lines.size();
2358 for( int i = 0; i < worn_numlines && line < last_line; i++ ) {
2359 if( line + 1 == last_line ) {
2360 worn_lines[i].append( "…" );
2361 }
2362 trim_and_print( w, point( column, line++ ), iWidth, c_light_gray, worn_lines[i] );
2363 }
2364 }
2365
2366 if( line == last_line ) {
2367 return line;
2368 }
2369
2370 // as of now, visibility of mutations is between 0 and 10
2371 // 10 perception and 10 distance would see all mutations - cap 0
2372 // 10 perception and 30 distance - cap 5, some mutations visible
2373 // 3 perception and 3 distance would see all mutations - cap 0
2374 // 3 perception and 15 distance - cap 5, some mutations visible
2375 // 3 perception and 20 distance would be barely able to discern huge antlers on a person - cap 10
2376 const int per = player_character.get_per();
2377 const int dist = rl_dist( player_character.pos(), pos() );
2378 int visibility_cap;
2379 if( per <= 1 ) {
2380 visibility_cap = INT_MAX;
2381 } else {
2382 visibility_cap = std::round( dist * dist / 20.0 / ( per - 1 ) );
2383 }
2384
2385 const std::string trait_str = visible_mutations( visibility_cap );
2386 if( !trait_str.empty() ) {
2387 std::vector<std::string> trait_lines = foldstring( _( "Traits: " ) + trait_str, iWidth );
2388 int trait_numlines = trait_lines.size();
2389 for( int i = 0; i < trait_numlines && line < last_line; i++ ) {
2390 if( line + 1 == last_line ) {
2391 trait_lines[i].append( "…" );
2392 }
2393 trim_and_print( w, point( column, line++ ), iWidth, c_light_gray, trait_lines[i] );
2394 }
2395 }
2396
2397 return line;
2398 }
2399
opinion_text() const2400 std::string npc::opinion_text() const
2401 {
2402 std::string ret;
2403 std::string desc;
2404
2405 if( op_of_u.trust <= -10 ) {
2406 desc = _( "Completely untrusting" );
2407 } else if( op_of_u.trust <= -6 ) {
2408 desc = _( "Very untrusting" );
2409 } else if( op_of_u.trust <= -3 ) {
2410 desc = _( "Untrusting" );
2411 } else if( op_of_u.trust <= 2 ) {
2412 desc = _( "Uneasy" );
2413 } else if( op_of_u.trust <= 4 ) {
2414 desc = _( "Trusting" );
2415 } else if( op_of_u.trust < 10 ) {
2416 desc = _( "Very trusting" );
2417 } else {
2418 desc = _( "Completely trusting" );
2419 }
2420
2421 ret += string_format( _( "Trust: %d (%s);\n" ), op_of_u.trust, desc );
2422
2423 if( op_of_u.fear <= -10 ) {
2424 desc = _( "Thinks you're laughably harmless" );
2425 } else if( op_of_u.fear <= -6 ) {
2426 desc = _( "Thinks you're harmless" );
2427 } else if( op_of_u.fear <= -3 ) {
2428 desc = _( "Unafraid" );
2429 } else if( op_of_u.fear <= 2 ) {
2430 desc = _( "Wary" );
2431 } else if( op_of_u.fear <= 5 ) {
2432 desc = _( "Afraid" );
2433 } else if( op_of_u.fear < 10 ) {
2434 desc = _( "Very afraid" );
2435 } else {
2436 desc = _( "Terrified" );
2437 }
2438
2439 ret += string_format( _( "Fear: %d (%s);\n" ), op_of_u.fear, desc );
2440
2441 if( op_of_u.value <= -10 ) {
2442 desc = _( "Considers you a major liability" );
2443 } else if( op_of_u.value <= -6 ) {
2444 desc = _( "Considers you a burden" );
2445 } else if( op_of_u.value <= -3 ) {
2446 desc = _( "Considers you an annoyance" );
2447 } else if( op_of_u.value <= 2 ) {
2448 desc = _( "Doesn't care about you" );
2449 } else if( op_of_u.value <= 5 ) {
2450 desc = _( "Values your presence" );
2451 } else if( op_of_u.value < 10 ) {
2452 desc = _( "Treasures you" );
2453 } else {
2454 desc = _( "Best Friends Forever!" );
2455 }
2456
2457 ret += string_format( _( "Value: %d (%s);\n" ), op_of_u.value, desc );
2458
2459 if( op_of_u.anger <= -10 ) {
2460 desc = _( "You can do no wrong!" );
2461 } else if( op_of_u.anger <= -6 ) {
2462 desc = _( "You're good people" );
2463 } else if( op_of_u.anger <= -3 ) {
2464 desc = _( "Thinks well of you" );
2465 } else if( op_of_u.anger <= 2 ) {
2466 desc = _( "Ambivalent" );
2467 } else if( op_of_u.anger <= 5 ) {
2468 desc = _( "Pissed off" );
2469 } else if( op_of_u.anger < 10 ) {
2470 desc = _( "Angry" );
2471 } else {
2472 desc = _( "About to kill you" );
2473 }
2474
2475 ret += string_format( _( "Anger: %d (%s)." ), op_of_u.anger, desc );
2476
2477 return ret;
2478 }
2479
maybe_shift(cata::optional<tripoint> & pos,const point & d)2480 static void maybe_shift( cata::optional<tripoint> &pos, const point &d )
2481 {
2482 if( pos ) {
2483 *pos += d;
2484 }
2485 }
2486
maybe_shift(tripoint & pos,const point & d)2487 static void maybe_shift( tripoint &pos, const point &d )
2488 {
2489 if( pos != tripoint_min ) {
2490 pos += d;
2491 }
2492 }
2493
shift(const point & s)2494 void npc::shift( const point &s )
2495 {
2496 const point shift = sm_to_ms_copy( s );
2497
2498 setpos( pos() - shift );
2499
2500 maybe_shift( wanted_item_pos, point( -shift.x, -shift.y ) );
2501 maybe_shift( last_player_seen_pos, point( -shift.x, -shift.y ) );
2502 maybe_shift( pulp_location, point( -shift.x, -shift.y ) );
2503 path.clear();
2504 }
2505
is_dead() const2506 bool npc::is_dead() const
2507 {
2508 return dead || is_dead_state();
2509 }
2510
reboot()2511 void npc::reboot()
2512 {
2513 //The NPC got into an infinite loop, in game.cpp -monmove() - a debugmsg just popped up
2514 // informing player of this.
2515 // put them to sleep and reboot their brain.
2516 // they can be woken up by the player, and if their brain is fixed, great,
2517 // if not, they will faint again, and the NPC can be kept asleep until the bug is fixed.
2518 cancel_activity();
2519 path.clear();
2520 last_player_seen_pos = cata::nullopt;
2521 last_seen_player_turn = 999;
2522 wanted_item_pos = tripoint_min;
2523 guard_pos = tripoint_min;
2524 goal = no_goal_point;
2525 fetching_item = false;
2526 has_new_items = true;
2527 worst_item_value = 0;
2528 mission = NPC_MISSION_NULL;
2529 patience = 0;
2530 ai_cache.danger = 0;
2531 ai_cache.total_danger = 0;
2532 ai_cache.danger_assessment = 0;
2533 ai_cache.target.reset();
2534 ai_cache.ally.reset();
2535 ai_cache.can_heal.clear_all();
2536 ai_cache.sound_alerts.clear();
2537 ai_cache.s_abs_pos = tripoint_zero;
2538 ai_cache.stuck = 0;
2539 ai_cache.guard_pos = cata::nullopt;
2540 ai_cache.my_weapon_value = 0;
2541 ai_cache.friends.clear();
2542 ai_cache.dangerous_explosives.clear();
2543 ai_cache.threat_map.clear();
2544 ai_cache.searched_tiles.clear();
2545 activity = player_activity();
2546 clear_destination();
2547 add_effect( effect_npc_suspend, 24_hours, true, 1 );
2548 }
2549
die(Creature * nkiller)2550 void npc::die( Creature *nkiller )
2551 {
2552 if( dead ) {
2553 // We are already dead, don't die again, note that npc::dead is
2554 // *only* set to true in this function!
2555 return;
2556 }
2557 if( assigned_camp ) {
2558 cata::optional<basecamp *> bcp = overmap_buffer.find_camp( ( *assigned_camp ).xy() );
2559 if( bcp ) {
2560 ( *bcp )->remove_assignee( getID() );
2561 }
2562 }
2563 assigned_camp = cata::nullopt;
2564 // Need to unboard from vehicle before dying, otherwise
2565 // the vehicle code cannot find us
2566 if( in_vehicle ) {
2567 get_map().unboard_vehicle( pos(), true );
2568 }
2569 if( is_mounted() ) {
2570 monster *critter = mounted_creature.get();
2571 critter->remove_effect( effect_ridden );
2572 critter->mounted_player = nullptr;
2573 critter->mounted_player_id = character_id();
2574 }
2575 // if this NPC was the only member of a micro-faction, clean it up.
2576 if( my_fac ) {
2577 if( !is_fake() && !is_hallucination() ) {
2578 if( my_fac->members.size() == 1 ) {
2579 for( const item *elem : inv_dump() ) {
2580 elem->remove_owner();
2581 elem->remove_old_owner();
2582 }
2583 }
2584 my_fac->remove_member( getID() );
2585 }
2586 }
2587 dead = true;
2588 Character::die( nkiller );
2589
2590 if( is_hallucination() ) {
2591 add_msg_if_player_sees( *this, _( "%s disappears." ), name.c_str() );
2592 return;
2593 }
2594
2595 add_msg_if_player_sees( *this, _( "%s dies!" ), name );
2596
2597 if( Character *ch = dynamic_cast<Character *>( killer ) ) {
2598 get_event_bus().send<event_type::character_kills_character>( ch->getID(), getID(), get_name() );
2599 }
2600
2601 Character &player_character = get_player_character();
2602 if( killer == &player_character && ( !guaranteed_hostile() || hit_by_player ) ) {
2603 bool cannibal = player_character.has_trait( trait_CANNIBAL );
2604 bool psycho = player_character.has_trait( trait_PSYCHOPATH );
2605 if( player_character.has_trait( trait_SAPIOVORE ) || psycho ) {
2606 // No morale effect
2607 } else if( cannibal ) {
2608 player_character.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours );
2609 } else {
2610 player_character.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours );
2611 }
2612 }
2613
2614 place_corpse();
2615 }
2616
npc_attitude_id(npc_attitude att)2617 std::string npc_attitude_id( npc_attitude att )
2618 {
2619 static const std::map<npc_attitude, std::string> npc_attitude_ids = {
2620 { NPCATT_NULL, "NPCATT_NULL" },
2621 { NPCATT_TALK, "NPCATT_TALK" },
2622 { NPCATT_FOLLOW, "NPCATT_FOLLOW" },
2623 { NPCATT_LEAD, "NPCATT_LEAD" },
2624 { NPCATT_WAIT, "NPCATT_WAIT" },
2625 { NPCATT_MUG, "NPCATT_MUG" },
2626 { NPCATT_WAIT_FOR_LEAVE, "NPCATT_WAIT_FOR_LEAVE" },
2627 { NPCATT_KILL, "NPCATT_KILL" },
2628 { NPCATT_FLEE, "NPCATT_FLEE" },
2629 { NPCATT_FLEE_TEMP, "NPCATT_FLEE_TEMP" },
2630 { NPCATT_HEAL, "NPCATT_HEAL" },
2631 { NPCATT_ACTIVITY, "NPCATT_ACTIVITY" },
2632 { NPCATT_RECOVER_GOODS, "NPCATT_RECOVER_GOODS" },
2633 { NPCATT_LEGACY_1, "NPCATT_LEGACY_1" },
2634 { NPCATT_LEGACY_2, "NPCATT_LEGACY_2" },
2635 { NPCATT_LEGACY_3, "NPCATT_LEGACY_3" },
2636 { NPCATT_LEGACY_4, "NPCATT_LEGACY_4" },
2637 { NPCATT_LEGACY_5, "NPCATT_LEGACY_5" },
2638 { NPCATT_LEGACY_6, "NPCATT_LEGACY_6" },
2639 };
2640 const auto &iter = npc_attitude_ids.find( att );
2641 if( iter == npc_attitude_ids.end() ) {
2642 debugmsg( "Invalid attitude: %d", att );
2643 return "NPCATT_INVALID";
2644 }
2645
2646 return iter->second;
2647 }
2648
npc_attitude_name(npc_attitude att)2649 std::string npc_attitude_name( npc_attitude att )
2650 {
2651 switch( att ) {
2652 // Don't care/ignoring player
2653 case NPCATT_NULL:
2654 return _( "Ignoring" );
2655 // Move to and talk to player
2656 case NPCATT_TALK:
2657 return _( "Wants to talk" );
2658 // Follow the player
2659 case NPCATT_FOLLOW:
2660 return _( "Following" );
2661 // Lead the player, wait for them if they're behind
2662 case NPCATT_LEAD:
2663 return _( "Leading" );
2664 // Waiting for the player
2665 case NPCATT_WAIT:
2666 return _( "Waiting for you" );
2667 // Mug the player
2668 case NPCATT_MUG:
2669 return _( "Mugging you" );
2670 // Attack the player if our patience runs out
2671 case NPCATT_WAIT_FOR_LEAVE:
2672 return _( "Waiting for you to leave" );
2673 // Kill the player
2674 case NPCATT_KILL:
2675 return _( "Attacking to kill" );
2676 // Get away from the player
2677 case NPCATT_FLEE:
2678 case NPCATT_FLEE_TEMP:
2679 return _( "Fleeing" );
2680 // Get to the player and heal them
2681 case NPCATT_HEAL:
2682 return _( "Healing you" );
2683 case NPCATT_ACTIVITY:
2684 return _( "Performing a task" );
2685 case NPCATT_RECOVER_GOODS:
2686 return _( "Trying to recover stolen goods" );
2687 case NPCATT_LEGACY_1:
2688 case NPCATT_LEGACY_2:
2689 case NPCATT_LEGACY_3:
2690 case NPCATT_LEGACY_4:
2691 case NPCATT_LEGACY_5:
2692 case NPCATT_LEGACY_6:
2693 return _( "NPC Legacy Attitude" );
2694 default:
2695 break;
2696 }
2697
2698 debugmsg( "Invalid attitude: %d", att );
2699 return _( "Unknown attitude" );
2700 }
2701
2702 //message related stuff
2703
2704 //message related stuff
add_msg_if_npc(const std::string & msg) const2705 void npc::add_msg_if_npc( const std::string &msg ) const
2706 {
2707 add_msg( replace_with_npc_name( msg ) );
2708 }
2709
add_msg_player_or_npc(const std::string &,const std::string & npc_msg) const2710 void npc::add_msg_player_or_npc( const std::string &/*player_msg*/,
2711 const std::string &npc_msg ) const
2712 {
2713 add_msg_if_player_sees( *this, replace_with_npc_name( npc_msg ) );
2714 }
2715
add_msg_if_npc(const game_message_params & params,const std::string & msg) const2716 void npc::add_msg_if_npc( const game_message_params ¶ms, const std::string &msg ) const
2717 {
2718 add_msg( params, replace_with_npc_name( msg ) );
2719 }
2720
add_msg_player_or_npc(const game_message_params & params,const std::string &,const std::string & npc_msg) const2721 void npc::add_msg_player_or_npc( const game_message_params ¶ms,
2722 const std::string &/*player_msg*/,
2723 const std::string &npc_msg ) const
2724 {
2725 if( get_player_view().sees( *this ) ) {
2726 add_msg( params, replace_with_npc_name( npc_msg ) );
2727 }
2728 }
2729
add_msg_player_or_say(const std::string &,const std::string & npc_speech) const2730 void npc::add_msg_player_or_say( const std::string &/*player_msg*/,
2731 const std::string &npc_speech ) const
2732 {
2733 say( npc_speech );
2734 }
2735
add_msg_player_or_say(const game_message_params &,const std::string &,const std::string & npc_speech) const2736 void npc::add_msg_player_or_say( const game_message_params &/*params*/,
2737 const std::string &/*player_msg*/, const std::string &npc_speech ) const
2738 {
2739 say( npc_speech );
2740 }
2741
add_new_mission(class mission * miss)2742 void npc::add_new_mission( class mission *miss )
2743 {
2744 chatbin.add_new_mission( miss );
2745 }
2746
on_unload()2747 void npc::on_unload()
2748 {
2749 }
2750
2751 // A throtled version of player::update_body since npc's don't need to-the-turn updates.
npc_update_body()2752 void npc::npc_update_body()
2753 {
2754 if( calendar::once_every( 10_seconds ) ) {
2755 update_body( last_updated, calendar::turn );
2756 last_updated = calendar::turn;
2757 }
2758 }
2759
on_load()2760 void npc::on_load()
2761 {
2762 const auto advance_effects = [&]( const time_duration & elapsed_dur ) {
2763 for( auto &elem : *effects ) {
2764 for( auto &_effect_it : elem.second ) {
2765 effect &e = _effect_it.second;
2766 const time_duration &time_left = e.get_duration();
2767 if( time_left > 1_turns ) {
2768 if( time_left < elapsed_dur ) {
2769 e.set_duration( 1_turns );
2770 } else {
2771 e.set_duration( time_left - elapsed_dur );
2772 }
2773 }
2774 }
2775 }
2776 };
2777 // Cap at some reasonable number, say 2 days
2778 const time_duration dt = std::min( calendar::turn - last_updated, 2_days );
2779 // TODO: Sleeping, healing etc.
2780 last_updated = calendar::turn;
2781 time_point cur = calendar::turn - dt;
2782 add_msg_debug( "on_load() by %s, %d turns", name, to_turns<int>( dt ) );
2783 // First update with 30 minute granularity, then 5 minutes, then turns
2784 for( ; cur < calendar::turn - 30_minutes; cur += 30_minutes + 1_turns ) {
2785 update_body( cur, cur + 30_minutes );
2786 advance_effects( 30_minutes );
2787 }
2788 for( ; cur < calendar::turn - 5_minutes; cur += 5_minutes + 1_turns ) {
2789 update_body( cur, cur + 5_minutes );
2790 advance_effects( 5_minutes );
2791 }
2792 for( ; cur < calendar::turn; cur += 1_turns ) {
2793 update_body( cur, cur + 1_turns );
2794 process_effects();
2795 }
2796
2797 if( dt > 0_turns ) {
2798 // This ensures food is properly rotten at load
2799 // Otherwise NPCs try to eat rotten food and fail
2800 process_items();
2801 // give NPCs that are doing activities a pile of moves
2802 if( has_destination() || activity ) {
2803 mod_moves( to_moves<int>( dt ) );
2804 }
2805 }
2806
2807 // Not necessarily true, but it's not a bad idea to set this
2808 has_new_items = true;
2809
2810 map &here = get_map();
2811 // for spawned npcs
2812 if( here.has_flag( "UNSTABLE", pos() ) ) {
2813 add_effect( effect_bouldering, 1_turns, true );
2814 } else if( has_effect( effect_bouldering ) ) {
2815 remove_effect( effect_bouldering );
2816 }
2817 if( here.veh_at( pos() ).part_with_feature( VPFLAG_BOARDABLE, true ) && !in_vehicle ) {
2818 here.board_vehicle( pos(), this );
2819 }
2820 if( has_effect( effect_riding ) && !mounted_creature ) {
2821 if( const monster *const mon = g->critter_at<monster>( pos() ) ) {
2822 mounted_creature = g->shared_from( *mon );
2823 } else {
2824 add_msg_debug( "NPC is meant to be riding, though the mount is not found when %s is loaded",
2825 disp_name() );
2826 }
2827 }
2828 if( has_trait( trait_HALLUCINATION ) ) {
2829 hallucination = true;
2830 }
2831 }
2832
2833 constexpr tripoint_abs_omt npc::no_goal_point;
2834
query_yn(const std::string &) const2835 bool npc::query_yn( const std::string &/*msg*/ ) const
2836 {
2837 // NPCs don't like queries - most of them are in the form of "Do you want to get hurt?".
2838 return false;
2839 }
2840
speed_rating() const2841 float npc::speed_rating() const
2842 {
2843 float ret = get_speed() / 100.0f;
2844 ret *= 100.0f / run_cost( 100, false );
2845
2846 return ret;
2847 }
2848
dispose_item(item_location && obj,const std::string &)2849 bool npc::dispose_item( item_location &&obj, const std::string & )
2850 {
2851 stow_item( *obj.get_item() );
2852 return true;
2853 }
2854
process_turn()2855 void npc::process_turn()
2856 {
2857 player::process_turn();
2858
2859 // NPCs shouldn't be using stamina, but if they have, set it back to max
2860 // If the stamina is higher than the max (Languorous), set it back to max
2861 if( calendar::once_every( 1_minutes ) && get_stamina() != get_stamina_max() ) {
2862 set_stamina( get_stamina_max() );
2863 }
2864
2865 if( is_player_ally() && calendar::once_every( 1_hours ) &&
2866 get_hunger() < 200 && get_thirst() < 100 && op_of_u.trust < 5 ) {
2867 // Friends who are well fed will like you more
2868 // 24 checks per day, best case chance at trust 0 is 1 in 48 for +1 trust per 2 days
2869 float trust_chance = 5 - op_of_u.trust;
2870 // Penalize for bad impression
2871 // TODO: Penalize for traits and actions (especially murder, unless NPC is psycho)
2872 int op_penalty = std::max( 0, op_of_u.anger ) +
2873 std::max( 0, -op_of_u.value ) +
2874 std::max( 0, op_of_u.fear );
2875 // Being barely hungry and thirsty, not in pain and not wounded means good care
2876 int state_penalty = get_hunger() + get_thirst() + ( 100 - hp_percentage() ) + get_pain();
2877 if( x_in_y( trust_chance, 240 + 10 * op_penalty + state_penalty ) ) {
2878 op_of_u.trust++;
2879 }
2880
2881 // TODO: Similar checks for fear and anger
2882 }
2883
2884 // TODO: Add decreasing trust/value/etc. here when player doesn't provide food
2885 // TODO: Make NPCs leave the player if there's a path out of map and player is sleeping/unseen/etc.
2886 }
2887
invoke_item(item * used,const tripoint & pt,int)2888 bool npc::invoke_item( item *used, const tripoint &pt, int )
2889 {
2890 const auto &use_methods = used->type->use_methods;
2891
2892 if( use_methods.empty() ) {
2893 return false;
2894 } else if( use_methods.size() == 1 ) {
2895 return Character::invoke_item( used, use_methods.begin()->first, pt );
2896 }
2897 return false;
2898 }
2899
invoke_item(item * used,const std::string & method)2900 bool npc::invoke_item( item *used, const std::string &method )
2901 {
2902 return Character::invoke_item( used, method );
2903 }
2904
invoke_item(item * used)2905 bool npc::invoke_item( item *used )
2906 {
2907 return Character::invoke_item( used );
2908 }
2909
2910 std::array<std::pair<std::string, overmap_location_str_id>, npc_need::num_needs> npc::need_data = {
2911 {
2912 { "need_none", overmap_location_str_id( "source_of_anything" ) },
2913 { "need_ammo", overmap_location_str_id( "source_of_ammo" ) },
2914 { "need_weapon", overmap_location_str_id( "source_of_weapons" )},
2915 { "need_gun", overmap_location_str_id( "source_of_guns" ) },
2916 { "need_food", overmap_location_str_id( "source_of_food" )},
2917 { "need_drink", overmap_location_str_id( "source_of_drink" ) },
2918 { "need_safety", overmap_location_str_id( "source_of_safety" ) }
2919 }
2920 };
2921
get_need_str_id(const npc_need & need)2922 std::string npc::get_need_str_id( const npc_need &need )
2923 {
2924 return need_data[static_cast<size_t>( need )].first;
2925 }
2926
get_location_for(const npc_need & need)2927 overmap_location_str_id npc::get_location_for( const npc_need &need )
2928 {
2929 return need_data[static_cast<size_t>( need )].second;
2930 }
2931
operator <<(std::ostream & os,const npc_need & need)2932 std::ostream &operator<< ( std::ostream &os, const npc_need &need )
2933 {
2934 return os << npc::get_need_str_id( need );
2935 }
2936
will_accept_from_player(const item & it) const2937 bool npc::will_accept_from_player( const item &it ) const
2938 {
2939 if( is_hallucination() ) {
2940 return false;
2941 }
2942
2943 if( is_minion() || get_player_character().has_trait( trait_DEBUG_MIND_CONTROL ) ||
2944 it.has_flag( flag_NPC_SAFE ) ) {
2945 return true;
2946 }
2947
2948 if( !it.type->use_methods.empty() ) {
2949 return false;
2950 }
2951
2952 if( it.is_comestible() ) {
2953 if( it.get_comestible_fun() < 0 || it.poison > 0 ) {
2954 return false;
2955 }
2956 }
2957
2958 return true;
2959 }
2960
get_pathfinding_settings() const2961 const pathfinding_settings &npc::get_pathfinding_settings() const
2962 {
2963 return get_pathfinding_settings( false );
2964 }
2965
get_pathfinding_settings(bool no_bashing) const2966 const pathfinding_settings &npc::get_pathfinding_settings( bool no_bashing ) const
2967 {
2968 path_settings->bash_strength = no_bashing ? 0 : smash_ability();
2969 // TODO: Extract climb skill
2970 const int climb = std::min( 20, get_dex() );
2971 if( climb > 1 ) {
2972 // Success is !one_in(dex), so 0%, 50%, 66%, 75%...
2973 // Penalty for failure chance is 1/success = 1/(1-failure) = 1/(1-(1/dex)) = dex/(dex-1)
2974 path_settings->climb_cost = ( 10 - climb / 5 ) * climb / ( climb - 1 );
2975 } else {
2976 // Climbing at this dexterity will always fail
2977 path_settings->climb_cost = 0;
2978 }
2979
2980 return *path_settings;
2981 }
2982
get_path_avoid() const2983 std::set<tripoint> npc::get_path_avoid() const
2984 {
2985 std::set<tripoint> ret;
2986 for( Creature &critter : g->all_creatures() ) {
2987 // TODO: Cache this somewhere
2988 ret.insert( critter.pos() );
2989 }
2990 map &here = get_map();
2991 if( rules.has_flag( ally_rule::avoid_doors ) ) {
2992 for( const tripoint &p : here.points_in_radius( pos(), 30 ) ) {
2993 if( here.open_door( p, true, true ) ) {
2994 ret.insert( p );
2995 }
2996 }
2997 }
2998 if( rules.has_flag( ally_rule::hold_the_line ) ) {
2999 for( const tripoint &p : here.points_in_radius( get_player_character().pos(), 1 ) ) {
3000 if( here.close_door( p, true, true ) || here.move_cost( p ) > 2 ) {
3001 ret.insert( p );
3002 }
3003 }
3004 }
3005 return ret;
3006 }
3007
get_monster_faction() const3008 mfaction_id npc::get_monster_faction() const
3009 {
3010 if( my_fac ) {
3011 if( my_fac->mon_faction.is_valid() ) {
3012 return my_fac->mon_faction;
3013 }
3014 }
3015
3016 // legacy checks
3017 // Those can't be static int_ids, because mods add factions
3018 static const string_id<monfaction> human_fac( "human" );
3019 static const string_id<monfaction> player_fac( "player" );
3020 static const string_id<monfaction> bee_fac( "bee" );
3021
3022 if( is_player_ally() ) {
3023 return player_fac.id();
3024 }
3025
3026 if( has_trait( trait_BEE ) ) {
3027 return bee_fac.id();
3028 }
3029
3030 return human_fac.id();
3031 }
3032
extended_description() const3033 std::string npc::extended_description() const
3034 {
3035 std::string ss;
3036 // For some reason setting it using str or constructor doesn't work
3037 ss += Character::extended_description();
3038
3039 ss += "\n--\n";
3040 if( attitude == NPCATT_KILL ) {
3041 ss += _( "Is trying to kill you." );
3042 } else if( attitude == NPCATT_FLEE || attitude == NPCATT_FLEE_TEMP ) {
3043 ss += _( "Is trying to flee from you." );
3044 } else if( is_player_ally() ) {
3045 ss += _( "Is your friend." );
3046 } else if( is_following() ) {
3047 ss += _( "Is following you." );
3048 } else if( is_leader() ) {
3049 ss += _( "Is guiding you." );
3050 } else if( guaranteed_hostile() ) {
3051 ss += _( "Will try to kill you or flee from you if you reveal yourself." );
3052 } else {
3053 ss += _( "Is neutral." );
3054 }
3055
3056 if( hit_by_player ) {
3057 ss += "--\n";
3058 ss += _( "Is still innocent and killing them will be considered murder." );
3059 // TODO: "But you don't care because you're an edgy psycho"
3060 }
3061
3062 return replace_colors( ss );
3063 }
3064
get_epilogue() const3065 std::string npc::get_epilogue() const
3066 {
3067 return SNIPPET.random_from_category(
3068 male ? "epilogue_npc_male" : "epilogue_npc_female"
3069 ).value_or( translation() ).translated();
3070 }
3071
set_companion_mission(npc & p,const std::string & mission_id)3072 void npc::set_companion_mission( npc &p, const std::string &mission_id )
3073 {
3074 const tripoint_abs_omt omt_pos = p.global_omt_location();
3075 set_companion_mission( omt_pos, p.companion_mission_role_id, mission_id );
3076 }
3077
hp_description() const3078 std::pair<std::string, nc_color> npc::hp_description() const
3079 {
3080 int cur_hp = hp_percentage();
3081 std::string damage_info;
3082 std::string pronoun;
3083 if( male ) {
3084 pronoun = _( "He " );
3085 } else {
3086 pronoun = _( "She " );
3087 }
3088 nc_color col;
3089 if( cur_hp == 100 ) {
3090 damage_info = pronoun + _( "is uninjured." );
3091 col = c_green;
3092 } else if( cur_hp >= 80 ) {
3093 damage_info = pronoun + _( "is lightly injured." );
3094 col = c_light_green;
3095 } else if( cur_hp >= 60 ) {
3096 damage_info = pronoun + _( "is moderately injured." );
3097 col = c_yellow;
3098 } else if( cur_hp >= 30 ) {
3099 damage_info = pronoun + _( "is heavily injured." );
3100 col = c_yellow;
3101 } else if( cur_hp >= 10 ) {
3102 damage_info = pronoun + _( "is severely injured." );
3103 col = c_light_red;
3104 } else {
3105 damage_info = pronoun + _( "is nearly dead!" );
3106 col = c_red;
3107 }
3108 return std::make_pair( damage_info, col );
3109 }
set_companion_mission(const tripoint_abs_omt & omt_pos,const std::string & role_id,const std::string & mission_id)3110 void npc::set_companion_mission( const tripoint_abs_omt &omt_pos, const std::string &role_id,
3111 const std::string &mission_id )
3112 {
3113 comp_mission.position = omt_pos;
3114 comp_mission.mission_id = mission_id;
3115 comp_mission.role_id = role_id;
3116 }
3117
set_companion_mission(const tripoint_abs_omt & omt_pos,const std::string & role_id,const std::string & mission_id,const tripoint_abs_omt & destination)3118 void npc::set_companion_mission( const tripoint_abs_omt &omt_pos, const std::string &role_id,
3119 const std::string &mission_id, const tripoint_abs_omt &destination )
3120 {
3121 comp_mission.position = omt_pos;
3122 comp_mission.mission_id = mission_id;
3123 comp_mission.role_id = role_id;
3124 comp_mission.destination = destination;
3125 }
3126
reset_companion_mission()3127 void npc::reset_companion_mission()
3128 {
3129 comp_mission.position = tripoint_abs_omt( -999, -999, -999 );
3130 comp_mission.mission_id.clear();
3131 comp_mission.role_id.clear();
3132 if( comp_mission.destination ) {
3133 comp_mission.destination = cata::nullopt;
3134 }
3135 }
3136
get_mission_destination() const3137 cata::optional<tripoint_abs_omt> npc::get_mission_destination() const
3138 {
3139 if( comp_mission.destination ) {
3140 return comp_mission.destination;
3141 } else {
3142 return cata::nullopt;
3143 }
3144 }
3145
has_companion_mission() const3146 bool npc::has_companion_mission() const
3147 {
3148 return !comp_mission.mission_id.empty();
3149 }
3150
get_companion_mission() const3151 npc_companion_mission npc::get_companion_mission() const
3152 {
3153 return comp_mission;
3154 }
3155
get_attitude_group(npc_attitude att) const3156 attitude_group npc::get_attitude_group( npc_attitude att ) const
3157 {
3158 switch( att ) {
3159 case NPCATT_MUG:
3160 case NPCATT_WAIT_FOR_LEAVE:
3161 case NPCATT_KILL:
3162 return attitude_group::hostile;
3163 case NPCATT_FLEE:
3164 case NPCATT_FLEE_TEMP:
3165 return attitude_group::fearful;
3166 case NPCATT_FOLLOW:
3167 case NPCATT_ACTIVITY:
3168 case NPCATT_LEAD:
3169 return attitude_group::friendly;
3170 default:
3171 break;
3172 }
3173 return attitude_group::neutral;
3174 }
3175
set_mission(npc_mission new_mission)3176 void npc::set_mission( npc_mission new_mission )
3177 {
3178 if( new_mission != mission ) {
3179 previous_mission = mission;
3180 mission = new_mission;
3181 }
3182 if( mission == NPC_MISSION_ACTIVITY ) {
3183 current_activity_id = activity.id();
3184 }
3185 }
3186
has_activity() const3187 bool npc::has_activity() const
3188 {
3189 return mission == NPC_MISSION_ACTIVITY && attitude == NPCATT_ACTIVITY;
3190 }
3191
get_attitude() const3192 npc_attitude npc::get_attitude() const
3193 {
3194 return attitude;
3195 }
3196
set_attitude(npc_attitude new_attitude)3197 void npc::set_attitude( npc_attitude new_attitude )
3198 {
3199 if( new_attitude == attitude ) {
3200 return;
3201 }
3202 previous_attitude = attitude;
3203 if( new_attitude == NPCATT_FLEE ) {
3204 new_attitude = NPCATT_FLEE_TEMP;
3205 }
3206 if( new_attitude == NPCATT_FLEE_TEMP && !has_effect( effect_npc_flee_player ) ) {
3207 add_effect( effect_npc_flee_player, 24_hours );
3208 }
3209
3210 add_msg_debug( "%s changes attitude from %s to %s",
3211 name, npc_attitude_id( attitude ), npc_attitude_id( new_attitude ) );
3212 attitude_group new_group = get_attitude_group( new_attitude );
3213 attitude_group old_group = get_attitude_group( attitude );
3214 if( new_group != old_group && !is_fake() && get_player_view().sees( *this ) ) {
3215 switch( new_group ) {
3216 case attitude_group::hostile:
3217 add_msg_if_npc( m_bad, _( "<npcname> gets angry!" ) );
3218 break;
3219 case attitude_group::fearful:
3220 add_msg_if_npc( m_warning, _( "<npcname> gets scared!" ) );
3221 break;
3222 default:
3223 if( old_group == attitude_group::hostile ) {
3224 add_msg_if_npc( m_good, _( "<npcname> calms down." ) );
3225 } else if( old_group == attitude_group::fearful ) {
3226 add_msg_if_npc( _( "<npcname> is no longer afraid." ) );
3227 }
3228 break;
3229 }
3230 }
3231 attitude = new_attitude;
3232 }
3233
npc_follower_rules()3234 npc_follower_rules::npc_follower_rules()
3235 {
3236 engagement = combat_engagement::CLOSE;
3237 aim = aim_rule::WHEN_CONVENIENT;
3238 overrides = ally_rule::DEFAULT;
3239 override_enable = ally_rule::DEFAULT;
3240
3241 set_flag( ally_rule::use_guns );
3242 set_flag( ally_rule::use_grenades );
3243 clear_flag( ally_rule::use_silent );
3244 set_flag( ally_rule::avoid_friendly_fire );
3245
3246 clear_flag( ally_rule::allow_pick_up );
3247 clear_flag( ally_rule::allow_bash );
3248 clear_flag( ally_rule::allow_sleep );
3249 set_flag( ally_rule::allow_complain );
3250 set_flag( ally_rule::allow_pulp );
3251 clear_flag( ally_rule::close_doors );
3252 clear_flag( ally_rule::follow_close );
3253 clear_flag( ally_rule::avoid_doors );
3254 clear_flag( ally_rule::hold_the_line );
3255 clear_flag( ally_rule::ignore_noise );
3256 clear_flag( ally_rule::forbid_engage );
3257 set_flag( ally_rule::follow_distance_2 );
3258 }
3259
has_flag(ally_rule test,bool check_override) const3260 bool npc_follower_rules::has_flag( ally_rule test, bool check_override ) const
3261 {
3262 if( check_override && ( static_cast<int>( test ) & static_cast<int>( override_enable ) ) ) {
3263 // if the override is set and false, return false
3264 if( static_cast<int>( test ) & ~static_cast<int>( overrides ) ) {
3265 return false;
3266 // if the override is set and true, return true
3267 } else if( static_cast<int>( test ) & static_cast<int>( overrides ) ) {
3268 return true;
3269 }
3270 }
3271 return static_cast<int>( test ) & static_cast<int>( flags );
3272 }
3273
set_flag(ally_rule setit)3274 void npc_follower_rules::set_flag( ally_rule setit )
3275 {
3276 flags = static_cast<ally_rule>( static_cast<int>( flags ) | static_cast<int>( setit ) );
3277 }
3278
clear_flag(ally_rule clearit)3279 void npc_follower_rules::clear_flag( ally_rule clearit )
3280 {
3281 flags = static_cast<ally_rule>( static_cast<int>( flags ) & ~static_cast<int>( clearit ) );
3282 }
3283
toggle_flag(ally_rule toggle)3284 void npc_follower_rules::toggle_flag( ally_rule toggle )
3285 {
3286 if( has_flag( toggle ) ) {
3287 clear_flag( toggle );
3288 } else {
3289 set_flag( toggle );
3290 }
3291 }
3292
set_specific_override_state(ally_rule rule,bool state)3293 void npc_follower_rules::set_specific_override_state( ally_rule rule, bool state )
3294 {
3295 if( state ) {
3296 set_override( rule );
3297 } else {
3298 clear_override( rule );
3299 }
3300 enable_override( rule );
3301 }
3302
toggle_specific_override_state(ally_rule rule,bool state)3303 void npc_follower_rules::toggle_specific_override_state( ally_rule rule, bool state )
3304 {
3305 if( has_override_enable( rule ) && has_override( rule ) == state ) {
3306 clear_override( rule );
3307 disable_override( rule );
3308 } else {
3309 set_specific_override_state( rule, state );
3310 }
3311 }
3312
has_override_enable(ally_rule test) const3313 bool npc_follower_rules::has_override_enable( ally_rule test ) const
3314 {
3315 return static_cast<int>( test ) & static_cast<int>( override_enable );
3316 }
3317
enable_override(ally_rule setit)3318 void npc_follower_rules::enable_override( ally_rule setit )
3319 {
3320 override_enable = static_cast<ally_rule>( static_cast<int>( override_enable ) |
3321 static_cast<int>( setit ) );
3322 }
3323
disable_override(ally_rule clearit)3324 void npc_follower_rules::disable_override( ally_rule clearit )
3325 {
3326 override_enable = static_cast<ally_rule>( static_cast<int>( override_enable ) &
3327 ~static_cast<int>( clearit ) );
3328 }
3329
has_override(ally_rule test) const3330 bool npc_follower_rules::has_override( ally_rule test ) const
3331 {
3332 return static_cast<int>( test ) & static_cast<int>( overrides );
3333 }
3334
set_override(ally_rule setit)3335 void npc_follower_rules::set_override( ally_rule setit )
3336 {
3337 overrides = static_cast<ally_rule>( static_cast<int>( overrides ) | static_cast<int>( setit ) );
3338 }
3339
clear_override(ally_rule clearit)3340 void npc_follower_rules::clear_override( ally_rule clearit )
3341 {
3342 overrides = static_cast<ally_rule>( static_cast<int>( overrides ) &
3343 ~static_cast<int>( clearit ) );
3344 }
3345
set_danger_overrides()3346 void npc_follower_rules::set_danger_overrides()
3347 {
3348 overrides = ally_rule::DEFAULT;
3349 override_enable = ally_rule::DEFAULT;
3350 set_override( ally_rule::follow_close );
3351 set_override( ally_rule::avoid_doors );
3352 set_override( ally_rule::hold_the_line );
3353 enable_override( ally_rule::follow_close );
3354 enable_override( ally_rule::allow_sleep );
3355 enable_override( ally_rule::close_doors );
3356 enable_override( ally_rule::avoid_doors );
3357 enable_override( ally_rule::hold_the_line );
3358 }
3359
clear_overrides()3360 void npc_follower_rules::clear_overrides()
3361 {
3362 overrides = ally_rule::DEFAULT;
3363 override_enable = ally_rule::DEFAULT;
3364 }
3365
get_thirst() const3366 int npc::get_thirst() const
3367 {
3368 return Character::get_thirst() - units::to_milliliter<int>( stomach.get_water() ) / 5;
3369 }
3370
describe_mission() const3371 std::string npc::describe_mission() const
3372 {
3373 switch( mission ) {
3374 case NPC_MISSION_SHELTER:
3375 return string_format( _( "I'm holing up here for safety. Long term, %s" ),
3376 myclass.obj().get_job_description() );
3377 case NPC_MISSION_SHOPKEEP:
3378 return _( "I run the shop here." );
3379 case NPC_MISSION_GUARD:
3380 case NPC_MISSION_GUARD_ALLY:
3381 case NPC_MISSION_GUARD_PATROL:
3382 return string_format( _( "Currently, I'm guarding this location. Overall, %s" ),
3383 myclass.obj().get_job_description() );
3384 case NPC_MISSION_ACTIVITY:
3385 return string_format( _( "Right now, I'm <current_activity>. In general, %s" ),
3386 myclass.obj().get_job_description() );
3387 case NPC_MISSION_TRAVELLING:
3388 case NPC_MISSION_NULL:
3389 return myclass.obj().get_job_description();
3390 default:
3391 return string_format( "ERROR: Someone forgot to code an npc_mission text for "
3392 "mission: %d.", static_cast<int>( mission ) );
3393 } // switch (mission)
3394 }
3395
name_and_activity() const3396 std::string npc::name_and_activity() const
3397 {
3398 if( current_activity_id ) {
3399 const std::string activity_name = current_activity_id.obj().verb().translated();
3400 //~ %1$s - npc name, %2$s - npc current activity name.
3401 return string_format( _( "%1$s (%2$s)" ), name, activity_name );
3402 } else {
3403 return name;
3404 }
3405 }
3406
get_talker_for(npc & guy)3407 std::unique_ptr<talker> get_talker_for( npc &guy )
3408 {
3409 return std::make_unique<talker_npc>( &guy );
3410 }
get_talker_for(npc * guy)3411 std::unique_ptr<talker> get_talker_for( npc *guy )
3412 {
3413 return std::make_unique<talker_npc>( guy );
3414 }
3415