• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CleverRaven / Cataclysm-DDA / 13038

pending completion
13038

Pull #26687

travis-ci

web-flow
Revert "Improve monster tracker by eliminating the unecessary vector member."
Pull Request #26687: Revert "Improve monster tracker by eliminating the unecessary vector member."

69 of 69 new or added lines in 4 files covered. (100.0%)

31167 of 118126 relevant lines covered (26.38%)

98904.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

27.04
/src/npcmove.cpp
1
#include "npc.h"
2

3
#include "ammo.h"
4
#include "cata_algo.h"
5
#include "debug.h"
6
#include "dispersion.h"
7
#include "effect.h"
8
#include "field.h"
9
#include "game.h"
10
#include "gates.h"
11
#include "gun_mode.h"
12
#include "itype.h"
13
#include "iuse_actor.h"
14
#include "line.h"
15
#include "map.h"
16
#include "map_iterator.h"
17
#include "messages.h"
18
#include "monster.h"
19
#include "mtype.h"
20
#include "output.h"
21
#include "overmap_location.h"
22
#include "overmapbuffer.h"
23
#include "projectile.h"
24
#include "ranged.h"
25
#include "rng.h"
26
#include "sounds.h"
27
#include "translations.h"
28
#include "veh_type.h"
29
#include "vehicle.h"
30
#include "visitable.h"
31
#include "vpart_position.h"
32
#include "vpart_range.h"
33
#include "vpart_reference.h"
34

35
#include <algorithm>
36
#include <memory>
37
#include <numeric>
38
#include <sstream>
39

40
// @todo: Get rid of this include
41

42
#define NPC_DANGER_VERY_LOW 5
43

44
#define dbg(x) DebugLog((DebugLevel)(x),D_NPC) << __FILE__ << ":" << __LINE__ << ": "
45

46
const skill_id skill_firstaid( "firstaid" );
1✔
47
const skill_id skill_gun( "gun" );
1✔
48
const skill_id skill_throw( "throw" );
1✔
49

50
const efftype_id effect_bleed( "bleed" );
1✔
51
const efftype_id effect_bite( "bite" );
1✔
52
const efftype_id effect_bouldering( "bouldering" );
1✔
53
const efftype_id effect_catch_up( "catch_up" );
1✔
54
const efftype_id effect_hit_by_player( "hit_by_player" );
1✔
55
const efftype_id effect_infection( "infection" );
1✔
56
const efftype_id effect_infected( "infected" );
1✔
57
const efftype_id effect_lying_down( "lying_down" );
1✔
58
const efftype_id effect_stunned( "stunned" );
1✔
59
const efftype_id effect_onfire( "onfire" );
1✔
60

61
enum npc_action : int {
62
    npc_undecided = 0,
63
    npc_pause,
64
    npc_reload, npc_sleep,
65
    npc_pickup,
66
    npc_wield_melee, npc_wield_loaded_gun, npc_wield_empty_gun,
67
    npc_heal, npc_use_painkiller, npc_drop_items,
68
    npc_flee, npc_melee, npc_shoot,
69
    npc_look_for_player, npc_heal_player, npc_follow_player, npc_follow_embarked,
70
    npc_talk_to_player, npc_mug_player,
71
    npc_goto_destination,
72
    npc_avoid_friendly_fire,
73
    npc_escape_explosion,
74
    npc_base_idle,
75
    npc_noop,
76
    npc_reach_attack,
77
    npc_aim,
78
    num_npc_actions
79
};
80

81
namespace
82
{
83

84
const int avoidance_vehicles_radius = 5;
85

86
}
87

88
std::string npc_action_name( npc_action action );
89

90
void print_action( const char *prepend, npc_action action );
91

92
hp_part most_damaged_hp_part( const Character &c );
93

94
// Used in npc::drop_items()
95
struct ratio_index {
96
    double ratio;
97
    int index;
98
    ratio_index( double R, int I ) : ratio( R ), index( I ) {}
×
99
};
100

101
bool clear_shot_reach( const tripoint &from, const tripoint &to )
×
102
{
103
    std::vector<tripoint> path = line_to( from, to );
×
104
    path.pop_back();
×
105
    for( const tripoint &p : path ) {
×
106
        Creature *inter = g->critter_at( p );
×
107
        if( inter != nullptr ) {
×
108
            return false;
109
        } else if( g->m.impassable( p ) ) {
×
110
            return false;
111
        }
112
    }
113

114
    return true;
115
}
116

117
tripoint good_escape_direction( const npc &who )
24✔
118
{
119
    std::vector<tripoint> candidates;
120

121
    const auto rate_pt = [&who]( const tripoint & p ) {
216✔
122
        if( !g->m.passable( p ) ) {
216✔
123
            return INT_MAX;
124
        }
125

126
        int rating = 0;
80✔
127
        for( const auto &e : g->m.field_at( p ) ) {
312✔
128
            if( who.is_dangerous_field( e.second ) ) {
76✔
129
                // @todo: Rate fire higher than smoke
130
                rating += e.second.getFieldDensity();
76✔
131
            }
132
        }
133

134
        return rating;
80✔
135
    };
24✔
136

137
    int best_rating = rate_pt( who.pos() );
24✔
138
    candidates.emplace_back( who.pos() );
24✔
139
    for( const tripoint &p : g->m.points_in_radius( who.pos(), 1 ) ) {
456✔
140
        if( p == who.pos() ) {
216✔
141
            continue;
142
        }
143

144
        int cur_rating = rate_pt( p );
192✔
145
        if( cur_rating == best_rating ) {
192✔
146
            candidates.emplace_back( p );
52✔
147
        } else if( cur_rating < best_rating ) {
140✔
148
            candidates.clear();
149
            candidates.emplace_back( p );
4✔
150
        }
151
    }
152

153
    return random_entry( candidates );
48✔
154
}
155

156
bool npc::sees_dangerous_field( const tripoint &p ) const
326✔
157
{
158
    return is_dangerous_fields( g->m.field_at( p ) );
326✔
159
}
160

161
bool npc::could_move_onto( const tripoint &p ) const
496✔
162
{
163
    if( !g->m.passable( p ) ) {
496✔
164
        return false;
165
    }
166

167
    if( !sees_dangerous_field( p ) ) {
192✔
168
        return true;
169
    }
170

171
    const auto fields_here = g->m.field_at( pos() );
192✔
172
    for( const auto &e : g->m.field_at( p ) ) {
768✔
173
        if( !is_dangerous_field( e.second ) ) {
192✔
174
            continue;
175
        }
176

177
        const auto *entry_here = fields_here.findField( e.first );
192✔
178
        if( entry_here == nullptr || entry_here->getFieldDensity() < e.second.getFieldDensity() ) {
192✔
179
            return false;
×
180
        }
181
    }
182

183
    return true;
192✔
184
}
185

186
std::vector<sphere> npc::find_dangerous_explosives() const
28✔
187
{
188
    std::vector<sphere> result;
189

190
    const auto active_items = g->m.get_active_items_in_radius( pos(), MAX_VIEW_DISTANCE );
28✔
191

192
    for( const auto &elem : active_items ) {
168✔
193
        const auto use = elem->type->get_use( "explosion" );
56✔
194

195
        if( !use ) {
56✔
196
            continue;
56✔
197
        }
198

199
        const explosion_iuse *actor = dynamic_cast<const explosion_iuse *>( use->get_actor_ptr() );
×
200
        const int safe_range = actor->explosion.safe_range();
×
201

202
        if( rl_dist( pos(), elem.position() ) >= safe_range ) {
×
203
            continue;   // Far enough.
204
        }
205

206
        const int turns_to_evacuate = 2 * safe_range / speed_rating();
×
207

208
        if( elem->charges > turns_to_evacuate ) {
×
209
            continue;   // Consider only imminent dangers.
210
        }
211

212
        result.emplace_back( elem.position(), safe_range );
×
213
    }
214

215
    return result;
28✔
216
}
217

218
// class npc functions!
219

220
float npc::evaluate_enemy( const Creature &target ) const
×
221
{
222
    if( target.is_monster() ) {
×
223
        // effective range [2..42]
224
        return std::max( dynamic_cast<const monster &>( target ).type->difficulty - 2, 0 ) / 40.0f;
×
225

226
    } else if( target.is_npc() || target.is_player() ) {
×
227
        // @todo: determine based upon visible equipment
228
        return 1.0f;
229

230
    } else {
231
        return 0.0f;
×
232
    }
233
}
234

235
void npc::assess_danger()
28✔
236
{
237
    float assessment = 0;
28✔
238
    for( const monster &critter : g->all_monsters() ) {
84✔
239
        if( sees( critter ) ) {
×
240
            assessment += critter.type->difficulty;
×
241
        }
242
    }
243
    assessment /= 10;
28✔
244
    if( assessment <= 2 ) {
28✔
245
        assessment = -10 + 5 * assessment; // Low danger if no monsters around
28✔
246
    }
247
    // Mod for the player
248
    if( is_enemy() ) {
28✔
249
        if( rl_dist( pos(), g->u.pos() ) < 10 ) {
×
250
            if( g->u.weapon.is_gun() ) {
×
251
                assessment += 10;
×
252
            } else {
253
                assessment += 10 - rl_dist( pos(), g->u.pos() );
×
254
            }
255
        }
256
    } else if( is_friend() ) {
28✔
257
        if( rl_dist( pos(), g->u.pos() ) < 8 ) {
24✔
258
            if( g->u.weapon.is_gun() ) {
20✔
259
                assessment -= 8;
×
260
            } else {
261
                assessment -= 8 - rl_dist( pos(), g->u.pos() );
20✔
262
            }
263
        }
264
    }
265
    for( int i = 0; i < num_hp_parts; i++ ) {
196✔
266
        if( i == hp_head || i == hp_torso ) {
168✔
267
            if( hp_cur[i] < hp_max[i] / 4 ) {
168✔
268
                assessment += 5;
×
269
            } else if( hp_cur[i] < hp_max[i] / 2 ) {
168✔
270
                assessment += 3;
×
271
            } else if( hp_cur[i] < hp_max[i] * .9 ) {
168✔
272
                assessment += 1;
×
273
            }
274
        } else {
275
            if( hp_cur[i] < hp_max[i] / 4 ) {
336✔
276
                assessment += 2;
×
277
            } else if( hp_cur[i] < hp_max[i] / 2 ) {
336✔
278
                assessment += 1;
×
279
            }
280
        }
281
    }
282

283
    ai_cache.danger_assessment = assessment;
28✔
284
}
28✔
285

286
float npc::character_danger( const Character &uc ) const
×
287
{
288
    // @todo: Remove this when possible
289
    const player &u = dynamic_cast<const player &>( uc );
×
290
    float ret = 0.0;
×
291
    bool u_gun = u.weapon.is_gun();
×
292
    bool my_gun = weapon.is_gun();
×
293
    double u_weap_val = u.weapon_value( u.weapon );
×
294
    const double &my_weap_val = ai_cache.my_weapon_value;
×
295
    if( u_gun && !my_gun ) {
×
296
        u_weap_val *= 1.5f;
×
297
    }
298
    ret += u_weap_val;
×
299

300
    ret += hp_percentage() * get_hp_max( hp_torso ) / 100.0 / my_weap_val;
×
301

302
    ret += my_gun ? u.get_dodge() / 2 : u.get_dodge();
×
303

304
    ret *= std::max( 0.5, u.get_speed() / 100.0 );
×
305

306
    add_msg( m_debug, "%s danger: %1f", u.disp_name().c_str(), ret );
×
307
    return ret;
×
308
}
309

310
void npc::regen_ai_cache()
28✔
311
{
312
    ai_cache.friends.clear();
28✔
313
    ai_cache.target = std::shared_ptr<Creature>();
56✔
314
    ai_cache.danger = 0.0f;
28✔
315
    ai_cache.total_danger = 0.0f;
28✔
316
    ai_cache.my_weapon_value = weapon_value( weapon );
28✔
317
    ai_cache.dangerous_explosives = find_dangerous_explosives();
56✔
318
    assess_danger();
28✔
319

320
    choose_target();
28✔
321
}
28✔
322

323
void npc::move()
28✔
324
{
325
    regen_ai_cache();
28✔
326
    npc_action action = npc_undecided;
28✔
327

328
    static const std::string no_target_str = "none";
28✔
329
    const Creature *target = current_target();
28✔
330
    const std::string &target_name = target != nullptr ? target->disp_name() : no_target_str;
28✔
331
    add_msg( m_debug, "NPC %s: target = %s, danger = %.1f, range = %d",
332
             name.c_str(), target_name.c_str(), ai_cache.danger,
28✔
333
             confident_shoot_range( weapon, recoil_total() ) );
84✔
334

335
    //faction opinion determines if it should consider you hostile
336
    if( !is_enemy() && guaranteed_hostile() && sees( g->u ) ) {
28✔
337
        add_msg( m_debug, "NPC %s turning hostile because is guaranteed_hostile()", name.c_str() );
×
338
        if( op_of_u.fear > 10 + personality.aggression + personality.bravery ) {
×
339
            set_attitude( NPCATT_FLEE );    // We don't want to take u on!
×
340
        } else {
341
            set_attitude( NPCATT_KILL );    // Yeah, we think we could take you!
×
342
        }
343
    }
344

345
    /* This bypasses the logic to determine the npc action, but this all needs to be rewritten anyway.
346
     * NPC won't avoid dangerous terrain while accompanying the player inside a vehicle
347
     * to keep them from inadvertantly getting themselves run over and/or cause vehicle related errors.
348
     */
349
    if( sees_dangerous_field( pos() ) && !in_vehicle ) {
28✔
350
        const tripoint escape_dir = good_escape_direction( *this );
24✔
351
        if( escape_dir != pos() ) {
24✔
352
            move_to( escape_dir );
20✔
353
            return;
20✔
354
        }
355
    }
356

357
    // TODO: Place player-aiding actions here, with a weight
358

359
    /* NPCs are fairly suicidal so at this point we will do a quick check to see if
360
     * something nasty is going to happen.
361
     */
362

363
    if( is_enemy() && vehicle_danger( avoidance_vehicles_radius ) > 0 ) {
8✔
364
        // TODO: Think about how this actually needs to work, for now assume flee from player
365
        ai_cache.target = g->shared_from( g->u );
×
366
    }
367

368
    if( !ai_cache.dangerous_explosives.empty() ) {
16✔
369
        action = npc_escape_explosion;
370
    } else if( target == &g->u && attitude == NPCATT_FLEE ) {
8✔
371
        action = method_of_fleeing();
×
372
    } else if( target != nullptr && ai_cache.danger > 0 ) {
8✔
373
        action = method_of_attack();
×
374
    } else {
375
        // No present danger
376
        action = address_needs();
8✔
377
        print_action( "address_needs %s", action );
8✔
378

379
        if( action == npc_undecided ) {
8✔
380
            action = address_player();
8✔
381
            print_action( "address_player %s", action );
8✔
382
        }
383
    }
384

385
    if( action == npc_undecided ) {
8✔
386
        if( is_guarding() ) {
8✔
387
            action = goal == global_omt_location() ?
×
388
                     npc_pause :
389
                     npc_goto_destination;
×
390
        } else if( has_new_items && scan_new_items() ) {
8✔
391
            return;
392
        } else if( !fetching_item ) {
2✔
393
            find_item();
2✔
394
            print_action( "find_item %s", action );
2✔
395
        }
396

397
        // check if in vehicle before rushing off to fetch things
398
        if( is_following() && g->u.in_vehicle ) {
2✔
399
            action = npc_follow_embarked;
400
        } else if( fetching_item ) {
1✔
401
            // Set to true if find_item() found something
402
            action = npc_pickup;
403
        } else if( is_following() ) {
1✔
404
            // No items, so follow the player?
405
            action = npc_follow_player;
1✔
406
        }
407

408
        if( action == npc_undecided ) {
2✔
409
            // Do our long-term action
410
            action = long_term_goal_action();
×
411
            print_action( "long_term_goal_action %s", action );
×
412
        }
413
    }
414

415
    /* Sometimes we'll be following the player at this point, but close enough that
416
     * "following" means standing still.  If that's the case, if there are any
417
     * monsters around, we should attack them after all!
418
     *
419
     * If we are following a embarked player and we are in a vehicle then shoot anyway
420
     * as we are most likely riding shotgun
421
     */
422
    if( ai_cache.danger > 0 && target != nullptr &&
4✔
423
        (
424
            ( action == npc_follow_embarked && in_vehicle ) ||
×
425
            ( action == npc_follow_player &&
×
426
              ( rl_dist( pos(), g->u.pos() ) <= follow_distance() || posz() != g->u.posz() ) )
×
427
        ) ) {
428
        action = method_of_attack();
×
429
    }
430

431
    add_msg( m_debug, "%s chose action %s.", name.c_str(), npc_action_name( action ).c_str() );
6✔
432

433
    execute_action( action );
2✔
434
}
435

