Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: better define how NPCs generate starting weapon #4081

Merged
merged 3 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions data/json/npcs/items_generic.json
Original file line number Diff line number Diff line change
Expand Up @@ -311,20 +311,72 @@
"id": "npc_holster",
"items": [ [ "null", 50 ], [ "sholster", 10 ], [ "sheath", 10 ] ]
},
{
"type": "item_group",
"id": "npc_bashing",
"items": [ { "group": "survivor_bashing", "prob": 100 } ]
},
{
"type": "item_group",
"id": "npc_cutting",
"items": [ { "group": "survivor_cutting", "prob": 100 } ]
},
{
"type": "item_group",
"id": "npc_stabbing",
"items": [ { "group": "survivor_knife", "prob": 20 }, { "group": "survivor_stabbing", "prob": 80 } ]
},
{
"type": "item_group",
"id": "npc_pistol",
"items": [ { "group": "guns_pistol_common", "prob": 75 }, { "group": "guns_pistol_improvised", "prob": 25 } ]
},
{
"type": "item_group",
"id": "npc_shotgun",
"items": [ { "group": "guns_shotgun_common", "prob": 75 }, { "group": "guns_shotgun_improvised", "prob": 25 } ]
},
{
"type": "item_group",
"id": "npc_rifle",
"items": [
[ "crossbow", 15 ],
[ "compcrossbow", 10 ],
{ "group": "guns_rifle_common", "prob": 50 },
{ "group": "guns_rifle_improvised", "prob": 25 }
]
},
{
"type": "item_group",
"id": "npc_smg",
"items": [ { "group": "guns_smg_common", "prob": 50 }, { "group": "guns_smg_improvised", "prob": 50 } ]
},
{
"type": "item_group",
"id": "npc_launcher",
"items": [ { "group": "guns_launcher_improvised", "prob": 100 } ]
},
{
"type": "item_group",
"id": "npc_throw",
"items": [ [ "throwing_knife", 7 ], [ "throwing_axe", 4 ] ]
"items": [
[ "slingshot", 15 ],
[ "wristrocket", 10 ],
[ "sling", 15 ],
[ "staff_sling", 10 ],
[ "throwing_knife", 30 ],
[ "throwing_axe", 20 ]
]
},
{
"type": "item_group",
"id": "npc_archery",
"items": [ [ "crossbow", 50 ] ]
"items": [ [ "shortbow", 50 ], [ "compbow", 50 ] ]
},
{
"type": "item_group",
"id": "npc_unarmed",
"items": [ [ "knuckle_brass", 50 ], [ "punch_dagger", 50 ] ]
},
{
"type": "item_group",
Expand Down
22 changes: 11 additions & 11 deletions data/json/skills.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
"id": "archery",
"name": { "str": "archery" },
"description": "Your skill in using bow weapons, from hand-carved self bows to complex compound bows. Quiet and effective, they require strength of body and sight to wield, and are not terribly accurate over a long distance.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 20, "base_time": 80, "time_reduction_per_level": 6 },
"companion_combat_rank_factor": 1,
"companion_survival_rank_factor": 1,
Expand All @@ -156,7 +156,7 @@
"id": "launcher",
"name": { "str": "launchers" },
"description": "Your skill in using heavy weapons like rocket, grenade or missile launchers. These weapons have a variety of applications and may carry immense destructive power, but they are cumbersome and hard to manage.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 30, "base_time": 100, "time_reduction_per_level": 7 },
"display_category": "display_ranged"
},
Expand All @@ -165,7 +165,7 @@
"id": "pistol",
"name": { "str": "handguns" },
"description": "Handguns have poor accuracy compared to rifles, but are usually quick to fire and reload faster than other guns. They are very effective at close quarters, though unsuited for long range engagement.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 10, "base_time": 80, "time_reduction_per_level": 7 },
"display_category": "display_ranged",
"companion_skill_practice": [ { "skill": "hunting", "weight": 25 } ]
Expand All @@ -175,7 +175,7 @@
"id": "rifle",
"name": { "str": "rifles" },
"description": "Rifles have terrific range and accuracy compared to other firearms, but may be slow to fire and reload, and can prove difficult to use in close quarters. Fully automatic rifles can fire rapidly, but are harder to handle properly.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 15, "base_time": 75, "time_reduction_per_level": 6 },
"display_category": "display_ranged",
"companion_skill_practice": [ { "skill": "hunting", "weight": 45 } ]
Expand All @@ -185,7 +185,7 @@
"id": "shotgun",
"name": { "str": "shotguns" },
"description": "Shotguns are easy to shoot and can inflict massive damage, but their effectiveness and accuracy decline rapidly with range. Slugs can be loaded into shotguns to provide greater range, though they are somewhat inaccurate.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 15, "base_time": 75, "time_reduction_per_level": 6 },
"display_category": "display_ranged",
"companion_skill_practice": [ { "skill": "hunting", "weight": 25 } ]
Expand All @@ -195,7 +195,7 @@
"id": "smg",
"name": { "str": "submachine guns" },
"description": "Comprised of an automatic rifle carbine designed to fire a pistol cartridge, submachine guns can reload and fire quickly, sometimes in bursts, but they are relatively inaccurate and may be prone to mechanical failures.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 20, "base_time": 80, "time_reduction_per_level": 6 },
"display_category": "display_ranged",
"companion_skill_practice": [ { "skill": "hunting", "weight": 25 } ]
Expand All @@ -205,7 +205,7 @@
"id": "throw",
"name": { "str": "throwing" },
"description": "Your skill in throwing objects over a distance. Skill increases accuracy, and at higher levels, the range of a throw.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"time_to_attack": { "min_time": 50, "base_time": 220, "time_reduction_per_level": 25 },
"display_category": "display_ranged"
},
Expand All @@ -232,7 +232,7 @@
"id": "bashing",
"name": { "str": "bashing weapons" },
"description": "Your skill in fighting with blunt weaponry, from rocks and sticks to baseball bats and the butts of rifles. Skill increases damage, and higher levels will improve the accuracy of an attack.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"companion_combat_rank_factor": 1,
"display_category": "display_melee",
"companion_skill_practice": [ { "skill": "hunting", "weight": 10 }, { "skill": "combat", "weight": 10 } ]
Expand All @@ -242,7 +242,7 @@
"id": "cutting",
"name": { "str": "cutting weapons" },
"description": "Your skill in fighting with weaponry designed to cut, hack and slash an opponent. Lower levels of skill increase accuracy and damage, while higher levels will help to bypass heavy armor and thick hides.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"companion_combat_rank_factor": 1,
"display_category": "display_melee",
"companion_skill_practice": [ { "skill": "hunting", "weight": 10 }, { "skill": "combat", "weight": 10 } ]
Expand All @@ -260,7 +260,7 @@
"id": "stabbing",
"name": { "str": "piercing weapons" },
"description": "Your skill in fighting with knives, spears and other such stabbing implements. Skill increases attack accuracy as well as the chance of inflicting a deadly and critical blow.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"companion_combat_rank_factor": 1,
"display_category": "display_melee",
"companion_skill_practice": [ { "skill": "hunting", "weight": 10 }, { "skill": "combat", "weight": 10 } ]
Expand All @@ -270,7 +270,7 @@
"id": "unarmed",
"name": { "str": "unarmed combat" },
"description": "Your skill in hand-to-hand fighting. For the unskilled, it's a good way to get hurt, but those with enough practice can perform special blows and techniques to quickly dispatch enemies.",
"tags": [ "combat_skill" ],
"tags": [ "combat_skill", "weapon_skill" ],
"companion_combat_rank_factor": 1,
"companion_survival_rank_factor": 1,
"display_category": "display_melee",
Expand Down
54 changes: 32 additions & 22 deletions src/npc.cpp
scarf005 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,14 @@ static const skill_id skill_archery( "archery" );
static const skill_id skill_barter( "barter" );
static const skill_id skill_bashing( "bashing" );
static const skill_id skill_cutting( "cutting" );
static const skill_id skill_launcher( "launcher" );
static const skill_id skill_pistol( "pistol" );
static const skill_id skill_rifle( "rifle" );
static const skill_id skill_shotgun( "shotgun" );
static const skill_id skill_smg( "smg" );
static const skill_id skill_stabbing( "stabbing" );
static const skill_id skill_throw( "throw" );
static const skill_id skill_unarmed( "unarmed" );

