static void equip_shooter( npc &shooter, std::vector<std::string> apparel ) { tripoint shooter_pos( 60, 60, 0 ); shooter.setpos( shooter_pos ); shooter.worn.clear(); shooter.inv.clear(); for( const std::string article : apparel ) { shooter.wear_item( item( article ) ); } }
bool vehicle_part::set_crew( const npc &who ) { if( who.is_dead_state() || !who.is_friend() ) { return false; } if( is_broken() || ( !is_seat() && !is_turret() ) ) { return false; } crew_id = who.getID(); return true; }
void test_needs( const npc &who, const numeric_interval<int> &hunger, const numeric_interval<int> &thirst, const numeric_interval<int> &fatigue ) { CHECK( who.get_hunger() <= hunger.max ); CHECK( who.get_hunger() >= hunger.min ); CHECK( who.get_thirst() <= thirst.max ); CHECK( who.get_thirst() >= thirst.min ); CHECK( who.get_fatigue() <= fatigue.max ); CHECK( who.get_fatigue() >= fatigue.min ); }
void talk_function::npc_thankful( npc &p ) { if( p.get_attitude() == NPCATT_MUG || p.get_attitude() == NPCATT_WAIT_FOR_LEAVE || p.get_attitude() == NPCATT_FLEE || p.get_attitude() == NPCATT_KILL || p.get_attitude() == NPCATT_FLEE_TEMP ) { p.set_attitude( NPCATT_NULL ); } if( p.chatbin.first_topic != "TALK_FRIEND" ) { p.chatbin.first_topic = "TALK_STRANGER_FRIENDLY"; } p.personality.aggression -= 1; }
static void arm_shooter( npc &shooter, std::string gun_type, std::vector<std::string> mods = {} ) { shooter.remove_weapon(); itype_id gun_id( gun_type ); // Give shooter a loaded gun of the requested type. item &gun = shooter.i_add( item( gun_id ) ); const itype_id ammo_id = gun.ammo_default(); if( gun.magazine_integral() ) { item &ammo = shooter.i_add( item( ammo_id, calendar::turn, gun.ammo_capacity() ) ); REQUIRE( gun.is_reloadable_with( ammo_id ) ); REQUIRE( shooter.can_reload( gun, ammo_id ) ); gun.reload( shooter, item_location( shooter, &ammo ), gun.ammo_capacity() ); } else { const itype_id magazine_id = gun.magazine_default(); item &magazine = shooter.i_add( item( magazine_id ) ); item &ammo = shooter.i_add( item( ammo_id, calendar::turn, magazine.ammo_capacity() ) ); REQUIRE( magazine.is_reloadable_with( ammo_id ) ); REQUIRE( shooter.can_reload( magazine, ammo_id ) ); magazine.reload( shooter, item_location( shooter, &ammo ), magazine.ammo_capacity() ); gun.reload( shooter, item_location( shooter, &magazine ), magazine.ammo_capacity() ); } for( auto mod : mods ) { gun.contents.push_back( item( itype_id( mod ) ) ); } shooter.wield( gun ); }
void talk_function::hostile( npc &p ) { if( p.get_attitude() == NPCATT_KILL ) { return; } if( p.sees( g->u ) ) { add_msg( _( "%s turns hostile!" ), p.name ); } g->u.add_memorial_log( pgettext( "memorial_male", "%s became hostile." ), pgettext( "memorial_female", "%s became hostile." ), p.name ); p.set_attitude( NPCATT_KILL ); }
void talk_function::give_equipment( npc &p ) { std::vector<item_pricing> giving = init_selling( p ); int chosen = -1; while( chosen == -1 && giving.size() > 1 ) { int index = rng( 0, giving.size() - 1 ); if( giving[index].price < p.op_of_u.owed ) { chosen = index; } giving.erase( giving.begin() + index ); } if( giving.empty() ) { popup( _( "%s has nothing to give!" ), p.name ); return; } if( chosen == -1 ) { chosen = 0; } item it = *giving[chosen].loc.get_item(); giving[chosen].loc.remove_item(); popup( _( "%1$s gives you a %2$s" ), p.name, it.tname() ); g->u.i_add( it ); p.op_of_u.owed -= giving[chosen].price; p.add_effect( effect_asked_for_item, 3_hours ); }
void talk_function::morale_chat_activity( npc &p ) { g->u.assign_activity( activity_id( "ACT_SOCIALIZE" ), 10000 ); g->u.activity.str_values.push_back( p.name ); add_msg( m_good, _( "That was a pleasant conversation with %s." ), p.disp_name() ); g->u.add_morale( MORALE_CHAT, rng( 3, 10 ), 10, 200_minutes, 5_minutes / 2 ); }
void talk_function::buy_100_logs( npc &p ) { std::vector<tripoint> places = overmap_buffer.find_all( g->u.global_omt_location(), "ranch_camp_67", 1, false ); if( places.empty() ) { debugmsg( "Couldn't find %s", "ranch_camp_67" ); return; } const auto &cur_om = g->get_cur_om(); std::vector<tripoint> places_om; for( auto &i : places ) { if( &cur_om == overmap_buffer.get_existing_om_global( i ) ) { places_om.push_back( i ); } } const tripoint site = random_entry( places_om ); tinymap bay; bay.load( site.x * 2, site.y * 2, site.z, false ); bay.spawn_item( 7, 15, "log", 100 ); bay.save(); p.add_effect( effect_currently_busy, 7_days ); add_msg( m_good, _( "%s drops the logs off in the garage..." ), p.name ); }
void talk_function::lead_to_safety( npc &p ) { const auto mission = mission::reserve_new( mission_type_id( "MISSION_REACH_SAFETY" ), -1 ); mission->assign( g->u ); p.goal = mission->get_target(); p.set_attitude( NPCATT_LEAD ); }
static dispersion_sources get_dispersion( npc &shooter, int aim_time ) { item &gun = shooter.weapon; dispersion_sources dispersion = shooter.get_weapon_dispersion( gun ); shooter.moves = aim_time; shooter.recoil = MAX_RECOIL; // Aim as well as possible within the provided time. shooter.aim(); if( aim_time > 0 ) { REQUIRE( shooter.recoil < MAX_RECOIL ); } dispersion.add_range( shooter.recoil ); return dispersion; }
void assert_encumbrance( npc &shooter, int encumbrance ) { for( body_part bp : bp_aBodyPart ) { INFO( "Body Part: " << body_part_name( bp ) ); REQUIRE( shooter.encumb( bp ) == encumbrance ); } }
void talk_function::goto_location( npc &p ) { int i = 0; uilist selection_menu; selection_menu.text = string_format( _( "Select a destination" ) ); std::vector<basecamp *> camps; tripoint destination; for( auto elem : g->u.camps ) { if( elem == p.global_omt_location() ) { continue; } cata::optional<basecamp *> camp = overmap_buffer.find_camp( elem.x, elem.y ); if( !camp ) { continue; } basecamp *temp_camp = *camp; camps.push_back( temp_camp ); } for( auto iter : camps ) { selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "%s at (%d, %d)" ), iter->camp_name(), iter->camp_omt_pos().x, iter->camp_omt_pos().y ); } selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "My current location" ) ); selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Cancel" ) ); selection_menu.selected = 0; selection_menu.query(); auto index = selection_menu.ret; if( index < 0 || index > static_cast<int>( camps.size() + 1 ) || index == static_cast<int>( camps.size() + 1 ) || index == UILIST_CANCEL ) { return; } if( index == static_cast<int>( camps.size() ) ) { destination = g->u.global_omt_location(); } else { auto selected_camp = camps[index]; destination = selected_camp->camp_omt_pos(); } p.set_companion_mission( p.global_omt_location(), "TRAVELLER", "travelling", destination ); p.mission = NPC_MISSION_TRAVELLING; p.chatbin.first_topic = "TALK_FRIEND_GUARD"; p.goal = destination; p.guard_pos = npc::no_goal_point; p.set_attitude( NPCATT_NULL ); return; }
void talk_function::stop_guard( npc &p ) { p.set_attitude( NPCATT_FOLLOW ); add_msg( _( "%s begins to follow you." ), p.name ); p.mission = NPC_MISSION_NULL; p.chatbin.first_topic = "TALK_FRIEND"; p.goal = npc::no_goal_point; p.guard_pos = npc::no_goal_point; }
void talk_function::stop_guard( npc &p ) { if( p.mission != NPC_MISSION_GUARD_ALLY ) { p.set_attitude( NPCATT_NULL ); p.mission = NPC_MISSION_NULL; return; } p.set_attitude( NPCATT_FOLLOW ); add_msg( _( "%s begins to follow you." ), p.name ); p.mission = NPC_MISSION_NULL; p.chatbin.first_topic = "TALK_FRIEND"; p.goal = npc::no_goal_point; p.guard_pos = npc::no_goal_point; cata::optional<basecamp *> bcp = overmap_buffer.find_camp( p.global_omt_location().x, p.global_omt_location().y ); if( bcp ) { basecamp *temp_camp = *bcp; temp_camp->validate_assignees(); } }
void talk_function::assign_base( npc &p ) { // TODO: decide what to do upon assign? maybe pathing required basecamp *camp = g->m.camp_at( g->u.pos() ); if( !camp ) { dbg( D_ERROR ) << "talk_function::assign_base: Assigned to base but no base here."; return; } add_msg( _( "%1$s waits at %2$s" ), p.name, camp->camp_name() ); p.mission = NPC_MISSION_BASE; p.set_attitude( NPCATT_NULL ); }
static void test_fast_shooting( npc &shooter, int moves, float hit_rate ) { const int fast_shooting_range = 3; const float hit_rate_cap = hit_rate + 0.3; dispersion_sources dispersion = get_dispersion( shooter, moves ); std::array<statistics, 5> fast_stats = firing_test( dispersion, fast_shooting_range, {{ -1, hit_rate, -1, -1, -1 }} ); std::array<statistics, 5> fast_stats_upper = firing_test( dispersion, fast_shooting_range, {{ -1, hit_rate_cap, -1, -1, -1 }} ); INFO( dispersion ); INFO( "Range: " << fast_shooting_range ); INFO( "Max aim speed: " << shooter.aim_per_move( shooter.weapon, MAX_RECOIL ) ); INFO( "Min aim speed: " << shooter.aim_per_move( shooter.weapon, shooter.recoil ) ); CAPTURE( shooter.weapon.gun_skill().str() ); CAPTURE( shooter.get_skill_level( shooter.weapon.gun_skill() ) ); CAPTURE( shooter.get_dex() ); CAPTURE( to_milliliter( shooter.weapon.volume() ) ); CAPTURE( fast_stats[1].n() ); CAPTURE( fast_stats[1].adj_wald_error() ); CHECK( fast_stats[1].avg() > hit_rate ); CAPTURE( fast_stats_upper[1].n() ); CAPTURE( fast_stats_upper[1].adj_wald_error() ); CHECK( fast_stats_upper[1].avg() < hit_rate_cap ); }
void talk_function::clear_mission( npc &p ) { mission *miss = p.chatbin.mission_selected; if( miss == nullptr ) { debugmsg( "clear_mission: mission_selected == nullptr" ); return; } const auto it = std::find( p.chatbin.missions_assigned.begin(), p.chatbin.missions_assigned.end(), miss ); if( it == p.chatbin.missions_assigned.end() ) { debugmsg( "clear_mission: mission_selected not in assigned" ); return; } p.chatbin.missions_assigned.erase( it ); if( p.chatbin.missions_assigned.empty() ) { p.chatbin.mission_selected = nullptr; } else { p.chatbin.mission_selected = p.chatbin.missions_assigned.front(); } if( miss->has_follow_up() ) { p.add_new_mission( mission::reserve_new( miss->get_follow_up(), p.getID() ) ); } }
void talk_function::give_aid( npc &p ) { p.add_effect( effect_currently_busy, 30_minutes ); for( int i = 0; i < num_hp_parts; i++ ) { const body_part bp_healed = player::hp_to_bp( hp_part( i ) ); g->u.heal( hp_part( i ), 5 * rng( 2, 5 ) ); if( g->u.has_effect( effect_bite, bp_healed ) ) { g->u.remove_effect( effect_bite, bp_healed ); } if( g->u.has_effect( effect_bleed, bp_healed ) ) { g->u.remove_effect( effect_bleed, bp_healed ); } if( g->u.has_effect( effect_infected, bp_healed ) ) { g->u.remove_effect( effect_infected, bp_healed ); } } g->u.assign_activity( activity_id( "ACT_WAIT_NPC" ), 10000 ); g->u.activity.str_values.push_back( p.name ); }
void basecamp::define_camp( npc &p ) { query_new_name(); omt_pos = p.global_omt_location(); sort_points = p.companion_mission_points; // purging the regions guarantees all entries will start with faction_base_ for( std::pair<std::string, tripoint> expansion : talk_function::om_building_region( omt_pos, 1, true ) ) { add_expansion( expansion.first, expansion.second ); } const std::string om_cur = overmap_buffer.ter( omt_pos ).id().c_str(); if( om_cur.find( prefix ) == std::string::npos ) { expansion_data e; e.type = "camp"; e.cur_level = 0; e.pos = omt_pos; expansions[ base_dir ] = e; } else { expansions[ base_dir ] = parse_expansion( om_cur, omt_pos ); } }
bool vehicle::assign_seat( vehicle_part &pt, const npc &who ) { if( !pt.is_seat() || !pt.set_crew( who ) ) { return false; } // NPC's can only be assigned to one seat in the vehicle for( auto &e : parts ) { if( &e == &pt ) { continue; // skip this part } if( e.is_seat() ) { const npc *n = e.crew(); if( n && n->getID() == who.getID() ) { e.unset_crew(); } } } return true; }
void talk_function::give_all_aid( npc &p ) { p.add_effect( effect_currently_busy, 30_minutes ); give_aid( p ); for( npc &guy : g->all_npcs() ) { if( rl_dist( guy.pos(), g->u.pos() ) < PICKUP_RANGE && guy.is_friend() ) { for( int i = 0; i < num_hp_parts; i++ ) { const body_part bp_healed = player::hp_to_bp( hp_part( i ) ); guy.heal( hp_part( i ), 5 * rng( 2, 5 ) ); if( guy.has_effect( effect_bite, bp_healed ) ) { guy.remove_effect( effect_bite, bp_healed ); } if( guy.has_effect( effect_bleed, bp_healed ) ) { guy.remove_effect( effect_bleed, bp_healed ); } if( guy.has_effect( effect_infected, bp_healed ) ) { guy.remove_effect( effect_infected, bp_healed ); } } } } }
static void test_shooting_scenario( npc &shooter, int min_quickdraw_range, int min_good_range, int max_good_range ) { { dispersion_sources dispersion = get_dispersion( shooter, 0 ); std::array<statistics, 5> minimum_stats = firing_test( dispersion, min_quickdraw_range, {{ 0.2, 0.1, -1, -1, -1 }} ); INFO( dispersion ); INFO( "Range: " << min_quickdraw_range ); INFO( "Max aim speed: " << shooter.aim_per_move( shooter.weapon, MAX_RECOIL ) ); INFO( "Min aim speed: " << shooter.aim_per_move( shooter.weapon, shooter.recoil ) ); CAPTURE( minimum_stats[0].n() ); CAPTURE( minimum_stats[0].adj_wald_error() ); CAPTURE( minimum_stats[1].n() ); CAPTURE( minimum_stats[1].adj_wald_error() ); CHECK( minimum_stats[0].avg() < 0.2 ); CHECK( minimum_stats[1].avg() < 0.1 ); } { dispersion_sources dispersion = get_dispersion( shooter, 300 ); std::array<statistics, 5> good_stats = firing_test( dispersion, min_good_range, {{ -1, -1, 0.5, -1, -1 }} ); INFO( dispersion ); INFO( "Range: " << min_good_range ); INFO( "Max aim speed: " << shooter.aim_per_move( shooter.weapon, MAX_RECOIL ) ); INFO( "Min aim speed: " << shooter.aim_per_move( shooter.weapon, shooter.recoil ) ); CAPTURE( good_stats[2].n() ); CAPTURE( good_stats[2].adj_wald_error() ); CHECK( good_stats[2].avg() > 0.5 ); } { dispersion_sources dispersion = get_dispersion( shooter, 500 ); std::array<statistics, 5> good_stats = firing_test( dispersion, max_good_range, {{ -1, -1, 0.1, -1, -1 }} ); INFO( dispersion ); INFO( "Range: " << max_good_range ); INFO( "Max aim speed: " << shooter.aim_per_move( shooter.weapon, MAX_RECOIL ) ); INFO( "Min aim speed: " << shooter.aim_per_move( shooter.weapon, shooter.recoil ) ); CAPTURE( good_stats[2].n() ); CAPTURE( good_stats[2].adj_wald_error() ); CHECK( good_stats[2].avg() < 0.1 ); } }
void talk_function::player_leaving( npc &p ) { p.set_attitude( NPCATT_WAIT_FOR_LEAVE ); p.patience = 15 - p.personality.aggression; }
void talk_function::leave( npc &p ) { add_msg( _( "%s leaves." ), p.name ); g->remove_npc_follower( p.getID() ); p.set_attitude( NPCATT_NULL ); }
void talk_function::stranger_neutral( npc &p ) { add_msg( _( "%s feels less threatened by you." ), p.name ); p.set_attitude( NPCATT_NULL ); p.chatbin.first_topic = "TALK_STRANGER_NEUTRAL"; }
void talk_function::start_mugging( npc &p ) { p.set_attitude( NPCATT_MUG ); add_msg( _( "Pause to stay still. Any movement may cause %s to attack." ), p.name ); }
model_npc.set_hunger( 0 ); model_npc.thirst = 0; model_npc.fatigue = 0; model_npc.remove_effect( "sleep" ); // An ugly hack to prevent NPC falling asleep during testing due to massive fatigue model_npc.set_mutation( "WEB_WEAVER" ); return model_npc; } TEST_CASE("on_load-sane-values") { npc model_npc = create_model(); SECTION("Awake for 10 minutes, gaining hunger/thirst/fatigue") { npc test_npc = model_npc; const int five_min_ticks = 2; on_load_test( test_npc, 0, MINUTES(5 * five_min_ticks) ); const int margin = 1; CHECK( test_npc.get_hunger() <= five_min_ticks + margin ); CHECK( test_npc.thirst <= five_min_ticks + margin ); CHECK( test_npc.fatigue <= five_min_ticks + margin ); CHECK( test_npc.get_hunger() >= five_min_ticks - margin ); CHECK( test_npc.thirst >= five_min_ticks - margin ); CHECK( test_npc.fatigue >= five_min_ticks - margin ); } SECTION("Awake for 2 days, gaining hunger/thirst/fatigue") { npc test_npc = model_npc; const int five_min_ticks = HOURS(2 * 24) / MINUTES(5);
void sane( const npc &who ) { CHECK( who.get_hunger() >= 0 ); CHECK( who.thirst >= 0 ); CHECK( who.fatigue >= -25 ); }
void talk_function::drop_weapon( npc &p ) { g->m.add_item_or_charges( p.pos(), p.remove_weapon() ); }