436
void npc::execute_action( npc_action action )
2✔
437
{
438
    int oldmoves = moves;
2✔
439
    tripoint tar = pos();
2✔
440
    Creature *cur = current_target();
2✔
441
    if( cur != nullptr ) {
2✔
442
        tar = cur->pos();
×
443
    }
444
    /*
445
      debugmsg("%s ran execute_action() with target = %d! Action %s",
446
               name.c_str(), target, npc_action_name(action).c_str());
447
    */
448

449
    switch( action ) {
2✔
450

451
        case npc_pause:
452
            move_pause();
×
453
            break;
454

455
        case npc_reload: {
456
            do_reload( weapon );
×
457
        }
458
        break;
459

460
        case npc_sleep: {
461
            // TODO: Allow stims when not too tired
462
            // Find a nice spot to sleep
463
            int best_sleepy = sleep_spot( pos() );
×
464
            tripoint best_spot = pos();
×
465
            const auto points = closest_tripoints_first( 6, pos() );
×
466
            for( const tripoint &p : points ) {
×
467
                if( !could_move_onto( p ) || !g->is_empty( p ) ) {
×
468
                    continue;
469
                }
470

471
                // TODO: Blankets when it's cold
472
                const int sleepy = sleep_spot( p );
×
473
                if( sleepy > best_sleepy ) {
×
474
                    best_sleepy = sleepy;
×
475
                    best_spot = p;
×
476
                }
477
            }
478
            if( is_following() ) {
×
479
                complain_about( "napping", 30_minutes, _( "<warn_sleep>" ) );
×
480
            }
481
            update_path( best_spot );
×
482
            // TODO: Handle empty path better
483
            if( best_spot == pos() || path.empty() ) {
×
484
                move_pause();
×
485
                if( !has_effect( effect_lying_down ) ) {
×
486
                    add_effect( effect_lying_down, 30_minutes, num_bp, false, 1 );
×
487
                    if( g->u.sees( *this ) && !g->u.in_sleep_state() ) {
×
488
                        add_msg( _( "%s lies down to sleep." ), name.c_str() );
×
489
                    }
490
                }
491
            } else {
492
                move_to_next();
×
493
            }
494
        }
495
        break;
×
496

497
        case npc_pickup:
498
            pick_up_item();
×
499
            break;
500

501
        case npc_wield_melee:
502
            wield_best_melee();
×
503
            break;
504

505
        case npc_wield_loaded_gun: {
506
            item *it = inv.most_loaded_gun();
×
507
            if( it->is_null() ) {
×
508
                debugmsg( "NPC tried to wield a loaded gun, but has none!" );
×
509
                move_pause();
×
510
            } else {
511
                wield( *it );
×
512
            }
513
        }
514
        break;
515

516
        case npc_wield_empty_gun: {
517
            bool ammo_found = false;
×
518
            int index = -1;
×
519
            invslice slice = inv.slice();
×
520
            for( size_t i = 0; i < slice.size(); i++ ) {
×
521
                item &it = slice[i]->front();
×
522
                bool am = ( it.is_gun() &&
×
523
                            !get_ammo( it.type->gun->ammo ).empty() );
×
524
                if( it.is_gun() && ( !ammo_found || am ) ) {
×
525
                    index = i;
×
526
                    ammo_found = ( ammo_found || am );
×
527
                }
528
            }
529
            if( index == -1 ) {
×
530
                debugmsg( "NPC tried to wield a gun, but has none!" );
×
531
                move_pause();
×
532
            } else {
533
                wield( slice[index]->front() );
×
534
            }
535
        }
536
        break;
×
537

538
        case npc_heal:
539
            heal_self();
×
540
            break;
541

542
        case npc_use_painkiller:
543
            use_painkiller();
×
544
            break;
545

546
        case npc_drop_items:
547
            /*
548
              drop_items(weight_carried() - weight_capacity(),
549
                            volume_carried() - volume_capacity());
550
            */
551
            move_pause();
×
552
            break;
553

554
        case npc_flee:
555
            // TODO: More intelligent fleeing
556
            move_away_from( tar );
×
557
            break;
558

559
        case npc_reach_attack:
560
            if( weapon.reach_range( *this ) >= rl_dist( pos(), tar ) &&
×
561
                clear_shot_reach( pos(), tar ) ) {
×
562
                reach_attack( tar );
×
563
                break;
564
            }
565
        /* fallthrough */
566
        case npc_melee:
567
            update_path( tar );
×
568
            if( path.size() > 1 ) {
×
569
                move_to_next();
×
570
            } else if( path.size() == 1 ) {
×
571
                if( cur != nullptr ) {
×
572
                    melee_attack( *cur, true );
×
573
                }
574
            } else {
575
                look_for_player( g->u );
×
576
            }
577
            break;
578

579
        case npc_aim:
580
            aim();
×
581
            break;
582

583
        case npc_shoot: {
584
            auto mode = weapon.gun_current_mode();
×
585
            if( !mode ) {
×
586
                debugmsg( "NPC tried to shoot without valid mode" );
×
587
                break;
588
            }
589
            aim();
×
590
            fire_gun( tar, mode.qty, *mode );
×
591
            break;
×
592
        }
593

594
        case npc_look_for_player:
595
            if( saw_player_recently() && last_player_seen_pos && sees( *last_player_seen_pos ) ) {
×
596
                update_path( *last_player_seen_pos );
×
597
                move_to_next();
×
598
            } else {
599
                look_for_player( g->u );
×
600
            }
601
            break;
602

603
        case npc_heal_player:
604
            update_path( g->u.pos() );
×
605
            if( path.size() == 1 ) { // We're adjacent to u, and thus can heal u
×
606
                heal_player( g->u );
×
607
            } else if( !path.empty() ) {
×
608
                move_to_next();
×
609
            } else {
610
                move_pause();
×
611
            }
612
            break;
613

614
        case npc_follow_player:
615
            update_path( g->u.pos() );
1✔
616
            if( static_cast<int>( path.size() ) <= follow_distance() &&
3✔
617
                g->u.posz() == posz() ) { // We're close enough to u.
1✔
618
                move_pause();
1✔
619
            } else if( !path.empty() ) {
×
620
                move_to_next();
×
621
            } else {
622
                move_pause();
×
623
            }
624
            // TODO: Make it only happen when it's safe
625
            complain();
1✔
626
            break;
627

628
        case npc_follow_embarked: {
629
            const optional_vpart_position vp = g->m.veh_at( g->u.pos() );
1✔
630

631
            if( !vp ) {
1✔
632
                debugmsg( "Following an embarked player with no vehicle at their location?" );
×
633
                // TODO: change to wait? - for now pause
634
                move_pause();
×
635
                break;
636
            }
637
            vehicle *const veh = &vp->vehicle();
2✔
638

639
            // Try to find the last destination
640
            // This is mount point, not actual position
641
            point last_dest( INT_MIN, INT_MIN );
642
            if( !path.empty() && veh_pointer_or_null( g->m.veh_at( path[path.size() - 1] ) ) == veh ) {
2✔
643
                last_dest = vp->mount();
×
644
            }
645

646
            // Prioritize last found path, then seats
647
            // Don't change spots if ours is nice
648
            int my_spot = -1;
1✔
649
            std::vector<std::pair<int, int> > seats;
650
            for( const vpart_reference &vp : veh->get_avail_parts( VPFLAG_BOARDABLE ) ) {
3✔
651
                const player *passenger = veh->get_passenger( vp.part_index() );
1✔
652
                if( passenger != this && passenger != nullptr ) {
1✔
653
                    continue;
1✔
654
                }
655

656
                // a seat is available if either unassigned or assigned to us
657
                auto available_seat = [&]( const vehicle_part & pt ) {
×
658
                    if( !pt.is_seat() ) {
×
659
                        return false;
660
                    }
661
                    const npc *who = pt.crew();
×
662
                    return !who || who->getID() == getID();
×
663
                };
664

665
                const vehicle_part &pt = vp.part();
×
666

667
                int priority = 0;
×
668

669
                if( vp.mount() == last_dest ) {
×
670
                    // Shares mount point with last known path
671
                    // We probably wanted to go there in the last turn
672
                    priority = 4;
673

674
                } else if( available_seat( pt ) ) {
×
675
                    // Assuming player "owns" a sensible vehicle seats should be in good spots to occupy
676
                    // Prefer our assigned seat if we have one
677
                    const npc *who = pt.crew();
×
678
                    priority = who && who->getID() == getID() ? 3 : 2;
×
679

680
                } else if( vp.is_inside() ) {
×
681
                    priority = 1;
×
682
                }
683

684
                if( passenger == this ) {
×
685
                    my_spot = priority;
×
686
                }
687

688
                seats.push_back( std::make_pair( priority, static_cast<int>( vp.part_index() ) ) );
×
689
            }
690

691
            if( my_spot >= 3 ) {
1✔
692
                // We won't get any better, so don't try
693
                move_pause();
×
694
                break;
695
            }
696

697
            std::sort( seats.begin(), seats.end(),
698
            []( const std::pair<int, int> &l, const std::pair<int, int> &r ) {
699
                return l.first > r.first;
700
            } );
1✔
701

702
            if( seats.empty() ) {
1✔
703
                // TODO: be angry at player, switch to wait or leave - for now pause
704
                move_pause();
1✔
705
                break;
706
            }
707

708
            // Only check few best seats - pathfinding can get expensive
709
            const size_t try_max = std::min<size_t>( 4, seats.size() );
×
710
            for( size_t i = 0; i < try_max; i++ ) {
×
711
                if( seats[i].first <= my_spot ) {
×
712
                    // We have a nicer spot than this
713
                    // Note: this will make NPCs steal player's seat...
714
                    break;
715
                }
716

717
                const int cur_part = seats[i].second;
×
718

719
                tripoint pp = veh->global_part_pos3( cur_part );
×
720
                update_path( pp, true );
×
721
                if( !path.empty() ) {
×
722
                    // All is fine
723
                    move_to_next();
×
724
                    break;
725
                }
726
            }
727

728
            // TODO: Check the rest
729
            move_pause();
×
730
        }
731

732
        break;
×
733
        case npc_talk_to_player:
734
            talk_to_u();
×
735
            moves = 0;
×
736
            break;
×
737

738
        case npc_mug_player:
739
            mug_player( g->u );
×
740
            break;
741

742
        case npc_goto_destination:
743
            go_to_destination();
×
744
            break;
745

746
        case npc_avoid_friendly_fire:
747
            avoid_friendly_fire();
×
748
            break;
749

750
        case npc_escape_explosion:
751
            escape_explosion();
×
752
            break;
753

754
        case npc_base_idle:
755
            // TODO: patrol or sleep or something?
756
            move_pause();
×
757
            break;
758

759
        case npc_undecided:
760
            complain();
×
761
            move_pause();
×
762
            break;
763

764
        case npc_noop:
765
            add_msg( m_debug, "%s skips turn (noop)", disp_name().c_str() );
×
766
            return;
2✔
767

768
        default:
769
            debugmsg( "Unknown NPC action (%d)", action );
×
770
    }
771

772
    if( oldmoves == moves ) {
2✔
773
        add_msg( m_debug, "NPC didn't use its moves.  Action %s (%d).",
774
                 npc_action_name( action ).c_str(), action );
×
775
    }
776
}
777

778
void npc::choose_target()
28✔
779
{
780
    ai_cache.total_danger = 0.0f;
28✔
781

782
    float highest_priority = 1.0f;
28✔
783

784
    // Radius we can attack without moving
785
    const int max_range = std::max( weapon.reach_range( *this ),
28✔
786
                                    confident_shoot_range( weapon, get_most_accurate_sight( weapon ) ) );
84✔
787

788
    constexpr static int def_radius = 6;
789

790
    const auto ok_by_rules = [max_range, this]( const Creature & c, int dist, int scaled_dist ) {
×
791
        if( !is_following() ) {
×
792
            return true;
793
        }
794

795
        switch( rules.engagement ) {
×
796
            case ENGAGE_NONE:
797
                return false;
798
            case ENGAGE_CLOSE:
799
                // Either close to player or close enough that we can reach it and close to us
800
                return rl_dist( c.pos(), g->u.pos() ) <= def_radius ||
×
801
                       ( dist <= max_range && scaled_dist <= def_radius / 2 );
×
802
            case ENGAGE_WEAK:
803
                return c.get_hp() <= average_damage_dealt();
×
804
            case ENGAGE_HIT:
805
                return c.has_effect( effect_hit_by_player );
×
806
            case ENGAGE_NO_MOVE:
807
                return dist <= max_range;
×
808
            case ENGAGE_ALL:
809
                return true;
×
810
        }
811

812
        return true;
×
813
    };
28✔
814

815
    for( monster &mon : g->all_monsters() ) {
84✔
816
        if( !sees( mon ) ) {
×
817
            continue;
818
        }
819

820
        int dist = rl_dist( pos(), mon.pos() );
×
821
        // @todo: This should include ranged attacks in calculation
822
        float scaled_distance = std::max( 1.0f, dist / mon.speed_rating() );
×
823
        float hp_percent = static_cast<float>( mon.get_hp_max() - mon.get_hp() ) / mon.get_hp_max();
×
824
        float critter_danger = mon.type->difficulty * ( hp_percent / 2.0f + 0.5f );
×
825

826
        auto att = mon.attitude( this );
×
827
        if( att == MATT_FRIEND ) {
×
828
            ai_cache.friends.emplace_back( g->shared_from( mon ) );
×
829
            continue;
×
830
        }
831

832
        if( att == MATT_FPASSIVE ) {
×
833
            continue;
834
        }
835

836
        if( att == MATT_ATTACK ) {
×
837
            critter_danger++;
×
838
        }
839

840
        ai_cache.total_danger += critter_danger / scaled_distance;
×
841

842
        if( !ok_by_rules( mon, dist, scaled_distance ) ) {
×
843
            continue;
844
        }
845

846
        float priority = critter_danger - 2.0f * ( scaled_distance - 1.0f );
×
847
        if( priority < 1.0f && is_following() && att == MATT_ATTACK &&
×
848
            rl_dist( mon.pos(), g->u.pos() ) <= def_radius ) {
×
849
            priority = 1.0f;
×
850
        }
851

852
        if( priority >= highest_priority ) {
×
853
            highest_priority = priority;
×
854
            ai_cache.target = g->shared_from( mon );
×
855
            ai_cache.danger = critter_danger;
×
856
        }
857
    }
858

859
    const auto check_hostile_character = [this, &ok_by_rules,
860
          &highest_priority]( const Character & c ) {
×
861
        float critter_danger = character_danger( c );
×
862

863
        int dist = rl_dist( pos(), c.pos() );
×
864
        int scaled_distance = std::max( 1, ( 100 * dist ) / c.get_speed() );
×
865

866
        ai_cache.total_danger += critter_danger / scaled_distance;
×
867

868
        if( !ok_by_rules( c, dist, scaled_distance ) ) {
×
869
            return false;
870
        }
871

872
        float priority = critter_danger - 2 * ( scaled_distance - 1 );
×
873

874
        if( priority < 1.0f && is_following() && rl_dist( c.pos(), g->u.pos() ) <= def_radius ) {
×
875
            priority = 1.0f;
×
876
        }
877

878
        if( priority > highest_priority ) {
×
879
            highest_priority = priority;
×
880
            ai_cache.danger = critter_danger;
×
881
            return true;
×
882
        }
883

884
        return false;
885
    };
28✔
886

887
    for( const npc &np : g->all_npcs() ) {
1,344✔
888
        if( &np == this ) {
420✔
889
            continue;
890
        }
891

892
        auto att = attitude_to( np );
392✔
893
        if( att == Creature::A_FRIENDLY ) {
392✔
894
            ai_cache.friends.emplace_back( g->shared_from( np ) );
528✔
895
        } else if( att == Creature::A_NEUTRAL ) {
128✔
896
            // Nothing
897
        } else if( sees( np ) && check_hostile_character( np ) ) {
24✔
898
            ai_cache.target = g->shared_from( np );
×
899
        }
900
    }
901

902
    if( is_friend() ) {
28✔
903
        ai_cache.friends.emplace_back( g->shared_from( g->u ) );
48✔
904
    } else if( is_enemy() ) {
4✔
905
        if( sees( g->u ) && check_hostile_character( g->u ) ) {
×
906
            ai_cache.target = g->shared_from( g->u );
×
907
            ai_cache.danger = std::max( 1.0f, ai_cache.danger );
×
908
        }
909
    }
910
}
28✔
911