static const bionic_id bio_eye_optic( "bio_eye_optic" );
static const bionic_id bio_memory( "bio_memory" );
Expand Down Expand Up @@ -790,7 +792,7 @@ skill_id npc::best_skill() const
skill_id highest_skill( skill_id::NULL_ID() );

for( const auto &p : *_skills ) {
if( p.first.obj().is_combat_skill() ) {
if( p.first.obj().is_weapon_skill() ) {
const int level = p.second.level();
if( level > highest_level ) {
highest_level = level;
Expand Down Expand Up @@ -818,6 +820,33 @@ int npc::best_skill_level() const
return highest_level;
}

namespace
{

const std::map<skill_id, std::string> skill_to_weapons = {
{ skill_bashing, "bashing" },
{ skill_cutting, "cutting" },
{ skill_unarmed, "unarmed" },
{ skill_throw, "throw" },
{ skill_archery, "archery" },
{ skill_launcher, "launcher" },
{ skill_pistol, "pistol" },
{ skill_shotgun, "shotgun" },
{ skill_smg, "smg" },
{ skill_rifle, "rifle" },
{ skill_stabbing, "stabbing" }
};

/// if NPC has no suitable skills default to stabbing weapon
auto best_weapon_category( const skill_id &best_skill ) -> std::string
{
const auto &res = skill_to_weapons.find( best_skill );

return res != skill_to_weapons.end() ? res->second : "stabbing";
}

} // namespace

void npc::starting_weapon( const npc_class_id &type )
{
if( item_group::group_is_defined( type->weapon_override ) ) {
Expand All @@ -826,27 +855,8 @@ void npc::starting_weapon( const npc_class_id &type )
}

const skill_id best = best_skill();

// if NPC has no suitable skills default to stabbing weapon
if( !best || best == skill_stabbing ) {
set_primary_weapon( random_item_from( type, "stabbing", item_group_id( "survivor_stabbing" ) ) );
} else if( best == skill_bashing ) {
set_primary_weapon( random_item_from( type, "bashing", item_group_id( "survivor_bashing" ) ) );
} else if( best == skill_cutting ) {
set_primary_weapon( random_item_from( type, "cutting", item_group_id( "survivor_cutting" ) ) );
} else if( best == skill_throw ) {
set_primary_weapon( random_item_from( type, "throw" ) );
} else if( best == skill_archery ) {
set_primary_weapon( random_item_from( type, "archery" ) );
} else if( best == skill_pistol ) {
set_primary_weapon( random_item_from( type, "pistol", item_group_id( "guns_pistol_common" ) ) );
} else if( best == skill_shotgun ) {
set_primary_weapon( random_item_from( type, "shotgun", item_group_id( "guns_shotgun_common" ) ) );
} else if( best == skill_smg ) {
set_primary_weapon( random_item_from( type, "smg", item_group_id( "guns_smg_common" ) ) );
} else if( best == skill_rifle ) {
set_primary_weapon( random_item_from( type, "rifle", item_group_id( "guns_rifle_common" ) ) );
}
const std::string category = best_weapon_category( best );
set_primary_weapon( random_item_from( type, category ) );

if( primary_weapon().is_gun() ) {
primary_weapon().ammo_set( primary_weapon().ammo_default() );
Expand Down
7 changes: 7 additions & 0 deletions src/skill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ bool Skill::is_contextual_skill() const
return _tags.count( contextual_skill ) > 0;
}

// used to check NPC weapon skills for determining starting weapon
bool Skill::is_weapon_skill() const
{
static const std::string weapon_skill( "weapon_skill" );
return _tags.count( weapon_skill ) > 0;
}

void SkillLevel::train( int amount, bool skip_scaling )
{
// Working off rust to regain levels goes twice as fast as reaching levels in the first place
Expand Down
1 change: 1 addition & 0 deletions src/skill.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class Skill

bool is_combat_skill() const;
bool is_contextual_skill() const;
bool is_weapon_skill() const;

// Required for LUA
inline bool operator<( const Skill &rhs ) const {
Expand Down
Loading