912
npc_action npc::method_of_fleeing()
×
913
{
914
    const Creature *target = current_target();
×
915
    if( target == nullptr ) {
×
916
        // Shouldn't be called
917
        debugmsg( "Ran npc::method_of_fleeing without a target!" );
×
918
        return npc_pause;
×
919
    }
920
    const float enemy_speed = target->speed_rating();
×
921
    const tripoint &enemy_loc = target->pos();
×
922
    int distance = rl_dist( pos(), enemy_loc );
×
923

924
    if( distance < 2 && enemy_speed > speed_rating() ) {
×
925
        // Can't outrun, so attack
926
        return method_of_attack();
×
927
    }
928

929
    return npc_flee;
930
}
931

932
npc_action npc::method_of_attack()
×
933
{
934
    Creature *critter = current_target();
×
935
    if( critter == nullptr ) {
×
936
        // This function shouldn't be called...
937
        debugmsg( "Ran npc::method_of_attack without a target!" );
×
938
        return npc_pause;
939
    }
940

941
    tripoint tar = critter->pos();
×
942
    int dist = rl_dist( pos(), tar );
×
943
    double danger = evaluate_enemy( *critter );
×
944

945
    // TODO: Change the in_vehicle check to actual "are we driving" check
946
    const bool dont_move = in_vehicle || rules.engagement == ENGAGE_NO_MOVE;
×
947

948
    long ups_charges = charges_of( "UPS" );
×
949

950
    // get any suitable modes excluding melee, any forbidden to NPCs and those without ammo
951
    // if we require a silent weapon inappropriate modes are also removed
952
    // except in emergency only fire bursts if danger > 0.5 and don't shoot at all at harmless targets
953
    std::vector<std::pair<gun_mode_id, gun_mode>> modes;
954
    if( rules.use_guns || !is_following() ) {
×
955
        for( const auto &e : weapon.gun_all_modes() ) {
×
956
            modes.push_back( e );
×
957
        }
958

959
        modes.erase( std::remove_if( modes.begin(), modes.end(),
960
        [&]( const std::pair<gun_mode_id, gun_mode> &e ) {
×
961

962
            const auto &m = e.second;
×
963
            return m.melee() || m.flags.count( "NPC_AVOID" ) ||
×
964
                   !m->ammo_sufficient( m.qty ) || !can_use( *m.target ) ||
×
965
                   m->get_gun_ups_drain() > ups_charges ||
×
966
                   ( danger <= ( ( m.qty == 1 ) ? 0.0 : 0.5 ) && !emergency() ) ||
×
967
                   ( rules.use_silent && is_following() && !m.target->is_silent() );
×
968

969
        } ), modes.end() );
×
970
    }
971

972
    // prefer modes that result in more total damage
973
    std::stable_sort( modes.begin(),
974
                      modes.end(), [&]( const std::pair<gun_mode_id, gun_mode> &lhs,
975
    const std::pair<gun_mode_id, gun_mode> &rhs ) {
×
976
        return ( lhs.second->gun_damage().total_damage() * lhs.second.qty ) >
×
977
               ( rhs.second->gun_damage().total_damage() * rhs.second.qty );
×
978
    } );
×
979

980
    const int cur_recoil = recoil_total();
×
981
    // modes outside confident range should always be the last option(s)
982
    std::stable_sort( modes.begin(),
983
                      modes.end(), [&]( const std::pair<gun_mode_id, gun_mode> &lhs,
984
    const std::pair<gun_mode_id, gun_mode> &rhs ) {
×
985
        return ( confident_gun_mode_range( lhs.second, cur_recoil ) >= dist ) >
×
986
               ( confident_gun_mode_range( rhs.second, cur_recoil ) >= dist );
×
987
    } );
×
988

989
    if( emergency() && alt_attack() ) {
×
990
        return npc_noop;
991
    }
992

993
    // reach attacks are silent and consume no ammo so prefer these if available
994
    int reach_range = weapon.reach_range( *this );
×
995
    if( reach_range > 1 && reach_range >= dist && clear_shot_reach( pos(), tar ) ) {
×
996
        return npc_reach_attack;
997
    }
998

999
    // if the best mode is within the confident range try for a shot
1000
    if( !modes.empty() && sees( *critter ) &&
×
1001
        confident_gun_mode_range( modes[ 0 ].second, cur_recoil ) >= dist ) {
×
1002

1003
        // @todo: Make NPCs understand reinforced glass and vehicles blocking line of fire
1004

1005
        if( wont_hit_friend( tar, weapon, false ) ) {
×
1006
            weapon.gun_set_mode( modes[ 0 ].first );
×
1007
            return npc_shoot;
1008

1009
        } else {
1010
            if( !dont_move ) {
×
1011
                return npc_avoid_friendly_fire;
1012
            }
1013
        }
1014
    }
1015

1016
    if( dist == 1 ) {
×
1017
        return npc_melee;
1018
    }
1019

1020
    // TODO: Add a time check now that wielding takes a lot of time
1021
    if( wield_better_weapon() ) {
×
1022
        return npc_noop;
1023
    }
1024

1025
    if( !weapon.ammo_sufficient() && can_reload_current() ) {
×
1026
        return npc_reload;
1027
    }
1028

1029
    // @todo Needs a check for transparent but non-passable tiles on the way
1030
    if( !modes.empty() && sees( *critter ) &&
×
1031
        aim_per_move( weapon, recoil ) > 0 &&
×
1032
        confident_shoot_range( weapon, get_most_accurate_sight( weapon ) ) >= dist ) {
×
1033
        return npc_aim;
1034
    }
1035

1036
    return dont_move ? npc_undecided : npc_melee;
×
1037
}
1038

1039
bool need_heal( const Character &n )
8✔
1040
{
1041
    for( int i = 0; i < num_hp_parts; i++ ) {
56✔
1042
        hp_part part = hp_part( i );
48✔
1043
        if( ( part == hp_head  && n.hp_cur[i] <= 35 ) ||
64✔
1044
            ( part == hp_torso && n.hp_cur[i] <= 25 ) ||
112✔
1045
            n.hp_cur[i] <= 15 ) {
96✔
1046
            return true;
1047
        }
1048
    }
1049

1050
    return false;
1051
}
1052

1053
npc_action npc::address_needs()
8✔
1054
{
1055
    return address_needs( ai_cache.danger );
8✔
1056
}
1057

1058
bool wants_to_reload( const npc &who, const item &it )
104✔
1059
{
1060
    if( !who.can_reload( it ) ) {
104✔
1061
        return false;
1062
    }
1063

1064
    const long required = it.ammo_required();
2✔
1065
    // TODO: Add bandolier check here, once they can be reloaded
1066
    if( required < 1 && !it.is_magazine() ) {
2✔
1067
        return false;
1068
    }
1069

1070
    const long remaining = it.ammo_remaining();
2✔
1071
    return remaining < required || remaining < it.ammo_capacity();
2✔
1072
}
1073

1074
bool wants_to_reload_with( const item &weap, const item &ammo )
×
1075
{
1076
    return !ammo.is_magazine() || ammo.ammo_remaining() > weap.ammo_remaining();
×
1077
}
1078

1079
item &npc::find_reloadable()
8✔
1080
{
1081
    // Check wielded gun, non-wielded guns, mags and tools
1082
    // TODO: Build a proper gun->mag->ammo DAG (Directed Acyclic Graph)
1083
    // to avoid checking same properties over and over
1084
    // TODO: Make this understand bandoliers, pouches etc.
1085
    // TODO: Cache items checked for reloading to avoid re-checking same items every turn
1086
    // TODO: Make it understand smaller and bigger magazines
1087
    item *reloadable = nullptr;
8✔
1088
    visit_items( [this, &reloadable]( item * node ) {
104✔
1089
        if( !wants_to_reload( *this, *node ) ) {
104✔
1090
            return VisitResponse::NEXT;
1091
        }
1092
        const auto it_loc = select_ammo( *node ).ammo;
4✔
1093
        if( it_loc && wants_to_reload_with( *node, *it_loc ) ) {
2✔
1094
            reloadable = node;
×
1095
            return VisitResponse::ABORT;
×
1096
        }
1097

1098
        return VisitResponse::NEXT;
1099
    } );
18✔
1100

1101
    if( reloadable != nullptr ) {
8✔
1102
        return *reloadable;
1103
    }
1104

1105
    return null_item_reference();
8✔
1106
}
1107

1108
const item &npc::find_reloadable() const
×
1109
{
1110
    return const_cast<const item &>( const_cast<npc *>( this )->find_reloadable() );
×
1111
}
1112

1113
bool npc::can_reload_current()
8✔
1114
{
1115
    if( !weapon.is_gun() ) {
8✔
1116
        return false;
1117
    }
1118

1119
    return find_usable_ammo( weapon );
4✔
1120
}
1121

1122
item_location npc::find_usable_ammo( const item &weap )
4✔
1123
{
1124
    if( !can_reload( weap ) ) {
4✔
1125
        return item_location();
4✔
1126
    }
1127

1128
    auto loc = select_ammo( weap ).ammo;
×
1129
    if( !loc || !wants_to_reload_with( weap, *loc ) ) {
×
1130
        return item_location();
×
1131
    }
1132

1133
    return loc;
×
1134
}
1135

1136
const item_location npc::find_usable_ammo( const item &weap ) const
×
1137
{
1138
    return const_cast<npc *>( this )->find_usable_ammo( weap );
×
1139
}
1140

1141
npc_action npc::address_needs( float danger )
8✔
1142
{
1143
    if( need_heal( *this ) && has_healing_item() ) {
8✔
1144
        return npc_heal;
1145
    }
1146

1147
    if( get_perceived_pain() >= 15 && has_painkiller() && !took_painkiller() ) {
8✔
1148
        return npc_use_painkiller;
1149
    }
1150

1151
    if( can_reload_current() ) {
8✔
1152
        return npc_reload;
1153
    }
1154

1155
    item &reloadable = find_reloadable();
8✔
1156
    if( !reloadable.is_null() ) {
8✔
1157
        do_reload( reloadable );
×
1158
        return npc_noop;
1159
    }
1160

1161
    if( ( danger <= NPC_DANGER_VERY_LOW && ( get_hunger() > 40 || get_thirst() > 40 ) ) ||
32✔
1162
        get_thirst() > 80 || get_hunger() > 160 ) {
24✔
1163
        if( consume_food() ) {
×
1164
            return npc_noop;
1165
        }
1166
    }
1167

1168
    if( danger <= NPC_DANGER_VERY_LOW && find_corpse_to_pulp() ) {
8✔
1169
        if( !do_pulp() ) {
×
1170
            move_to_next();
×
1171
        }
1172

1173
        return npc_noop;
1174
    }
1175

1176
    if( danger <= NPC_DANGER_VERY_LOW && adjust_worn() ) {
8✔
1177
        return npc_noop;
1178
    }
1179

1180
    const auto could_sleep = [&]() {
8✔
1181
        if( danger <= 0.01 ) {
8✔
1182
            if( get_fatigue() >= TIRED ) {
8✔
1183
                return true;
1184
            } else if( is_following() && g->u.in_sleep_state() && get_fatigue() > ( TIRED / 2 ) ) {
8✔
1185
                return true;
1186
            }
1187
        }
1188
        return false;
1189
    };
8✔
1190
    // TODO: More risky attempts at sleep when exhausted
1191
    if( could_sleep() ) {
8✔
1192
        if( !is_following() ) {
×
1193
            set_fatigue( 0 ); // TODO: Make tired NPCs handle sleep offscreen
×
1194
            return npc_undecided;
1195
        }
1196

1197
        if( rules.allow_sleep || get_fatigue() > MASSIVE_FATIGUE ) {
×
1198
            return npc_sleep;
1199
        } else if( g->u.in_sleep_state() ) {
×
1200
            // TODO: "Guard me while I sleep" command
1201
            return npc_sleep;
1202
        }
1203
    }
1204

1205
    // TODO: Mutation & trait related needs
1206
    // e.g. finding glasses; getting out of sunlight if we're an albino; etc.
1207

1208
    return npc_undecided;
1209
}
1210

1211
npc_action npc::address_player()
8✔
1212
{
1213
    if( attitude == NPCATT_TALK && sees( g->u ) ) {
8✔
1214
        if( g->u.in_sleep_state() ) {
×
1215
            // Leave sleeping characters alone.
1216
            return npc_undecided;
1217
        }
1218
        if( rl_dist( pos(), g->u.pos() ) <= 6 ) {
×
1219
            return npc_talk_to_player;    // Close enough to talk to you
1220
        } else {
1221
            if( one_in( 10 ) ) {
×
1222
                say( "<lets_talk>" );
×
1223
            }
1224
            return npc_follow_player;
1225
        }
1226
    }
1227

1228
    if( attitude == NPCATT_MUG && sees( g->u ) ) {
8✔
1229
        if( one_in( 3 ) ) {
×
1230
            say( _( "Don't move a <swear> muscle..." ) );
×
1231
        }
1232
        return npc_mug_player;
1233
    }
1234

1235
    if( attitude == NPCATT_WAIT_FOR_LEAVE ) {
8✔
1236
        patience--;
×
1237
        if( patience <= 0 ) {
×
1238
            patience = 0;
×
1239
            set_attitude( NPCATT_KILL );
×
1240
            return npc_noop;
×
1241
        }
1242
        return npc_undecided;
1243
    }
1244

1245
    if( attitude == NPCATT_FLEE ) {
8✔
1246
        return npc_flee;
1247
    }
1248

1249
    if( attitude == NPCATT_LEAD ) {
8✔
1250
        if( rl_dist( pos(), g->u.pos() ) >= 12 || !sees( g->u ) ) {
×
1251
            int intense = get_effect_int( effect_catch_up );
×
1252
            if( intense < 10 ) {
×
1253
                say( "<keep_up>" );
×
1254
                add_effect( effect_catch_up, 5_turns );
×
1255
                return npc_pause;
×
1256
            } else {
1257
                say( "<im_leaving_you>" );
×
1258
                set_attitude( NPCATT_NULL );
×
1259
                return npc_pause;
×
1260
            }
1261
        } else if( has_destination() ) {
×
1262
            return npc_goto_destination;
1263
        } else { // At goal. Now, waiting on nearby player
1264
            return npc_pause;
×
1265
        }
1266
    }
1267
    return npc_undecided;
1268
}
1269

1270
npc_action npc::long_term_goal_action()
×
1271
{
1272
    add_msg( m_debug, "long_term_goal_action()" );
×
1273

1274
    if( mission == NPC_MISSION_SHOPKEEP || mission == NPC_MISSION_SHELTER ) {
×
1275
        return npc_pause;    // Shopkeepers just stay put.
1276
    }
1277

1278
    // TODO: Follow / look for player
1279

1280
    if( mission == NPC_MISSION_BASE ) {
×
1281
        return npc_base_idle;
1282
    }
1283

1284
    if( !has_destination() ) {
×
1285
        set_destination();
×
1286
    }
1287

1288
    if( has_destination() ) {
×
1289
        return npc_goto_destination;
1290
    }
1291

1292
    return npc_undecided;
×
1293
}
1294

1295
double npc::confidence_mult() const
28✔
1296
{
1297
    if( !is_following() ) {
28✔
1298
        return 1.0f;
1299
    }
1300

1301
    switch( rules.aim ) {
24✔
1302
        case AIM_WHEN_CONVENIENT:
1303
            return emergency() ? 1.5f : 1.0f;
24✔
1304
        case AIM_SPRAY:
1305
            return 2.0f;
1306
        case AIM_PRECISE:
1307
            return emergency() ? 1.0f : 0.75f;
×
1308
        case AIM_STRICTLY_PRECISE:
1309
            return 0.5f;
×
1310
    }
1311

1312
    return 1.0f;
×
1313
}
1314

1315
int npc::confident_shoot_range( const item &it, int recoil ) const
56✔
1316
{
1317
    int res = 0;
56✔
1318
    for( const auto &m : it.gun_all_modes() ) {
280✔
1319
        res = std::max( res, confident_gun_mode_range( m.second, recoil ) );
56✔
1320
    }
1321
    return res;
56✔
1322
}
1323

1324
int npc::confident_gun_mode_range( const gun_mode &gun, int at_recoil ) const
28✔
1325
{
1326
    if( !gun || gun.melee() ) {
28✔
1327
        return 0;
1328
    }
1329

1330
    // Same calculation as in @ref item::info
1331
    // @todo Extract into common method
1332
    double max_dispersion = get_weapon_dispersion( *( gun.target ) ).max() + at_recoil;
28✔
1333
    double even_chance_range = range_with_even_chance_of_good_hit( max_dispersion );
28✔
1334
    double confident_range = even_chance_range * confidence_mult();
28✔
1335

1336
    add_msg( m_debug, "confident_gun (%s<=%.2f) at %.1f", gun.name(), confident_range,
1337
             max_dispersion );
28✔
1338
    return std::max<int>( confident_range, 1 );
56✔
1339
}
1340

1341
int npc::confident_throw_range( const item &thrown, Creature *target ) const
×
1342
{
1343
    double average_dispersion = throwing_dispersion( thrown, target ) / 2.0;
×
1344
    double even_chance_range = ( target == nullptr ? 0.5 : target->ranged_target_size() ) /
×
1345
                               average_dispersion;
×
1346
    double confident_range = even_chance_range * confidence_mult();
×
1347
    add_msg( m_debug, "confident_throw_range == %d", static_cast<int>( confident_range ) );
×
1348
    return static_cast<int>( confident_range );
×
1349
}
1350

1351
// Index defaults to -1, i.e., wielded weapon
1352
bool npc::wont_hit_friend( const tripoint &tar, const item &it, bool throwing ) const
×
1353
{
1354
    // @todo: Get actual dispersion instead of extracting it (badly) from confident range
1355
    int confident = throwing ?
1356
                    confident_throw_range( it, nullptr ) :
1357
                    confident_shoot_range( it, recoil_total() );
×
1358
    // if there is no confidence at using weapon, it's not used at range
1359
    // zero confidence leads to divide by zero otherwise
1360
    if( confident < 1 ) {
×
1361
        return true;
1362
    }
1363

1364
    if( rl_dist( pos(), tar ) == 1 ) {
×
1365
        return true;    // If we're *really* sure that our aim is dead-on
1366
    }
1367

1368
    int target_angle = g->m.coord_to_angle( posx(), posy(), tar.x, tar.y );
×
1369

1370
    // @todo: Base on dispersion
1371
    int safe_angle = 30;
×
1372

1373
    for( const auto &fr : ai_cache.friends ) {
×
1374
        const Creature &ally = *fr.get();
×
1375

1376
        // @todo: Extract common functions with turret target selection
1377
        int safe_angle_ally = safe_angle;
×
1378
        int ally_dist = rl_dist( pos(), ally.pos() );
×
1379
        if( ally_dist < 3 ) {
×
1380
            safe_angle_ally += ( 3 - ally_dist ) * 30;
×
1381
        }
1382

1383
        int ally_angle = g->m.coord_to_angle( posx(), posy(), ally.posx(), ally.posy() );
×
1384
        int angle_diff = abs( ally_angle - target_angle );
×
1385
        angle_diff = std::min( 360 - angle_diff, angle_diff );
×
1386
        if( angle_diff < safe_angle_ally ) {
×
1387
            // @todo: Disable NPC whining is it's other NPC who prevents aiming
1388
            return false;
×
1389
        }
1390
    }
1391

1392
    return true;
1393
}
1394

1395
bool npc::enough_time_to_reload( const item &gun ) const
×
1396
{
1397
    int rltime = item_reload_cost( gun, item( gun.ammo_type()->default_ammotype() ),
×
1398
                                   gun.ammo_capacity() );
×
1399
    const float turns_til_reloaded = static_cast<float>( rltime ) / get_speed();
×
1400

1401
    const Creature *target = current_target();
×
1402
    if( target == nullptr ) {
×
1403
        // No target, plenty of time to reload
1404
        return true;
1405
    }
1406

1407
    const auto distance = rl_dist( pos(), target->pos() );
×
1408
    const float target_speed = target->speed_rating();
×
1409
    const float turns_til_reached = distance / target_speed;
×
1410
    if( target->is_player() || target->is_npc() ) {
×
1411
        auto &c = dynamic_cast<const Character &>( *target );
×
1412
        // TODO: Allow reloading if the player has a low accuracy gun
1413
        if( sees( c ) && c.weapon.is_gun() && rltime > 200 &&
×
1414
            c.weapon.gun_range( true ) > distance + turns_til_reloaded / target_speed ) {
×
1415
            // Don't take longer than 2 turns if player has a gun
1416
            return false;
1417
        }
1418
    }
1419

1420
    // TODO: Handle monsters with ranged attacks and players with CBMs
1421
    return turns_til_reloaded < turns_til_reached;
×
1422
}
1423

1424
void npc::aim()
88✔
1425
{
1426
    double aim_amount = aim_per_move( weapon, recoil );
88✔
1427
    while( aim_amount > 0 && recoil > 0 && moves > 0 ) {
6,389✔
1428
        moves--;
6,213✔
1429
        recoil -= aim_amount;
6,213✔
1430
        recoil = std::max( 0.0, recoil );
12,426✔
1431
        aim_amount = aim_per_move( weapon, recoil );
6,213✔
1432
    }
1433
}
88✔
1434

1435
bool npc::update_path( const tripoint &p, const bool no_bashing, bool force )
1✔
1436
{
1437
    if( p == pos() ) {
1✔
1438
        path.clear();
×
1439
        return true;
×
1440
    }
1441

1442
    while( !path.empty() && path[0] == pos() ) {
2✔
1443
        path.erase( path.begin() );
×
1444
    }
1445

1446
    if( !path.empty() ) {
2✔
1447
        const tripoint &last = path[path.size() - 1];
×
1448
        if( last == p && ( path[0].z != posz() || rl_dist( path[0], pos() ) <= 1 ) ) {
×
1449
            // Our path already leads to that point, no need to recalculate
1450
            return true;
1451
        }
1452
    }
1453

1454
    auto new_path = g->m.route( pos(), p, get_pathfinding_settings( no_bashing ), get_path_avoid() );
2✔
1455
    if( new_path.empty() ) {
1✔
1456
        add_msg( m_debug, "Failed to path %d,%d,%d->%d,%d,%d",
1457
                 posx(), posy(), posz(), p.x, p.y, p.z );
1✔
1458
    }
1459

1460
    while( !new_path.empty() && new_path[0] == pos() ) {
1✔
1461
        new_path.erase( new_path.begin() );
×
1462
    }
1463

1464
    if( !new_path.empty() || force ) {
1✔
1465
        path = std::move( new_path );
1✔
1466
        return true;
1✔
1467
    }
1468

1469
    return false;
1470
}
1471

1472
bool npc::can_move_to( const tripoint &p, bool no_bashing ) const
462✔
1473
{
1474
    // Allow moving into any bashable spots, but penalize them during pathing
1475
    return( rl_dist( pos(), p ) <= 1 &&
924✔
1476
            (
1477
                g->m.passable( p ) ||
828✔
1478
                ( !no_bashing && g->m.bash_rating( smash_ability(), p ) > 0 ) ||
366✔
1479
                g->m.open_door( p, !g->m.is_outside( pos() ), true )
366✔
1480
            )
1481
          );
462✔
1482
}
1483

1484
void npc::move_to( const tripoint &pt, bool no_bashing, std::set<tripoint> *nomove )
106✔
1485
{
1486
    tripoint p = pt;
106✔
1487
    if( sees_dangerous_field( p )
212✔
1488
        || ( nomove != nullptr && nomove->find( p ) != nomove->end() ) ) {
106✔
1489
        // Move to a neighbor field instead, if possible.
1490
        // Maybe this code already exists somewhere?
1491
        auto other_points = g->m.get_dir_circle( pos(), p );
102✔
1492
        for( const tripoint &ot : other_points ) {
818✔
1493
            if( could_move_onto( ot )
992✔
1494
                && ( nomove == nullptr || nomove->find( ot ) == nomove->end() ) ) {
848✔
1495

1496
                p = ot;
86✔
1497
                break;
86✔
1498
            }
1499
        }
1500
    }
1501

1502
    recoil = MAX_RECOIL;
106✔
1503

1504
    if( has_effect( effect_stunned ) ) {
106✔
1505
        p.x = rng( posx() - 1, posx() + 1 );
×
1506
        p.y = rng( posy() - 1, posy() + 1 );
×
1507
        p.z = posz();
×
1508
    }
1509

1510
    // nomove is used to resolve recursive invocation, so reset destination no
1511
    // matter it was changed by stunned effect or not.
1512
    if( nomove != nullptr && nomove->find( p ) != nomove->end() ) {
278✔
1513
        p = pos();
×
1514
    }
1515

1516
    // "Long steps" are allowed when crossing z-levels
1517
    // Stairs teleport the player too
1518
    if( rl_dist( pos(), p ) > 1 && p.z == posz() ) {
106✔
1519
        // On the same level? Not so much. Something weird happened
1520
        path.clear();
×
1521
        move_pause();
×
1522
    }
1523
    bool attacking = false;
106✔
1524
    if( g->critter_at<monster>( p ) ) {
106✔
1525
        attacking = true;
×
1526
    }
1527
    if( !move_effects( attacking ) ) {
106✔
1528
        mod_moves( -100 );
×
1529
        return;
102✔
1530
    }
1531

1532
    Creature *critter = g->critter_at( p );
106✔
1533
    if( critter != nullptr ) {
106✔
1534
        if( critter == this ) { // We're just pausing!
102✔
1535
            move_pause();
16✔
1536
            return;
1537
        }
1538
        const auto att = attitude_to( *critter );
86✔
1539
        if( att == A_HOSTILE ) {
86✔
1540
            if( !no_bashing ) {
×
1541
                melee_attack( *critter, true );
×
1542
            } else {
1543
                move_pause();
×
1544
            }
1545

1546
            return;
1547
        }
1548

1549
        if( critter == &g->u ) {
86✔
1550
            say( "<let_me_pass>" );
×
1551
        }
1552

1553
        // Let NPCs push each other when non-hostile
1554
        // TODO: Have them attack each other when hostile
1555
        npc *np = dynamic_cast<npc *>( critter );
86✔
1556
        if( np != nullptr && !np->in_sleep_state() ) {
86✔
1557
            std::unique_ptr<std::set<tripoint>> newnomove;
86✔
1558
            std::set<tripoint> *realnomove;
1559
            if( nomove != nullptr ) {
86✔
1560
                realnomove = nomove;
1561
            } else {
1562
                // create the no-move list
1563
                newnomove.reset( new std::set<tripoint>() );
32✔
1564
                realnomove = newnomove.get();
16✔
1565
            }
1566
            // other npcs should not try to move into this npc anymore,
1567
            // so infinite loop can be avoided.
1568
            realnomove->insert( pos() );
86✔
1569
            np->move_away_from( pos(), true, realnomove );
86✔
1570
        }
1571

1572
        if( critter->pos() == p ) {
86✔
1573
            move_pause();
86✔
1574
            return;
1575
        }
1576
    }
1577

1578
    // Boarding moving vehicles is fine, unboarding isn't
1579
    bool moved = false;
4✔
1580
    if( const optional_vpart_position vp = g->m.veh_at( pos() ) ) {
4✔
1581
        const optional_vpart_position ovp = g->m.veh_at( p );
×
1582
        if( abs( vp->vehicle().velocity ) > 0 &&
×
1583
            ( veh_pointer_or_null( ovp ) != veh_pointer_or_null( vp ) ||
×
1584
              !ovp.part_with_feature( VPFLAG_BOARDABLE, true ) ) ) {
×
1585
            move_pause();
×
1586
            return;
1587
        }
1588
    }
1589

1590
    if( p.z != posz() ) {
4✔
1591
        // Z-level move
1592
        // For now just teleport to the destination
1593
        // TODO: Make it properly find the tile to move to
1594
        moves -= 100;
×
1595
        moved = true;
×
1596
    } else if( g->m.passable( p ) ) {
4✔
1597
        bool diag = trigdist && posx() != p.x && posy() != p.y;
4✔
1598
        moves -= run_cost( g->m.combined_movecost( pos(), p ), diag );
4✔
1599
        moved = true;
4✔
1600
    } else if( g->m.open_door( p, !g->m.is_outside( pos() ) ) ) {
×
1601
        moves -= 100;
×
1602
    } else if( get_dex() > 1 && g->m.has_flag_ter_or_furn( "CLIMBABLE", p ) ) {
×
1603
        ///\EFFECT_DEX_NPC increases chance to climb CLIMBABLE furniture or terrain
1604
        int climb = get_dex();
×
1605
        if( one_in( climb ) ) {
×
1606
            add_msg_if_npc( m_neutral, _( "%1$s tries to climb the %2$s but slips." ),
1607
                            name.c_str(), g->m.tername( p ).c_str() );
×
1608
            moves -= 400;
×
1609
        } else {
1610
            add_msg_if_npc( m_neutral, _( "%1$s climbs over the %2$s." ), name.c_str(),
×
1611
                            g->m.tername( p ).c_str() );
×
1612
            moves -= ( 500 - ( rng( 0, climb ) * 20 ) );
×
1613
            moved = true;
×
1614
        }
1615
    } else if( !no_bashing && smash_ability() > 0 && g->m.is_bashable( p ) &&
×
1616
               g->m.bash_rating( smash_ability(), p ) > 0 ) {
×
1617
        moves -= !is_armed() ? 80 : weapon.attack_time() * 0.8;
×
1618
        g->m.bash( p, smash_ability() );
×
1619
    } else {
1620
        if( attitude == NPCATT_MUG ||
×
1621
            attitude == NPCATT_KILL ||
×
1622
            attitude == NPCATT_WAIT_FOR_LEAVE ) {
1623
            set_attitude( NPCATT_FLEE );
×
1624
        }
1625

1626
        moves = 0;
×
1627
    }
1628

1629
    if( moved ) {
4✔
1630
        const tripoint old_pos = pos();
4✔
1631
        setpos( p );
4✔
1632

1633
        if( g->m.has_flag( "UNSTABLE", pos() ) ) {
4✔
1634
            add_effect( effect_bouldering, 1_turns, num_bp, true );
×
1635
        } else if( has_effect( effect_bouldering ) ) {
4✔
1636
            remove_effect( effect_bouldering );
×
1637
        }
1638

1639
        if( in_vehicle ) {
4✔
1640
            g->m.unboard_vehicle( old_pos );
×
1641
        }
1642

1643
        // Close doors behind self (if you can)
1644
        if( is_friend() && rules.close_doors ) {
4✔
1645
            doors::close_door( g->m, *this, old_pos );
×
1646
        }
1647

1648
        if( g->m.veh_at( p ).part_with_feature( VPFLAG_BOARDABLE, true ) ) {
12✔
1649
            g->m.board_vehicle( p, this );
×
1650
        }
1651

1652
        g->m.creature_on_trap( *this );
4✔
1653
        g->m.creature_in_field( *this );
4✔
1654
    }
1655
}
1656

1657
void npc::move_to_next()
×
1658
{
1659
    while( !path.empty() && pos() == path[0] ) {
×
1660
        path.erase( path.begin() );
×
1661
    }
1662

1663
    if( path.empty() ) {
×
1664
        add_msg( m_debug,
1665
                 "npc::move_to_next() called with an empty path or path containing only current position" );
×
1666
        move_pause();
×
1667
        return;
×
1668
    }
1669

1670
    move_to( path[0] );
×
1671
    if( !path.empty() && pos() == path[0] ) { // Move was successful
×
1672
        path.erase( path.begin() );
×
1673
    }
1674
}
1675

1676
void npc::avoid_friendly_fire()
×
1677
{
1678
    // @todo: To parameter
1679
    const tripoint &tar = current_target()->pos();
×
1680
    // Calculate center of weight of friends and move away from that
1681
    tripoint center;
×
1682
    for( const auto &fr : ai_cache.friends ) {
×
1683
        const Creature &ally = *fr.get();
×
1684
        center += ally.pos();
×
1685
    }
1686

1687
    float friend_count = ai_cache.friends.size();
×
1688
    center.x = round( center.x / friend_count );
×
1689
    center.y = round( center.y / friend_count );
×
1690
    center.z = round( center.z / friend_count );
×
1691

1692
    auto candidates = closest_tripoints_first( 1, pos() );
×
1693
    candidates.erase( candidates.begin() );
×
1694
    std::sort( candidates.begin(), candidates.end(),
1695
    [&tar, &center]( const tripoint & l, const tripoint & r ) {
×
1696
        return ( rl_dist( l, tar ) - rl_dist( l, center ) ) <
×
1697
               ( rl_dist( r, tar ) - rl_dist( r, center ) );
×
1698
    } );
×
1699

1700
    for( const auto &pt : candidates ) {
×
1701
        if( can_move_to( pt ) ) {
×
1702
            move_to( pt );
×
1703
            return;
×
1704
        }
1705
    }
1706

1707
    /* If we're still in the function at this point, maneuvering can't help us. So,
1708
     * might as well address some needs.
1709
     * We pass a <danger> value of NPC_DANGER_VERY_LOW + 1 so that we won't start
1710
     * eating food (or, god help us, sleeping).
1711
     */
1712
    npc_action action = address_needs( NPC_DANGER_VERY_LOW + 1 );
×
1713
    if( action == npc_undecided ) {
×
1714
        move_pause();
×
1715
    }
1716
    execute_action( action );
×
1717
}
1718

1719
void npc::escape_explosion()
×
1720
{
1721
    if( ai_cache.dangerous_explosives.empty() ) {
×
1722
        return;
×
1723
    }
1724

1725
    if( is_following() && one_in( 10 ) ) {
×
1726
        say( "<fire_in_the_hole>" );
×
1727
    }
1728

1729
    move_away_from( ai_cache.dangerous_explosives, true );
×
1730
}
1731

1732
void npc::move_away_from( const tripoint &pt, bool no_bash_atk, std::set<tripoint> *nomove )
86✔
1733
{
1734
    tripoint best_pos = pos();
86✔
1735
    int best = -1;
86✔
1736
    int chance = 2;
86✔
1737
    for( const tripoint &p : g->m.points_in_radius( pos(), 1 ) ) {
1,634✔
1738
        if( nomove != nullptr && nomove->find( p ) != nomove->end() ) {
2,322✔
1739
            continue;
1740
        }
1741

1742
        if( p == pos() ) {
632✔
1743
            continue;
1744
        }
1745

1746
        if( p == g->u.pos() ) {
546✔
1747
            continue;
1748
        }
1749

1750
        const int cost = g->m.combined_movecost( pos(), p );
546✔
1751
        if( cost <= 0 ) {
546✔
1752
            continue;
1753
        }
1754

1755
        const int dst = abs( p.x - pt.x ) + abs( p.y - pt.y ) + abs( p.z - pt.z );
546✔
1756
        const int val = dst * 1000 / cost;
546✔
1757
        if( val > best && can_move_to( p, no_bash_atk ) ) {
546✔
1758
            best_pos = p;
96✔
1759
            best = val;
96✔
1760
            chance = 2;
96✔
1761
        } else if( ( val == best && one_in( chance ) ) && can_move_to( p, no_bash_atk ) ) {
450✔
1762
            best_pos = p;
×
1763
            best = val;
×
1764
            chance++;
×
1765
        }
1766
    }
1767

1768
    move_to( best_pos, no_bash_atk, nomove );
86✔
1769
}
86✔
1770

1771
void npc::move_pause()
104✔
1772

1773
{
1774
    // NPCs currently always aim when using a gun, even with no target
1775
    // This simulates them aiming at stuff just at the edge of their range
1776
    if( !weapon.is_gun() ) {
104✔
1777
        pause();
64✔
1778
        return;
168✔
1779
    }
1780

1781
    // Stop, drop, and roll
1782
    if( has_effect( effect_onfire ) ) {
40✔
1783
        pause();
×
1784
    } else {
1785
        aim();
40✔
1786
        moves = std::min( moves, 0 );
80✔
1787
    }
1788
}
1789

1790
static cata::optional<tripoint> nearest_passable( const tripoint &p, const tripoint &closest_to )
1791
{
1792
    if( g->m.passable( p ) ) {
×
1793
        return p;
1794
    }
1795

1796
    // We need to path to adjacent tile, not the exact one
1797
    // Let's pick the closest one to us that is passable
1798
    auto candidates = closest_tripoints_first( 1, p );
×
1799
    std::sort( candidates.begin(), candidates.end(), [ closest_to ]( const tripoint & l,
1800
    const tripoint & r ) {
×
1801
        return rl_dist( closest_to, l ) < rl_dist( closest_to, r );
×
1802
    } );
×
1803
    auto iter = std::find_if( candidates.begin(), candidates.end(), []( const tripoint & pt ) {
×
1804
        return g->m.passable( pt );
×
1805
    } );
×
1806
    if( iter != candidates.end() ) {
×
1807
        return *iter;
×
1808
    }
1809

1810
    return cata::nullopt;
×
1811
}
1812

1813
void npc::move_away_from( const std::vector<sphere> &spheres, bool no_bashing )
×
1814
{
1815
    if( spheres.empty() ) {
×
1816
        return;
×
1817
    }
1818

1819
    tripoint minp( pos() );
×
1820
    tripoint maxp( pos() );
×
1821

1822
    for( const auto &elem : spheres ) {
×
1823
        minp.x = std::min( minp.x, elem.center.x - elem.radius );
×
1824
        minp.y = std::min( minp.y, elem.center.y - elem.radius );
×
1825
        maxp.x = std::max( maxp.x, elem.center.x + elem.radius );
×
1826
        maxp.y = std::max( maxp.y, elem.center.y + elem.radius );
×
1827
    }
1828

1829
    const tripoint_range range( minp, maxp );
1830

1831
    std::vector<tripoint> escape_points;
1832

1833
    std::copy_if( range.begin(), range.end(), std::back_inserter( escape_points ),
1834
    [&]( const tripoint & elem ) {
×
1835
        return g->m.passable( elem );
×
1836
    } );
×
1837

1838
    algo::sort_by_rating( escape_points.begin(), escape_points.end(), [&]( const tripoint & elem ) {
×
1839
        const int danger = std::accumulate( spheres.begin(), spheres.end(), 0,
1840
        [&]( const int sum, const sphere & s ) {
×
1841
            return sum + std::max( s.radius - rl_dist( elem, s.center ), 0 );
×
1842
        } );
×
1843

1844
        const int distance = rl_dist( pos(), elem );
×
1845
        const int move_cost = g->m.move_cost( elem );
×
1846

1847
        return std::make_tuple( danger, distance, move_cost );
×
1848
    } );
×
1849

1850
    for( const auto &elem : escape_points ) {
×
1851
        update_path( elem, no_bashing );
×
1852

1853
        if( elem == pos() || !path.empty() ) {
×
1854
            break;
1855
        }
1856
    }
1857

1858
    if( !path.empty() ) {
×
1859
        move_to_next();
×
1860
    } else {
1861
        move_pause();
×
1862
    }
1863
}
1864

1865
void npc::find_item()
2✔
1866
{
1867
    if( is_following() && !rules.allow_pick_up ) {
2✔
1868
        // Grabbing stuff not allowed by our "owner"
1869
        return;
2✔
1870
    }
1871

1872
    fetching_item = false;
×
1873
    int best_value = minimum_item_value();
×
1874
    // Not perfect, but has to mirror pickup code
1875
    units::volume volume_allowed = volume_capacity() - volume_carried();
×
1876
    units::mass   weight_allowed = weight_capacity() - weight_carried();
×
1877
    // For some reason range limiting by vision doesn't work properly
1878
    const int range = 6;
×
1879
    //int range = sight_range( g->light_level( posz() ) );
1880
    //range = std::max( 1, std::min( 12, range ) );
1881

1882
    static const zone_type_id no_pickup( "NO_NPC_PICKUP" );
1883

1884
    const item *wanted = nullptr;
×
1885

1886
    const bool whitelisting = has_item_whitelist();
×
1887

1888
    if( volume_allowed <= 0 || weight_allowed <= 0 ) {
×
1889
        return;
1890
    }
1891

1892
    const auto consider_item =
1893
        [&wanted, &best_value, whitelisting, volume_allowed, weight_allowed, this]
1894
    ( const item & it, const tripoint & p ) {
×
1895
        if( it.made_of_from_type( LIQUID ) ) {
×
1896
            // Don't even consider liquids.
1897
            return;
1898
        }
1899

1900
        if( whitelisting && !item_whitelisted( it ) ) {
×
1901
            return;
1902
        }
1903

1904
        // When using a whitelist, skip the value check
1905
        // @todo: Whitelist hierarchy?
1906
        int itval = whitelisting ? 1000 : value( it );
×
1907

1908
        if( itval > best_value &&
×
1909
            ( it.volume() <= volume_allowed && it.weight() <= weight_allowed ) ) {
×
1910
            wanted_item_pos = p;
×
1911
            wanted = &( it );
×
1912
            best_value = itval;
×
1913
        }
1914
    };
1915

1916
    // Harvest item doesn't exist, so we'll be checking by its name
1917
    std::string wanted_name;
1918
    const auto consider_terrain =
1919
    [ this, whitelisting, volume_allowed, &wanted, &wanted_name ]( const tripoint & p ) {
×
1920
        // We only want to pick plants when there are no items to pick
1921
        if( !whitelisting || wanted != nullptr || !wanted_name.empty() ||
×
1922
            volume_allowed < units::from_milliliter( 250 ) ) {
×
1923
            return;
×
1924
        }
1925

1926
        const auto harvest = g->m.get_harvest_names( p );
×
1927
        for( const auto &entry : harvest ) {
×
1928
            if( item_name_whitelisted( entry ) ) {
×
1929
                wanted_name = entry;
×
1930
                wanted_item_pos = p;
×
1931
                break;
×
1932
            }
1933
        }
1934
    };
1935

1936
    for( const tripoint &p : closest_tripoints_first( range, pos() ) ) {
×
1937
        // TODO: Make this sight check not overdraw nearby tiles
1938
        // TODO: Optimize that zone check
1939
        if( is_following() && g->check_zone( no_pickup, p ) ) {
×
1940
            continue;
×
1941
        }
1942

1943
        if( g->m.sees_some_items( p, *this ) && sees( p ) ) {
×
1944
            for( const item &it : g->m.i_at( p ) ) {
×
1945
                consider_item( it, p );
×
1946
            }
1947
        }
1948

1949
        // Allow terrain check without sight, because it would cost more CPU than it is worth
1950
        consider_terrain( p );
×
1951

1952
        const optional_vpart_position vp = g->m.veh_at( p );
×
1953
        if( !vp || vp->vehicle().velocity != 0 || !sees( p ) ) {
×
1954
            continue;
1955
        }
1956
        const cata::optional<vpart_reference> cargo = vp.part_with_feature( VPFLAG_CARGO, true );
×
1957
        static const std::string locked_string( "LOCKED" );
1958
        //TODO Let player know what parts are safe from NPC thieves
1959
        if( !cargo || cargo->has_feature( locked_string ) ) {
×
1960
            continue;
1961
        }
1962

1963
        static const std::string cargo_locking_string( "CARGO_LOCKING" );
1964
        if( vp.part_with_feature( cargo_locking_string, true ) ) {
×
1965
            continue;
1966
        }
1967

1968
        for( const item &it : cargo->vehicle().get_items( cargo->part_index() ) ) {
×
1969
            consider_item( it, p );
×
1970
        }
1971
    }
1972

1973
    if( wanted != nullptr ) {
×
1974
        wanted_name = wanted->tname();
×
1975
    }
1976

1977
    if( wanted_name.empty() ) {
×
1978
        return;
×
1979
    }
1980

1981
    fetching_item = true;
×
1982

1983
    // TODO: Move that check above, make it multi-target pathing and use it
1984
    // to limit tiles available for choice of items
1985
    const int dist_to_item = rl_dist( wanted_item_pos, pos() );
×
1986
    if( const cata::optional<tripoint> dest = nearest_passable( wanted_item_pos, pos() ) ) {
×
1987
        update_path( *dest );
×
1988
    }
1989

1990
    if( path.empty() && dist_to_item > 1 ) {
×
1991
        // Item not reachable, let's just totally give up for now
1992
        fetching_item = false;
×
1993
    }
1994

1995
    if( fetching_item && rl_dist( wanted_item_pos, pos() ) > 1 && is_following() ) {
×
1996
        say( _( "Hold on, I want to pick up that %s." ), wanted_name.c_str() );
×
1997
    }
1998
}
1999

2000
void npc::pick_up_item()
×
2001
{
2002
    if( is_following() && !rules.allow_pick_up ) {
×
2003
        add_msg( m_debug, "%s::pick_up_item(); Cancelling on player's request", name.c_str() );
×
2004
        fetching_item = false;
×
2005
        moves -= 1;
×
2006
        return;
×
2007
    }
2008

2009
    const cata::optional<vpart_reference> vp = g->m.veh_at( wanted_item_pos ).part_with_feature(
2010
                VPFLAG_CARGO, false );
×
2011
    const bool has_cargo = vp && !vp->has_feature( "LOCKED" );
×
2012

2013
    if( ( !g->m.has_items( wanted_item_pos ) && !has_cargo &&
×
2014
          !g->m.is_harvestable( wanted_item_pos ) && sees( wanted_item_pos ) ) ||
×
2015
        ( is_following() && g->check_zone( zone_type_id( "NO_NPC_PICKUP" ), wanted_item_pos ) ) ) {
×
2016
        // Items we wanted no longer exist and we can see it
2017
        // Or player who is leading us doesn't want us to pick it up
2018
        fetching_item = false;
×
2019
        move_pause();
×
2020
        add_msg( m_debug, "Canceling pickup - no items or new zone" );
×
2021
        return;
2022
    }
2023

2024
    add_msg( m_debug, "%s::pick_up_item(); [%d, %d, %d] => [%d, %d, %d]", name.c_str(),
×
2025
             posx(), posy(), posz(), wanted_item_pos.x, wanted_item_pos.y, wanted_item_pos.z );
×
2026
    if( const cata::optional<tripoint> dest = nearest_passable( wanted_item_pos, pos() ) ) {
×
2027
        update_path( *dest );
×
2028
    }
2029

2030
    const int dist_to_pickup = rl_dist( pos(), wanted_item_pos );
×
2031
    if( dist_to_pickup > 1 && !path.empty() ) {
×
2032
        add_msg( m_debug, "Moving; [%d, %d, %d] => [%d, %d, %d]",
2033
                 posx(), posy(), posz(), path[0].x, path[0].y, path[0].z );
×
2034

2035
        move_to_next();
×
2036
        return;
2037
    } else if( dist_to_pickup > 1 && path.empty() ) {
×
2038
        add_msg( m_debug, "Can't find path" );
×
2039
        // This can happen, always do something
2040
        fetching_item = false;
×
2041
        move_pause();
×
2042
        return;
2043
    }
2044

2045
    // We're adjacent to the item; grab it!
2046

2047
    auto picked_up = pick_up_item_map( wanted_item_pos );
×
2048
    if( picked_up.empty() && has_cargo ) {
×
2049
        picked_up = pick_up_item_vehicle( vp->vehicle(), vp->part_index() );
×
2050
    }
2051

2052
    if( picked_up.empty() ) {
×
2053
        // Last chance: plant harvest
2054
        if( g->m.is_harvestable( wanted_item_pos ) ) {
×
2055
            g->m.examine( *this, wanted_item_pos );
×
2056
            // Note: we didn't actually pick up anything, just spawned items
2057
            // but we want the item picker to find new items
2058
            fetching_item = false;
×
2059
            return;
2060
        }
2061
    }
2062
    // Describe the pickup to the player
2063
    bool u_see = g->u.sees( *this ) || g->u.sees( wanted_item_pos );
×
2064
    if( u_see ) {
×
2065
        if( picked_up.size() == 1 ) {
×
2066
            add_msg( _( "%1$s picks up a %2$s." ), name.c_str(),
×
2067
                     picked_up.front().tname().c_str() );
×
2068
        } else if( picked_up.size() == 2 ) {
×
2069
            add_msg( _( "%1$s picks up a %2$s and a %3$s." ), name.c_str(),
×
2070
                     picked_up.front().tname().c_str(),
×
2071
                     picked_up.back().tname().c_str() );
×
2072
        } else if( picked_up.size() > 2 ) {
×
2073
            add_msg( _( "%s picks up several items." ), name.c_str() );
×
2074
        } else {
2075
            add_msg( _( "%s looks around nervously, as if searching for something." ), name.c_str() );
×
2076
        }
2077
    }
2078

2079
    for( auto &it : picked_up ) {
×
2080
        int itval = value( it );
×
2081
        if( itval < worst_item_value ) {
×
2082
            worst_item_value = itval;
×
2083
        }
2084

2085
        i_add( it );
×
2086
    }
2087

2088
    moves -= 100;
×
2089
    fetching_item = false;
×
2090
    has_new_items = true;
×
2091
}
2092

2093
template <typename T>
2094
std::list<item> npc_pickup_from_stack( npc &who, T &items )
×
2095
{
2096
    const bool whitelisting = who.has_item_whitelist();
×
2097
    auto volume_allowed = who.volume_capacity() - who.volume_carried();
×
2098
    auto weight_allowed = who.weight_capacity() - who.weight_carried();
×
2099
    auto min_value = whitelisting ? 0 : who.minimum_item_value();
×
2100
    std::list<item> picked_up;
2101

2102
    for( auto iter = items.begin(); iter != items.end(); ) {
×
2103
        const item &it = *iter;
×
2104
        if( it.made_of_from_type( LIQUID ) ) {
×
2105
            iter++;
×
2106
            continue;
×
2107
        }
2108

2109
        if( whitelisting && !who.item_whitelisted( it ) ) {
×
2110
            iter++;
×
2111
            continue;
2112
        }
2113

2114
        auto volume = it.volume();
×
2115
        if( volume > volume_allowed ) {
×
2116
            iter++;
×
2117
            continue;
2118
        }
2119

2120
        auto weight = it.weight();
×
2121
        if( weight > weight_allowed ) {
×
2122
            iter++;
×
2123
            continue;
2124
        }
2125

2126
        int itval = whitelisting ? 1000 : who.value( it );
×
2127
        if( itval < min_value ) {
×
2128
            iter++;
×
2129
            continue;
2130
        }
2131

2132
        volume_allowed -= volume;
2133
        weight_allowed -= weight;
2134
        picked_up.push_back( it );
×
2135
        iter = items.erase( iter );
×
2136
    }
2137

2138
    return picked_up;
×
2139
}
2140

2141
std::list<item> npc::pick_up_item_map( const tripoint &where )
×
2142
{
2143
    auto stack = g->m.i_at( where );
×
2144
    return npc_pickup_from_stack( *this, stack );
×
2145
}
2146

2147
std::list<item> npc::pick_up_item_vehicle( vehicle &veh, int part_index )
×
2148
{
2149
    auto stack = veh.get_items( part_index );
×
2150
    return npc_pickup_from_stack( *this, stack );
×
2151
}
2152

2153
void npc::drop_items( int weight, int volume )
×
2154
{
2155
    add_msg( m_debug, "%s is dropping items-%d,%d (%d items, wgt %d/%d, vol %d/%d)",
2156
             name.c_str(), weight, volume, inv.size(), to_gram( weight_carried() ),
×
2157
             to_gram( weight_capacity() ), volume_carried() / units::legacy_volume_factor,
×
2158
             volume_capacity() / units::legacy_volume_factor );
×
2159

2160
    int weight_dropped = 0;
×
2161
    int volume_dropped = 0;
×
2162
    std::vector<ratio_index> rWgt, rVol; // Weight/Volume to value ratios
2163

2164
    // First fill our ratio vectors, so we know which things to drop first
2165
    invslice slice = inv.slice();
×
2166
    for( unsigned int i = 0; i < slice.size(); i++ ) {
×
2167
        item &it = slice[i]->front();
×
2168
        double wgt_ratio = 0.0;
×
2169
        double vol_ratio = 0.0;
×
2170
        if( value( it ) == 0 ) {
×
2171
            wgt_ratio = 99999;
2172
            vol_ratio = 99999;
2173
        } else {
2174
            wgt_ratio = it.weight() / 1_gram / value( it );
×
2175
            vol_ratio = it.volume() / units::legacy_volume_factor / value( it );
×
2176
        }
2177
        bool added_wgt = false;
×
2178
        bool added_vol = false;
×
2179
        for( size_t j = 0; j < rWgt.size() && !added_wgt; j++ ) {
×
2180
            if( wgt_ratio > rWgt[j].ratio ) {
×
2181
                added_wgt = true;
×
2182
                rWgt.insert( rWgt.begin() + j, ratio_index( wgt_ratio, i ) );
×
2183
            }
2184
        }
2185
        if( !added_wgt ) {
×
2186
            rWgt.push_back( ratio_index( wgt_ratio, i ) );
×
2187
        }
2188
        for( size_t j = 0; j < rVol.size() && !added_vol; j++ ) {
×
2189
            if( vol_ratio > rVol[j].ratio ) {
×
2190
                added_vol = true;
×
2191
                rVol.insert( rVol.begin() + j, ratio_index( vol_ratio, i ) );
×
2192
            }
2193
        }
2194
        if( !added_vol ) {
×
2195
            rVol.push_back( ratio_index( vol_ratio, i ) );
×
2196
        }
2197
    }
2198

2199
    std::stringstream item_name; // For description below
×
2200
    int num_items_dropped = 0; // For description below
×
2201
    // Now, drop items, starting from the top of each list
2202
    while( weight_dropped < weight || volume_dropped < volume ) {
×
2203
        // weight and volume may be passed as 0 or a negative value, to indicate that
2204
        // decreasing that variable is not important.
2205
        int dWeight = ( weight <= 0 ? -1 : weight - weight_dropped );
×
2206
        int dVolume = ( volume <= 0 ? -1 : volume - volume_dropped );
×
2207
        int index;
2208
        // Which is more important, weight or volume?
2209
        if( dWeight > dVolume ) {
×
2210
            index = rWgt[0].index;
×
2211
            rWgt.erase( rWgt.begin() );
×
2212
            // Fix the rest of those indices.
2213
            for( auto &elem : rWgt ) {
×
2214
                if( elem.index > index ) {
×
2215
                    elem.index--;
×
2216
                }
2217
            }
2218
        } else {
2219
            index = rVol[0].index;
×
2220
            rVol.erase( rVol.begin() );
×
2221
            // Fix the rest of those indices.
2222
            for( size_t i = 0; i < rVol.size(); i++ ) {
×
2223
                if( i > rVol.size() ) {
×
2224
                    debugmsg( "npc::drop_items() - looping through rVol - Size is %d, i is %d",
×
2225
                              rVol.size(), i );
×
2226
                }
2227
                if( rVol[i].index > index ) {
×
2228
                    rVol[i].index--;
×
2229
                }
2230
            }
2231
        }
2232
        weight_dropped += slice[index]->front().weight() / 1_gram;
×
2233
        volume_dropped += slice[index]->front().volume() / units::legacy_volume_factor;
×
2234
        item dropped = i_rem( index );
×
2235
        num_items_dropped++;
×
2236
        if( num_items_dropped == 1 ) {
×
2237
            item_name << dropped.tname();
×
2238
        } else if( num_items_dropped == 2 ) {
×
2239
            item_name << _( " and " ) << dropped.tname();
×
2240
        }
2241
        g->m.add_item_or_charges( pos(), dropped );
×
2242
    }
2243
    // Finally, describe the action if u can see it
2244
    if( g->u.sees( *this ) ) {
×
2245
        if( num_items_dropped >= 3 ) {
×
2246
            add_msg( ngettext( "%s drops %d item.", "%s drops %d items.",
2247
                               num_items_dropped ), name.c_str(),
×
2248
                     num_items_dropped );
×
2249
        } else {
2250
            std::string item_name_str = item_name.str();
2251
            add_msg( _( "%1$s drops a %2$s." ), name.c_str(),
×
2252
                     item_name_str.c_str() );
×
2253
        }
2254
    }
2255
    update_worst_item_value();
×
2256
}
2257

2258
bool npc::find_corpse_to_pulp()
8✔
2259
{
2260
    if( is_following() && ( !rules.allow_pulp || g->u.in_vehicle ) ) {
8✔
2261
        return false;
2262
    }
2263

2264
    // Pathing with overdraw can get expensive, limit it
2265
    int path_counter = 4;
5✔
2266
    const auto check_tile = [this, &path_counter]( const tripoint & p ) -> const item * {
845✔
2267
        if( !g->m.sees_some_items( p, *this ) || !sees( p ) )
845✔
2268
        {
2269
            return nullptr;
2270
        }
2271

2272
        const auto items = g->m.i_at( p );
1✔
2273
        const item *found = nullptr;
1✔
2274
        for( const item &it : items )
16✔
2275
        {
2276
            // Pulp only stuff that revives, but don't pulp acid stuff
2277
            // That is, if you aren't protected from this stuff!
2278
            if( it.can_revive() ) {
14✔
2279
                // If the first encountered corpse bleeds something dangerous then
2280
                // it is not safe to bash.
2281
                if( is_dangerous_field( field_entry( it.get_mtype()->bloodType(), 1, 0 ) ) ) {
×
2282
                    return nullptr;
×
2283
                }
2284

2285
                found = &it;
2286
                break;
2287
            }
2288
        }
2289

2290
        if( found != nullptr )
1✔
2291
        {
2292
            path_counter--;
×
2293
            // Only return corpses we can path to
2294
            return update_path( p, false, false ) ? found : nullptr;
×
2295
        }
2296

2297
        return nullptr;
2298
    };
5✔
2299

2300
    const int range = 6;
5✔
2301

2302
    const item *corpse = nullptr;
5✔
2303
    if( pulp_location && square_dist( pos(), *pulp_location ) <= range ) {
5✔
2304
        corpse = check_tile( *pulp_location );
×
2305
    }
2306

2307
    // Find the old target to avoid spamming
2308
    const item *old_target = corpse;
5✔
2309

2310
    if( corpse == nullptr ) {
5✔
2311
        // If we're following the player, don't wander off to pulp corpses
2312
        const tripoint &around = is_following() ? g->u.pos() : pos();
5✔
2313
        for( const tripoint &p : closest_tripoints_first( range, around ) ) {
865✔
2314
            corpse = check_tile( p );
845✔
2315

2316
            if( corpse != nullptr ) {
845✔
2317
                pulp_location.emplace( p );
×
2318
                break;
2319
            }
2320

2321
            if( path_counter <= 0 ) {
845✔
2322
                break;
2323
            }
2324
        }
2325
    }
2326

2327
    if( corpse != nullptr && corpse != old_target && is_following() ) {
5✔
2328
        say( _( "Hold on, I want to pulp that %s." ),
2329
             corpse->tname().c_str() );
×
2330
    }
2331

2332
    return corpse != nullptr;
5✔
2333
}
2334

2335
bool npc::do_pulp()
×
2336
{
2337
    if( !pulp_location ) {
×
2338
        return false;
2339
    }
2340

2341
    if( rl_dist( *pulp_location, pos() ) > 1 || pulp_location->z != posz() ) {
×
2342
        return false;
2343
    }
2344

2345
    // TODO: Don't recreate the activity every time
2346
    int old_moves = moves;
×
2347
    assign_activity( activity_id( "ACT_PULP" ), calendar::INDEFINITELY_LONG, 0 );
×
2348
    activity.placement = *pulp_location;
×
2349
    activity.do_turn( *this );
×
2350
    return moves != old_moves;
×
2351
}
2352

2353
bool npc::wield_better_weapon()
8✔
2354
{
2355
    // TODO: Allow wielding weaker weapons against weaker targets
2356
    bool can_use_gun = ( !is_following() || rules.use_guns );
8✔
2357
    bool use_silent = ( is_following() && rules.use_silent );
8✔
2358
    invslice slice = inv.slice();
8✔
2359

2360
    // Check if there's something better to wield
2361
    item *best = &weapon;
8✔
2362
    double best_value = -100.0;
8✔
2363

2364
    const long ups_charges = charges_of( "UPS" );
8✔
2365

2366
    const auto compare_weapon =
2367
    [this, &best, &best_value, ups_charges, can_use_gun, use_silent]( item & it ) {
24✔
2368
        bool allowed = can_use_gun && it.is_gun() && ( !use_silent || it.is_silent() );
24✔
2369
        double val;
2370
        if( !allowed ) {
24✔
2371
            val = weapon_value( it, 0 );
16✔
2372
        } else {
2373
            long ammo_count = it.ammo_remaining();
8✔
2374
            long ups_drain = it.get_gun_ups_drain();
8✔
2375
            if( ups_drain > 0 ) {
8✔
2376
                ammo_count = std::min( ammo_count, ups_charges / ups_drain );
×
2377
            }
2378

2379
            val = weapon_value( it, ammo_count );
8✔
2380
        }
2381

2382
        if( val > best_value ) {
24✔
2383
            best = &it;
10✔
2384
            best_value = val;
10✔
2385
        }
2386
    };
32✔
2387

2388
    compare_weapon( weapon );
8✔
2389
    // To prevent changing to barely better stuff
2390
    best_value *= std::max<float>( 1.0f, ai_cache.danger_assessment / 10.0f );
16✔
2391

2392
    // Fists aren't checked below
2393
    compare_weapon( null_item_reference() );
8✔
2394

2395
    visit_items( [&compare_weapon]( item * node ) {
96✔
2396
        // Skip some bad items
2397
        if( !node->is_melee() ) {
96✔
2398
            return VisitResponse::SKIP;
2399
        }
2400

2401
        compare_weapon( *node );
8✔
2402

2403
        return VisitResponse::SKIP;
8✔
2404
    } );
16✔
2405

2406
    // @todo: Reimplement switching to empty guns
2407
    // Needs to check reload speed, RELOAD_ONE etc.
2408
    // Until then, the NPCs should reload the guns as a last resort
2409

2410
    if( best == &weapon ) {
8✔
2411
        add_msg( m_debug, "Wielded %s is best at %.1f, not switching",
2412
                 best->display_name().c_str(), best_value );
12✔
2413
        return false;
6✔
2414
    }
2415

2416
    add_msg( m_debug, "Wielding %s at value %.1f",
2417
             best->display_name().c_str(), best_value );
4✔
2418

2419
    wield( *best );
2✔
2420
    return true;
2421
}
2422

2423
bool npc::scan_new_items()
8✔
2424
{
2425
    add_msg( m_debug, "%s scanning new items", name.c_str() );
16✔
2426
    if( !wield_better_weapon() ) {
8✔
2427
        // Stop "having new items" when you no longer do anything with them
2428
        has_new_items = false;
6✔
2429
        return true;
6✔
2430
    }
2431

2432
    return false;
2433
    // TODO: Armor?
2434
}
2435

2436
void npc::wield_best_melee()
×
2437
{
2438
    double best_value = 0.0;
×
2439
    item *it = inv.best_for_melee( *this, best_value );
×
2440
    if( unarmed_value() >= best_value ) {
×
2441
        // "I cast fist!"
2442
        it = &null_item_reference();
×
2443
    }
2444

2445
    wield( *it );
×
2446
}
2447

2448
void npc_throw( npc &np, item &it, int index, const tripoint &pos )
×
2449
{
2450
    if( g->u.sees( np ) ) {
×
2451
        add_msg( _( "%1$s throws a %2$s." ), np.name.c_str(), it.tname().c_str() );
×
2452
    }
2453

2454
    long stack_size = -1;
×
2455
    if( it.count_by_charges() ) {
×
2456
        stack_size = it.charges;
×
2457
        it.charges = 1;
×
2458
    }
2459
    np.throw_item( pos, it );
×
2460
    // Throw a single charge of a stacking object.
2461
    if( stack_size == -1 || stack_size == 1 ) {
×
2462
        np.i_rem( index );
×
2463
    } else {
2464
        it.charges = stack_size - 1;
×
2465
    }
2466
}
2467

2468
bool npc::alt_attack()
×
2469
{
2470
    if( is_following() && !rules.use_grenades ) {
×
2471
        return false;
2472
    }
2473

2474
    Creature *critter = current_target();
×
2475
    if( critter == nullptr ) {
×
2476
        // This function shouldn't be called...
2477
        debugmsg( "npc::alt_attack() called with no target" );
×
2478
        move_pause();
×
2479
        return false;
2480
    }
2481

2482
    tripoint tar = critter->pos();
×
2483

2484
    const int dist = rl_dist( pos(), tar );
×
2485
    item *used = nullptr;
×
2486
    // Remember if we have an item that is dangerous to hold
2487
    bool used_dangerous = false;
×
2488

2489
    static const std::string danger_string( "NPC_THROW_NOW" );
2490
    static const std::string alt_string( "NPC_ALT_ATTACK" );
2491
    // @todo: The active bomb with shortest fuse should be thrown first
2492
    const auto check_alt_item = [&used, &used_dangerous, dist, this]( item & it ) {
×
2493
        const bool dangerous = it.has_flag( danger_string );
×
2494
        if( !dangerous && used_dangerous ) {
×
2495
            return;
2496
        }
2497

2498
        // Not alt attack
2499
        if( !dangerous && !it.has_flag( alt_string ) ) {
×
2500
            return;
2501
        }
2502

2503
        // @todo: Non-thrown alt items
2504
        if( !dangerous && throw_range( it ) < dist ) {
×
2505
            return;
2506
        }
2507

2508
        // Low priority items
2509
        if( !dangerous && used != nullptr ) {
×
2510
            return;
2511
        }
2512

2513
        used = &it;
×
2514
        used_dangerous = used_dangerous || dangerous;
×
2515
    };
2516

2517
    check_alt_item( weapon );
×
2518
    for( auto &sl : inv.slice() ) {
×
2519
        // @todo: Cached values - an itype slot maybe?
2520
        check_alt_item( sl->front() );
×
2521
    }
2522

2523
    if( used == nullptr ) {
×
2524
        return false;
2525
    }
2526

2527
    int weapon_index = get_item_position( used );
×
2528
    if( weapon_index == INT_MIN ) {
×
2529
        debugmsg( "npc::alt_attack() couldn't find expected item %s",
×
2530
                  used->tname().c_str() );
×
2531
        return false;
×
2532
    }
2533

2534
    // Are we going to throw this item?
2535
    if( !used->active && used->has_flag( "NPC_ACTIVATE" ) ) {
×
2536
        activate_item( weapon_index );
×
2537
        // Note: intentional lack of return here
2538
        // We want to ignore player-centric rules to avoid carrying live explosives
2539
        // @todo: Non-grenades
2540
    }
2541

2542
    // We are throwing it!
2543
    int conf = confident_throw_range( *used, critter );
×
2544
    const bool wont_hit = wont_hit_friend( tar, *used, true );
×
2545
    if( dist <= conf && wont_hit ) {
×
2546
        npc_throw( *this, *used, weapon_index, tar );
×
2547
        return true;
2548
    }
2549

2550
    if( wont_hit ) {
×
2551
        // Within this block, our chosen target is outside of our range
2552
        update_path( tar );
×
2553
        move_to_next(); // Move towards the target
×
2554
    }
2555

2556
    // Danger of friendly fire
2557
    if( !wont_hit && !used_dangerous ) {
×
2558
        // Safe to hold on to, for now
2559
        // Maneuver around player
2560
        avoid_friendly_fire();
×
2561
        return true;
2562
    }
2563

2564
    // We need to throw this live (grenade, etc) NOW! Pick another target?
2565
    for( int dist = 2; dist <= conf; dist++ ) {
×
2566
        for( const tripoint &pt : g->m.points_in_radius( pos(), dist ) ) {
×
2567
            const monster *const target_ptr = g->critter_at<monster>( pt );
×
2568
            int newdist = rl_dist( pos(), pt );
×
2569
            // TODO: Change "newdist >= 2" to "newdist >= safe_distance(used)"
2570
            if( newdist <= conf && newdist >= 2 && target_ptr &&
×
2571
                wont_hit_friend( pt, *used, true ) ) {
×
2572
                // Friendlyfire-safe!
2573
                ai_cache.target = g->shared_from( *target_ptr );
×
2574
                if( !one_in( 100 ) ) {
×
2575
                    // Just to prevent infinite loops...
2576
                    if( alt_attack() ) {
×
2577
                        return true;
×
2578
                    }
2579
                }
2580
                return false;
2581
            }
2582
        }
2583
    }
2584
    /* If we have reached THIS point, there's no acceptable monster to throw our
2585
     * grenade or whatever at.  Since it's about to go off in our hands, better to
2586
     * just chuck it as far away as possible--while being friendly-safe.
2587
     */
2588
    int best_dist = 0;
2589
    for( int dist = 2; dist <= conf; dist++ ) {
×
2590
        for( const tripoint &pt : g->m.points_in_radius( pos(), dist ) ) {
×
2591
            int new_dist = rl_dist( pos(), pt );
×
2592
            if( new_dist > best_dist && wont_hit_friend( pt, *used, true ) ) {
×
2593
                best_dist = new_dist;
×
2594
                tar = pt;
×
2595
            }
2596
        }
2597
    }
2598
    /* Even if tar.x/tar.y didn't get set by the above loop, throw it anyway.  They
2599
     * should be equal to the original location of our target, and risking friendly
2600
     * fire is better than holding on to a live grenade / whatever.
2601
     */
2602
    npc_throw( *this, *used, weapon_index, tar );
×
2603
    return true;
2604
}
2605

2606
void npc::activate_item( int item_index )
×
2607
{
2608
    const int oldmoves = moves;
×
2609
    item &it = i_at( item_index );
×
2610
    if( it.is_tool() || it.is_food() ) {
×
2611
        it.type->invoke( *this, it, pos() );
×
2612
    }
2613

2614
    if( moves == oldmoves ) {
×
2615
        // A hack to prevent debugmsgs when NPCs activate 0 move items
2616
        // while not removing the debugmsgs for other 0 move actions
2617
        moves--;
×
2618
    }
2619
}
2620

2621
void npc::heal_player( player &patient )
×
2622
{
2623
    int dist = rl_dist( pos(), patient.pos() );
×
2624

2625
    if( dist > 1 ) {
×
2626
        // We need to move to the player
2627
        update_path( patient.pos() );
×
2628
        move_to_next();
×
2629
        return;
×
2630
    }
2631

2632
    // Close enough to heal!
2633
    bool u_see = g->u.sees( *this ) || g->u.sees( patient );
×
2634
    if( u_see ) {
×
2635
        add_msg( _( "%1$s heals %2$s." ), name.c_str(), patient.name.c_str() );
×
2636
    }
2637

2638
    item &used = get_healing_item();
×
2639
    if( used.is_null() ) {
×
2640
        debugmsg( "%s tried to heal you but has no healing item", disp_name().c_str() );
×
2641
        return;
×
2642
    }
2643

2644
    long charges_used = used.type->invoke( *this, used, patient.pos(), "heal" );
×
2645
    consume_charges( used, charges_used );
×
2646

2647
    if( !patient.is_npc() ) {
×
2648
        // Test if we want to heal the player further
2649
        if( op_of_u.value * 4 + op_of_u.trust + personality.altruism * 3 +
×
2650
            ( fac_has_value( FACVAL_CHARITABLE ) ?  5 : 0 ) +
×
2651
            ( fac_has_job( FACJOB_DOCTORS )    ? 15 : 0 ) - op_of_u.fear * 3 <  25 ) {
×
2652
            set_attitude( NPCATT_FOLLOW );
×
2653
            say( _( "That's all the healing I can do." ) );
×
2654
        } else {
2655
            say( _( "Hold still, I can heal you more." ) );
×
2656
        }
2657
    }
2658
}
2659

2660
void npc::heal_self()
×
2661
{
2662
    item &used = get_healing_item();
×
2663
    if( used.is_null() ) {
×
2664
        debugmsg( "%s tried to heal self but has no healing item", disp_name().c_str() );
×
2665
        return;
×
2666
    }
2667

2668
    if( g->u.sees( *this ) ) {
×
2669
        add_msg( _( "%s applies a %s" ), name.c_str(), used.tname().c_str() );
×
2670
    }
2671

2672
    long charges_used = used.type->invoke( *this, used, pos(), "heal" );
×
2673
    if( used.is_medication() ) {
×
2674
        consume_charges( used, charges_used );
×
2675
    }
2676
}
2677

2678
void npc::use_painkiller()
×
2679
{
2680
    // First, find the best painkiller for our pain level
2681
    item *it = inv.most_appropriate_painkiller( get_pain() );
×
2682

2683
    if( it->is_null() ) {
×
2684
        debugmsg( "NPC tried to use painkillers, but has none!" );
×
2685
        move_pause();
×
2686
    } else {
2687
        if( g->u.sees( *this ) ) {
×
2688
            add_msg( _( "%1$s takes some %2$s." ), name.c_str(), it->tname().c_str() );
×
2689
        }
2690
        consume( inv.position_by_item( it ) );
×
2691
        moves = 0;
×
2692
    }
2693
}
2694

2695
// We want our food to:
2696
// Provide enough nutrition and quench
2697
// Not provide too much of either (don't waste food)
2698
// Not be unhealthy
2699
// Not have side effects
2700
// Be eaten before it rots (favor soon-to-rot perishables)
2701
float rate_food( const item &it, int want_nutr, int want_quench )
×
2702
{
2703
    const auto &food = it.type->comestible;
×
2704
    if( !food ) {
×
2705
        return 0.0f;
2706
    }
2707

2708
    if( food->parasites && !it.has_flag( "NO_PARASITES" ) ) {
×
2709
        return 0.0;
2710
    }
2711

2712
    int nutr = food->nutr;
×
2713
    int quench = food->quench;
×
2714

2715
    if( nutr <= 0 && quench <= 0 ) {
×
2716
        // Not food - may be salt, drugs etc.
2717
        return 0.0f;
2718
    }
2719

2720
    if( !it.type->use_methods.empty() ) {
×
2721
        // TODO: Get a good method of telling apart:
2722
        // raw meat (parasites - don't eat unless mutant)
2723
        // zed meat (poison - don't eat unless mutant)
2724
        // alcohol (debuffs, health drop - supplement diet but don't bulk-consume)
2725
        // caffeine (fine to consume, but expensive and prevents sleep)
2726
        // hallucination mushrooms (NPCs don't hallucinate, so don't eat those)
2727
        // honeycomb (harmless iuse)
2728
        // royal jelly (way too expensive to eat as food)
2729
        // mutagenic crap (don't eat, we want player to micromanage muties)
2730
        // marloss (NPCs don't turn fungal)
2731
        // weed brownies (small debuff)
2732
        // seeds (too expensive)
2733

2734
        // For now skip all of those
2735
        return 0.0f;
2736
    }
2737

2738
    double relative_rot = it.get_relative_rot();
×
2739
    if( relative_rot >= 1.0f ) {
×
2740
        // TODO: Allow sapro mutants to eat it anyway and make them prefer it
2741
        return 0.0f;
2742
    }
2743

2744
    float weight = std::max( 1.0, 10.0 * relative_rot );
×
2745
    if( food->fun < 0 ) {
×
2746
        // This helps to avoid eating stuff like flour
2747
        weight /= ( -food->fun ) + 1;
×
2748
    }
2749

2750
    if( food->healthy < 0 ) {
×
2751
        weight /= ( -food->healthy ) + 1;
×
2752
    }
2753

2754
    // Avoid wasting quench values unless it's about to rot away
2755
    if( relative_rot < 0.9f && quench > want_quench ) {
×
2756
        weight -= ( 1.0f - relative_rot ) * ( quench - want_quench );
×
2757
    }
2758

2759
    if( quench < 0 && want_quench > 0 && want_nutr < want_quench ) {
×
2760
        // Avoid stuff that makes us thirsty when we're more thirsty than hungry
2761
        weight = weight * want_nutr / want_quench;
×
2762
    }
2763

2764
    if( nutr > want_nutr ) {
×
2765
        // TODO: Allow overeating in some cases
2766
        if( nutr >= 5 ) {
×
2767
            return 0.0f;
2768
        }
2769

2770
        if( relative_rot < 0.9f ) {
×
2771
            weight /= nutr - want_nutr;
×
2772
        }
2773
    }
2774

2775
    if( it.poison > 0 ) {
×
2776
        weight -= it.poison;
×
2777
    }
2778

2779
    return weight;
×
2780
}
2781

2782
bool npc::consume_food()
×
2783
{
2784
    float best_weight = 0.0f;
×
2785
    int index = -1;
×
2786
    int want_hunger = get_hunger();
×
2787
    int want_quench = get_thirst();
×
2788
    invslice slice = inv.slice();
×
2789
    for( unsigned int i = 0; i < slice.size(); i++ ) {
×
2790
        const item &it = slice[i]->front();
×
2791
        const item &food_item = it.is_food_container() ?
×
2792
                                it.contents.front() : it;
×
2793
        float cur_weight = rate_food( food_item, want_hunger, want_quench );
×
2794
        // Note: will_eat is expensive, avoid calling it if possible
2795
        if( cur_weight > best_weight && will_eat( food_item ).success() ) {
×
2796
            best_weight = cur_weight;
×
2797
            index = i;
×
2798
        }
2799
    }
2800

2801
    if( index == -1 ) {
×
2802
        if( !is_friend() ) {
×
2803
            // TODO: Remove this and let player "exploit" hungry NPCs
2804
            set_hunger( 0 );
×
2805
            set_thirst( 0 );
×
2806
        }
2807
        return false;
2808
    }
2809

2810
    // consume doesn't return a meaningful answer, we need to compare moves
2811
    // @todo: Make player::consume return false if it fails to consume
2812
    int old_moves = moves;
×
2813
    bool consumed = consume( index ) && old_moves != moves;
×
2814
    if( !consumed ) {
×
2815
        debugmsg( "%s failed to consume %s", name.c_str(), i_at( index ).tname().c_str() );
×
2816
    }
2817

2818
    return consumed;
×
2819
}
2820

2821
void npc::mug_player( player &mark )
×
2822
{
2823
    if( mark.is_armed() ) {
×
2824
        make_angry();
×
2825
    }
2826

2827
    if( rl_dist( pos(), mark.pos() ) > 1 ) { // We have to travel
×
2828
        update_path( mark.pos() );
×
2829
        move_to_next();
×
2830
        return;
×
2831
    }
2832

2833
    const bool u_see = g->u.sees( *this ) || g->u.sees( mark );
×
2834
    if( mark.cash > 0 ) {
×
2835
        cash += mark.cash;
×
2836
        mark.cash = 0;
×
2837
        moves = 0;
×
2838
        // Describe the action
2839
        if( mark.is_npc() ) {
×
2840
            if( u_see ) {
×
2841
                add_msg( _( "%1$s takes %2$s's money!" ),
2842
                         name.c_str(), mark.name.c_str() );
×
2843
            }
2844
        } else {
2845
            add_msg( m_bad, _( "%s takes your money!" ), name.c_str() );
×
2846
        }
2847
        return;
2848
    }
2849

2850
    // We already have their money; take some goodies!
2851
    // value_mod affects at what point we "take the money and run"
2852
    // A lower value means we'll take more stuff
2853
    double value_mod = 1 - ( ( 10 - personality.bravery )    * .05 ) -
×
2854
                       ( ( 10 - personality.aggression ) * .04 ) -
×
2855
                       ( ( 10 - personality.collector )  * .06 );
×
2856
    if( !mark.is_npc() ) {
×
2857
        value_mod += ( op_of_u.fear * .08 );
×
2858
        value_mod -= ( ( 8 - op_of_u.value ) * .07 );
×
2859
    }
2860
    double best_value = minimum_item_value() * value_mod;
×
2861
    int item_index = INT_MIN;
×
2862
    invslice slice = mark.inv.slice();
×
2863
    for( unsigned int i = 0; i < slice.size(); i++ ) {
×
2864
        if( value( slice[i]->front() ) >= best_value &&
×
2865
            can_pickVolume( slice[i]->front(), true ) &&
×
2866
            can_pickWeight( slice[i]->front(), true ) ) {
×
2867
            best_value = value( slice[i]->front() );
×
2868
            item_index = i;
×
2869
        }
2870
    }
2871
    if( item_index == INT_MIN ) { // Didn't find anything worthwhile!
×
2872
        set_attitude( NPCATT_FLEE );
×
2873
        if( !one_in( 3 ) ) {
×
2874
            say( "<done_mugging>" );
×
2875
        }
2876
        moves -= 100;
×
2877
        return;
2878
    }
2879

2880
    item stolen = mark.i_rem( item_index );
×
2881
    if( mark.is_npc() ) {
×
2882
        if( u_see ) {
×
2883
            add_msg( _( "%1$s takes %2$s's %3$s." ), name.c_str(),
×
2884
                     mark.name.c_str(),
×
2885
                     stolen.tname().c_str() );
×
2886
        }
2887
    } else {
2888
        add_msg( m_bad, _( "%1$s takes your %2$s." ),
2889
                 name.c_str(), stolen.tname().c_str() );
×
2890
    }
2891
    i_add( stolen );
×
2892
    moves -= 100;
×
2893
    if( !mark.is_npc() ) {
×
2894
        op_of_u.value -= rng( 0, 1 );  // Decrease the value of the player
×
2895
    }
2896
}
2897

2898
void npc::look_for_player( player &sought )
×
2899
{
2900
    update_path( sought.pos() );
×
2901
    move_to_next();
×
2902
    return;
×
2903
    // The part below is not implemented properly
2904
    /*
2905
    if( sees( sought ) ) {
2906
        move_pause();
2907
        return;
2908
    }
2909

2910
    if (!path.empty()) {
2911
        const tripoint &dest = path[path.size() - 1];
2912
        if( !sees( dest ) ) {
2913
            move_to_next();
2914
            return;
2915
        }
2916
        path.clear();
2917
    }
2918
    std::vector<point> possibilities;
2919
    for (int x = 1; x < SEEX * MAPSIZE; x += 11) { // 1, 12, 23, 34
2920
        for (int y = 1; y < SEEY * MAPSIZE; y += 11) {
2921
            if( sees( x, y ) ) {
2922
                possibilities.push_back(point(x, y));
2923
            }
2924
        }
2925
    }
2926
    if (possibilities.empty()) { // We see all the spots we'd like to check!
2927
        say("<wait>");
2928
        move_pause();
2929
    } else {
2930
        if (one_in(6)) {
2931
            say("<wait>");
2932
        }
2933
        update_path( tripoint( random_entry( possibilities ), posz() ) );
2934
        move_to_next();
2935
    }
2936
    */
2937
}
2938

2939
bool npc::saw_player_recently() const
×
2940
{
2941
    return last_player_seen_pos && g->m.inbounds( *last_player_seen_pos ) && last_seen_player_turn > 0;
×
2942
}
2943

2944
bool npc::has_destination() const
×
2945
{
2946
    return goal != no_goal_point;
×
2947
}
2948

2949
void npc::reach_destination()
×
2950
{
2951
    // Guarding NPCs want a specific point, not just an overmap tile
2952
    // Rest stops having a goal after reaching it
2953
    if( !is_guarding() ) {
×
2954
        goal = no_goal_point;
×
2955
        return;
×
2956
    }
2957

2958
    // If we are guarding, remember our position in case we get forcibly moved
2959
    goal = global_omt_location();
×
2960
    if( guard_pos == global_square_location() ) {
×
2961
        // This is the specific point
2962
        return;
2963
    }
2964

2965
    if( path.size() > 1 ) {
×
2966
        // No point recalculating the path to get home
2967
        move_to_next();
×
2968
    } else if( guard_pos != no_goal_point ) {
×
2969
        const tripoint sm_dir = goal - submap_coords;
×
2970
        const tripoint dest( sm_dir.x * SEEX + guard_pos.x - posx(),
×
2971
                             sm_dir.y * SEEY + guard_pos.y - posy(),
×
2972
                             guard_pos.z );
×
2973
        update_path( dest );
×
2974
        move_to_next();
×
2975
    } else {
2976
        guard_pos = global_square_location();
×
2977
    }
2978
}
2979

2980
void npc::set_destination()
×
2981
{
2982
    /* TODO: Make NPCs' movement more intelligent.
2983
     * Right now this function just makes them attempt to address their needs:
2984
     *  if we need ammo, go to a gun store, if we need food, go to a grocery store,
2985
     *  and if we don't have any needs, pick a random spot.
2986
     * What it SHOULD do is that, if there's time; but also look at our mission and
2987
     *  our faction to determine more meaningful actions, such as attacking a rival
2988
     *  faction's base, or meeting up with someone friendly.  NPCs should also
2989
     *  attempt to reach safety before nightfall, and possibly similar goals.
2990
     * Also, NPCs should be able to assign themselves missions like "break into that
2991
     *  lab" or "map that river bank."
2992
     */
2993
    if( is_guarding() ) {
×
2994
        guard_current_pos();
×
2995
        return;
×
2996
    }
2997

2998
    // all of the following luxuries are at ground level.
2999
    // so please wallow in hunger & fear if below ground.
3000
    if( posz() != 0 && !g->m.has_zlevels() ) {
×
3001
        goal = no_goal_point;
×
3002
        return;
×
3003
    }
3004

3005
    decide_needs();
×
3006
    if( needs.empty() ) { // We don't need anything in particular.
×
3007
        needs.push_back( need_none );
×
3008
    }
3009

3010
    // We need that, otherwise find_closest won't work properly
3011
    // TODO: Allow finding sewers and stuff
3012
    tripoint surface_omt_loc = global_omt_location();
×
3013
    surface_omt_loc.z = 0;
×
3014

3015
    std::string dest_type = get_location_for( needs.front() )->get_random_terrain().id().str();
×
3016
    goal = overmap_buffer.find_closest( surface_omt_loc, dest_type, 0, false );
×
3017

3018
    DebugLog( D_INFO, DC_ALL ) << "npc::set_destination - new goal for NPC [" << get_name() <<
×
3019
                               "] with ["
×
3020
                               << get_need_str_id( needs.front() ) << "] is [" << dest_type << "] in ["
×
3021
                               << goal.x << "," << goal.y << "," << goal.z << "].";
×
3022
}
3023

3024
void npc::go_to_destination()
×
3025
{
3026
    if( goal == no_goal_point ) {
×
3027
        add_msg( m_debug, "npc::go_to_destination with no goal" );
×
3028
        move_pause();
×
3029
        reach_destination();
×
3030
        return;
×
3031
    }
3032

3033
    const tripoint omt_pos = global_omt_location();
×
3034
    int sx = sgn( goal.x - omt_pos.x );
×
3035
    int sy = sgn( goal.y - omt_pos.y );
×
3036
    const int minz = std::min( goal.z, posz() );
×
3037
    const int maxz = std::max( goal.z, posz() );
×
3038
    add_msg( m_debug, "%s going (%d,%d,%d)->(%d,%d,%d)", name.c_str(),
×
3039
             omt_pos.x, omt_pos.y, omt_pos.z, goal.x, goal.y, goal.z );
×
3040
    if( goal == omt_pos ) {
×
3041
        // We're at our desired map square!
3042
        reach_destination();
×
3043
        return;
3044
    }
3045

3046
    if( !path.empty() &&
×
3047
        sgn( path.back().x - posx() ) == sx &&
×
3048
        sgn( path.back().y - posy() ) == sy &&
×
3049
        sgn( path.back().z - posz() ) == sgn( goal.z - posz() ) ) {
×
3050
        // We're moving in the right direction, don't find a different path
3051
        move_to_next();
×
3052
        return;
3053
    }
3054

3055
    if( sx == 0 && sy == 0 && goal.z != posz() ) {
×
3056
        // Make sure we always have some points to check
3057
        sx = rng( -1, 1 );
×
3058
        sy = rng( -1, 1 );
×
3059
    }
3060

3061
    // sx and sy are now equal to the direction we need to move in
3062
    tripoint dest( posx() + 8 * sx, posy() + 8 * sy, goal.z );
×
3063
    for( int i = 0; i < 8; i++ ) {
×
3064
        if( ( g->m.passable( dest ) ||
×
3065
              //Needs 20% chance of bashing success to be considered for pathing
3066
              g->m.bash_rating( smash_ability(), dest ) >= 2 ||
×
3067
              g->m.open_door( dest, true, true ) ) &&
×
3068
            ( one_in( 4 ) || sees( dest ) ) ) {
×
3069
            update_path( dest );
×
3070
            if( !path.empty() && can_move_to( path[0] ) ) {
×
3071
                move_to_next();
×
3072
                return;
3073
            } else {
3074
                move_pause();
×
3075
                return;
3076
            }
3077
        }
3078

3079
        dest = tripoint( posx() + rng( 0, 16 ) * sx, posy() + rng( 0, 16 ) * sy, rng( minz, maxz ) );
×
3080
    }
3081
    move_pause();
×
3082
}
3083

3084
void npc::guard_current_pos()
×
3085
{
3086
    goal = global_omt_location();
×
3087
    guard_pos = global_square_location();
×
3088
}
3089

3090
std::string npc_action_name( npc_action action )
2✔
3091
{
3092
    switch( action ) {
2✔
3093
        case npc_undecided:
3094
            return _( "Undecided" );
×
3095
        case npc_pause:
3096
            return _( "Pause" );
×
3097
        case npc_reload:
3098
            return _( "Reload" );
×
3099
        case npc_sleep:
3100
            return _( "Sleep" );
×
3101
        case npc_pickup:
3102
            return _( "Pick up items" );
×
3103
        case npc_wield_melee:
3104
            return _( "Wield melee weapon" );
×
3105
        case npc_wield_loaded_gun:
3106
            return _( "Wield loaded gun" );
×
3107
        case npc_wield_empty_gun:
3108
            return _( "Wield empty gun" );
×
3109
        case npc_heal:
3110
            return _( "Heal self" );
×
3111
        case npc_use_painkiller:
3112
            return _( "Use painkillers" );
×
3113
        case npc_drop_items:
3114
            return _( "Drop items" );
×
3115
        case npc_flee:
3116
            return _( "Flee" );
×
3117
        case npc_melee:
3118
            return _( "Melee" );
×
3119
        case npc_reach_attack:
3120
            return _( "Reach attack" );
×
3121
        case npc_aim:
3122
            return _( "Aim" );
×
3123
        case npc_shoot:
3124
            return _( "Shoot" );
×
3125
        case npc_look_for_player:
3126
            return _( "Look for player" );
×
3127
        case npc_heal_player:
3128
            return _( "Heal player" );
×
3129
        case npc_follow_player:
3130
            return _( "Follow player" );
1✔
3131
        case npc_follow_embarked:
3132
            return _( "Follow player (embarked)" );
1✔
3133
        case npc_talk_to_player:
3134
            return _( "Talk to player" );
×
3135
        case npc_mug_player:
3136
            return _( "Mug player" );
×
3137
        case npc_goto_destination:
3138
            return _( "Go to destination" );
×
3139
        case npc_avoid_friendly_fire:
3140
            return _( "Avoid friendly fire" );
×
3141
        case npc_escape_explosion:
3142
            return _( "Escape explosion" );
×
3143
        default:
3144
            return "Unnamed action";
×
3145
    }
3146
}
3147

3148
void print_action( const char *prepend, npc_action action )
18✔
3149
{
3150
    if( action != npc_undecided ) {
18✔
3151
        add_msg( m_debug, prepend, npc_action_name( action ).c_str() );
×
3152
    }
3153
}
18✔
3154

3155
const Creature *npc::current_target() const
×
3156
{
3157
    return ai_cache.target.get();
30✔
3158
}
3159

3160
Creature *npc::current_target()
×
3161
{
3162
    return const_cast<Creature *>( const_cast<const npc *>( this )->current_target() );
×
3163
}
3164

3165
// Maybe TODO: Move to Character method and use map methods
3166
body_part bp_affected( npc &who, const efftype_id &effect_type )
×
3167
{
3168
    body_part ret = num_bp;
×
3169
    int highest_intensity = INT_MIN;
×
3170
    for( const body_part bp : all_body_parts ) {
×
3171
        const auto &eff = who.get_effect( effect_type, bp );
×
3172
        if( !eff.is_null() && eff.get_intensity() > highest_intensity ) {
×
3173
            ret = bp;
×
3174
            highest_intensity = eff.get_intensity();
×
3175
        }
3176
    }
3177

3178
    return ret;
×
3179
}
3180

3181
bool npc::complain_about( const std::string &issue, const time_duration &dur,
×
3182
                          const std::string &speech, const bool force )
3183
{
3184
    // Don't have a default constructor for time_point, so accessing it in the
3185
    // complaints map is a bit difficult, those lambdas should cover it.
3186
    const auto complain_since = [this]( const std::string & key, const time_duration & d ) {
×
3187
        const auto iter = complaints.find( key );
×
3188
        return iter == complaints.end() || iter->second < calendar::turn - d;
×
3189
    };
3190
    const auto set_complain_since = [this]( const std::string & key ) {
×
3191
        const auto iter = complaints.find( key );
×
3192
        if( iter == complaints.end() ) {
×
3193
            complaints.emplace( key, calendar::turn );
×
3194
        } else {
3195
            iter->second = calendar::turn;
×
3196
        }
3197
    };
3198

3199
    // Don't wake player up with non-serious complaints
3200
    const bool do_complain = ( rules.allow_complain && !g->u.in_sleep_state() ) || force;
×
3201

3202
    if( complain_since( issue, dur ) && do_complain ) {
×
3203
        say( speech );
×
3204
        set_complain_since( issue );
×
3205
        return true;
3206
    }
3207
    return false;
3208
}
3209

3210
bool npc::complain()
1✔
3211
{
3212
    static const std::string infected_string = "infected";
1✔
3213
    static const std::string fatigue_string = "fatigue";
1✔
3214
    static const std::string bite_string = "bite";
1✔
3215
    static const std::string bleed_string = "bleed";
1✔
3216
    static const std::string radiation_string = "radiation";
1✔
3217
    static const std::string hunger_string = "hunger";
1✔
3218
    static const std::string thirst_string = "thirst";
1✔
3219
    // TODO: Allow calling for help when scared
3220
    if( !is_following() || !g->u.sees( *this ) ) {
1✔
3221
        return false;
3222
    }
3223

3224
    // When infected, complain every (4-intensity) hours
3225
    // At intensity 3, ignore player wanting us to shut up
3226
    if( has_effect( effect_infected ) ) {
×
3227
        body_part bp = bp_affected( *this, effect_infected );
×
3228
        const auto &eff = get_effect( effect_infected, bp );
×
3229
        int intensity = eff.get_intensity();
×
3230
        const std::string speech = string_format( _( "My %s wound is infected..." ),
3231
                                   body_part_name( bp ).c_str() );
×
3232
        if( complain_about( infected_string, time_duration::from_hours( 4 - intensity ), speech,
×
3233
                            intensity >= 3 ) ) {
×
3234
            // Only one complaint per turn
3235
            return true;
×
3236
        }
3237
    }
3238

3239
    // When bitten, complain every hour, but respect restrictions
3240
    if( has_effect( effect_bite ) ) {
×
3241
        body_part bp = bp_affected( *this, effect_bite );
×
3242
        const std::string speech = string_format( _( "The bite wound on my %s looks bad." ),
3243
                                   body_part_name( bp ).c_str() );
×
3244
        if( complain_about( bite_string, 1_hours, speech ) ) {
×
3245
            return true;
×
3246
        }
3247
    }
3248

3249
    // When tired, complain every 30 minutes
3250
    // If massively tired, ignore restrictions
3251
    if( get_fatigue() > TIRED && complain_about( fatigue_string, 30_minutes, _( "<yawn>" ),
×
3252
            get_fatigue() > MASSIVE_FATIGUE - 100 ) )  {
×
3253
        return true;
3254
    }
3255

3256
    // Radiation every 10 minutes
3257
    if( radiation > 90 ) {
×
3258
        std::string speech = _( "I'm suffering from radiation sickness..." );
×
3259
        if( complain_about( radiation_string, 10_minutes, speech, radiation > 150 ) ) {
×
3260
            return true;
×
3261
        }
3262
    }
3263

3264
    // Hunger every 3-6 hours
3265
    // Since NPCs can't starve to death, respect the rules
3266
    if( get_hunger() > 160 &&
×
3267
        complain_about( hunger_string, std::max( 3_hours,
3268
                        time_duration::from_minutes( 60 * 8 - get_hunger() ) ), _( "<hungry>" ) ) ) {
×
3269
        return true;
3270
    }
3271

3272
    // Thirst every 2 hours
3273
    // Since NPCs can't dry to death, respect the rules
3274
    if( get_thirst() > 80 && complain_about( thirst_string, 2_hours, _( "<thirsty>" ) ) ) {
×
3275
        return true;
3276
    }
3277

3278
    //Bleeding every 5 minutes
3279
    if( has_effect( effect_bleed ) ) {
×
3280
        body_part bp = bp_affected( *this, effect_bleed );
×
3281
        std::string speech = string_format( _( "My %s is bleeding!" ), body_part_name( bp ).c_str() );
×
3282
        if( complain_about( bleed_string, 5_minutes, speech ) ) {
×
3283
            return true;
×
3284
        }
3285
    }
3286

3287
    return false;
3288
}
3289

3290
void npc::do_reload( item &it )
×
3291
{
3292
    item::reload_option reload_opt = select_ammo( it );
×
3293

3294
    if( !reload_opt ) {
×
3295
        debugmsg( "do_reload failed: no usable ammo for %s", it.tname().c_str() );
×
3296
        return;
×
3297
    }
3298

3299
    // Note: we may be reloading the magazine inside, not the gun itself
3300
    // Maybe @todo: allow reload functions to understand such reloads instead of const casts
3301
    item &target = const_cast<item &>( *reload_opt.target );
×
3302
    item_location &usable_ammo = reload_opt.ammo;
×
3303

3304
    long qty = std::max( 1l, std::min( usable_ammo->charges,
×
3305
                                       it.ammo_capacity() - it.ammo_remaining() ) );
×
3306
    int reload_time = item_reload_cost( it, *usable_ammo, qty );
×
3307
    // @todo: Consider printing this info to player too
3308
    const std::string ammo_name = usable_ammo->tname();
×
3309
    if( !target.reload( *this, std::move( usable_ammo ), qty ) ) {
×
3310
        debugmsg( "do_reload failed: item %s could not be reloaded with %ld charge(s) of %s",
×
3311
                  it.tname().c_str(), qty, ammo_name.c_str() );
×
3312
        return;
×
3313
    }
3314

3315
    moves -= reload_time;
×
3316
    recoil = MAX_RECOIL;
×
3317

3318
    if( g->u.sees( *this ) ) {
×
3319
        add_msg( _( "%1$s reloads their %2$s." ), name.c_str(), it.tname().c_str() );
×
3320
        sfx::play_variant_sound( "reload", it.typeId(), sfx::get_heard_volume( pos() ),
×
3321
                                 sfx::get_heard_angle( pos() ) );
×
3322
    }
3323

3324
    // Otherwise the NPC may not equip the weapon until they see danger
3325
    has_new_items = true;
×
3326
}
3327

3328
bool npc::adjust_worn()
8✔
3329
{
3330
    const auto covers_broken = [this]( const item & it, side s ) {
×
3331
        const auto covered = it.get_covered_body_parts( s );
×
3332
        for( size_t i = 0; i < num_hp_parts; i++ ) {
×
3333
            if( hp_cur[ i ] <= 0 && covered.test( hp_to_bp( hp_part( i ) ) ) ) {
×
3334
                return true;
3335
            }
3336
        }
3337
        return false;
3338
    };
8✔
3339

3340
    for( auto &elem : worn ) {
84✔
3341
        if( !elem.has_flag( "SPLINT" ) ) {
52✔
3342
            continue;
3343
        }
3344

3345
        if( !covers_broken( elem, elem.get_side() ) ) {
×
3346
            const bool needs_change = covers_broken( elem, opposite_side( elem.get_side() ) );
×
3347
            // Try to change side (if it makes sense), or take off.
3348
            if( ( needs_change && change_side( elem ) ) || takeoff( elem ) ) {
×
3349
                return true;
3350
            }
3351
        }
3352
    }
3353

3354
    return false;
3355
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc