Skip to content

Commit

Permalink
implement .22 perk
Browse files Browse the repository at this point in the history
  • Loading branch information
GuardianDll committed Sep 18, 2024
1 parent c6700ba commit dcda137
Show file tree
Hide file tree
Showing 22 changed files with 126 additions and 2 deletions.
1 change: 1 addition & 0 deletions data/json/monster_weakpoints/abomination_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
{
"id": "armor_thick",
"name": "a thick part of its armor",
"is_good": false,
"armor_mult": { "all": 2.0 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "cut": 1.5 },
Expand Down
2 changes: 2 additions & 0 deletions data/json/monster_weakpoints/arthropod_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
{
"id": "armor_thick",
"name": "a thick part of the exoskeleton",
"is_good": false,
"armor_mult": { "all": 1.5 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "cut": 1.5 },
Expand Down Expand Up @@ -329,6 +330,7 @@
{
"id": "armor_thick",
"name": "a thick part of its armor",
"is_good": false,
"armor_mult": { "all": 1.5 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "cut": 1.5 },
Expand Down
1 change: 1 addition & 0 deletions data/json/monster_weakpoints/cyborg_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
{
"id": "hard_point",
"name": "a particularly thick patch of armor",
"is_good": false,
"armor_mult": { "all": 1.25 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down
3 changes: 3 additions & 0 deletions data/json/monster_weakpoints/generic_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
{
"id": "hard_hide",
"name": "a particularly thick patch of hide",
"is_good": false,
"armor_mult": { "all": 1.25 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down Expand Up @@ -52,6 +53,7 @@
{
"id": "hard_point",
"name": "a particularly thick patch of bone",
"is_good": false,
"armor_mult": { "all": 1.25 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down Expand Up @@ -83,6 +85,7 @@
{
"id": "hard_point",
"name": "a strong, rigid chunk of metal",
"is_good": false,
"armor_mult": { "all": 1.4 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down
4 changes: 4 additions & 0 deletions data/json/monster_weakpoints/humanoid_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@
{
"id": "armour_plate_bullet",
"name": "the body armor",
"is_good": false,
"armor_mult": { "cut": 1.5, "stab": 1.5, "bash": 1.5 },
"coverage_mult": { "ranged": 0.8, "melee": 0 },
"//": "Note that most bullet hits on an armour plate probably shatter it, but not all of them shatter it enough to matter for future attacks.",
Expand Down Expand Up @@ -315,6 +316,7 @@
{
"id": "armour_plate_melee",
"name": "the body armor",
"is_good": false,
"armor_mult": { "cut": 1.3, "stab": 1.15, "bash": 1.15 },
"coverage_mult": { "ranged": 0, "melee": 0.8 },
"//": "Note that most bullet hits on an armour plate probably shatter it, but not all of them shatter it enough to matter for future attacks.",
Expand Down Expand Up @@ -446,6 +448,7 @@
"id": "helmet",
"//": "the hard part of the helmet is actually the opposite of a weakpoint.",
"name": "the helmet",
"is_good": false,
"armor_mult": { "physical": 1.5 },
"crit_mult": { "all": 0.5 },
"coverage_mult": { "melee": 0.75 },
Expand Down Expand Up @@ -520,6 +523,7 @@
"id": "helmet",
"name": "the helmet",
"//": "the hard part of the helmet is actually the opposite of a weakpoint.",
"is_good": false,
"armor_mult": { "physical": 1.5 },
"crit_mult": { "all": 0.5 },
"coverage_mult": { "melee": 0.75 },
Expand Down
1 change: 1 addition & 0 deletions data/json/monster_weakpoints/slime_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
{
"id": "insensitive_spot",
"name": "a spot with virtually nothing to damage",
"is_good": false,
"armor_mult": { "all": 1.25 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down
1 change: 1 addition & 0 deletions data/json/monster_weakpoints/triffid_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
{
"id": "thick bark",
"name": "a particularly thick patch of the bark",
"is_good": false,
"armor_mult": { "all": 1.25 },
"crit_mult": { "all": 0.75 },
"coverage_mult": { "melee": 0.75 },
Expand Down
2 changes: 2 additions & 0 deletions data/json/monster_weakpoints/yrax_weakpoints.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
{
"id": "heavy_armor",
"name": "a segment of sloped armor",
"is_good": false,
"armor_mult": { "all": 1 },
"crit_mult": { "all": 0.1 },
"coverage_mult": { "melee": 1.5 },
Expand Down Expand Up @@ -51,6 +52,7 @@
{
"id": "heavy_armor",
"name": "a segment of sloped armor",
"is_good": false,
"armor_mult": { "all": 5 },
"crit_mult": { "all": 0.1 },
"coverage_mult": { "melee": 0.1 },
Expand Down
16 changes: 16 additions & 0 deletions data/mods/BombasticPerks/perkmenu.json
Original file line number Diff line number Diff line change
Expand Up @@ -1380,6 +1380,22 @@
],
"topic": "TALK_PERK_MENU_SELECT_PLAYSTYLE"
},
{
"condition": { "not": { "u_has_trait": "22_is_cool" } },
"text": "Gain [<trait_name:22_is_cool>]",
"effect": [
{ "set_string_var": "<trait_name:22_is_cool>", "target_var": { "context_val": "trait_name" } },
{ "set_string_var": "<trait_description:22_is_cool>", "target_var": { "context_val": "trait_description" } },
{ "set_string_var": "22_is_cool", "target_var": { "context_val": "trait_id" } },
{
"set_string_var": "No Requirements",
"target_var": { "context_val": "trait_requirement_description" },
"i18n": true
},
{ "set_condition": "perk_condition", "condition": { "math": [ "0", "==", "0" ] } }
],
"topic": "TALK_PERK_MENU_SELECT_PLAYSTYLE"
},
{
"condition": { "not": { "u_has_trait": "perk_empath" } },
"text": "Gain [<trait_name:perk_empath>]",
Expand Down
16 changes: 16 additions & 0 deletions data/mods/BombasticPerks/perks.json
Original file line number Diff line number Diff line change
Expand Up @@ -1198,5 +1198,21 @@
]
}
]
},
{
"type": "mutation",
"id": "22_is_cool",
"name": { "str": "Twenty two weakpoints" },
"description": "You always appreciated the size of this little fella named \"Dot Two Two Long Rifle\", but they laughed at you. Not anymore! You found that small size of a bullet is perfect to hit into little spots between armor or narrow places. Gives additional armor penetration and quadruple your chanses to hit a weakpoint if you use .22 weapon.",
"points": 0,
"purifiable": false,
"valid": false,
"category": [ "perk" ],
"enchantments": [
{
"condition": { "u_has_wielded_with_ammotype": "22" },
"values": [ { "value": "RANGED_ARMOR_PENETRATION", "add": 5 }, { "value": "WEAKPOINT_ACCURACY", "multiply": 3 } ]
}
]
}
]
17 changes: 17 additions & 0 deletions doc/EFFECT_ON_CONDITION.md
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,23 @@ check do you wield a gun with `pistol` skill
{ "u_has_wielded_with_skill": "pistol" }
```

### `u_has_wielded_with_ammotype``npc_has_wielded_with_ammotype`
- type: string or [variable object](#variable-object)
- return true if alpha or beta talker wield an item that can have this ammo type
- works with items that allow multiple ammo types

#### Valid talkers:

| Avatar | Character | NPC | Monster | Furniture | Item |
| ------ | --------- | --------- | ---- | ------- | --- |
| ✔️ | ✔️ | ✔️ ||||

#### Examples
check do you wield a gun with `22` ammo type (.22 LR)
```json
{ "u_has_wielded_with_ammotype": "22" }
```

### `u_can_see``npc_can_see`
- type: simple string
- return true if alpha or beta talker can see (not blind)
Expand Down
2 changes: 2 additions & 0 deletions doc/MAGIC.md
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,7 @@ Character status value | Description
`PHASE_DISTANCE` | Distance the character is able to teleport through impassible terrain. Values less than 1 do nothing and the max distance is 48 tiles.
`POWER_TRICKLE` | Generates this amount of millijoules each second. Default value is zero, so better to use `add`
`RANGE` | Modifies your characters range with firearms
`RANGED_ARMOR_PENETRATION` | Adds armor penetration to ranged attacks.
`RANGED_DAMAGE` | Adds damage to ranged attacks.
`RANGE_DODGE` | Chance to dodge projectile attack, no matter of it's speed; Consumes dodges similarly to melee dodges, and fails, if character has no dodges left. `add` and `multiply` behave equally. `add: 0.5` would result in 50% chance to avoid projectile
`READING_EXP` | Changes the minimum you learn from each reading increment.
Expand Down Expand Up @@ -912,6 +913,7 @@ Character status value | Description
`VITAMIN_ABSORB_MOD` | Increases amount of vitamins obtained from the food
`VOMIT_MUL` | Affects your chances to vomit.
`WEAKNESS_TO_WATER` | Amount of damage character gets when wet, once per second; scales with wetness, being 50% wet deal only half of damage; negative values restore hp; flat number with default value of 0, so `multiply` is useful only in combination with `add`; Works with float numbers, so `"add": -0.3` would result in restoring 1 hp with 30% change, and 70% chance to do nothing
`WEAKPOINT_ACCURACY` | Increases the coverage of every weakpoint you hit, therefore, increasing chances to hit said weakpoint. Works only if weakpoint has `"is_good": true` (all weakpoints have it true by default)
`WEAPON_DISPERSION` | Positive value increase the dispersion, negative decrease one.


Expand Down
1 change: 1 addition & 0 deletions doc/MONSTERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ Field | Description
`id` | id of the weakpoint. Defaults to `name`, if not specified.
`name` | name of the weakpoint. Used in hit messages.
`coverage` | base percentage chance of hitting the weakpoint. (e.g. A coverage of 5 means a 5% base chance of hitting the weakpoint)
`is_good` | marks mutation, that is beneficial for you to hit (like headshot); false means it is a bad weakpoint for you to hit (like thick piece of armor); default true;
`coverage_mult` | object mapping weapon types to constant coverage multipliers.
`difficulty` | object mapping weapon types to difficulty values. Difficulty acts as soft "gate" on the attacker's skill. If the the attacker has skill equal to the difficulty, coverage is reduced to 50%.
`armor_mult` | object mapping damage types to multipliers on the monster's base protection, when hitting the weakpoint.
Expand Down
13 changes: 13 additions & 0 deletions src/condition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1946,13 +1946,25 @@ conditional_t::func f_has_wielded_with_weapon_category( const JsonObject &jo,
conditional_t::func f_has_wielded_with_skill( const JsonObject &jo, std::string_view member,
bool is_npc )
{
// ideally all this "u wield with X" should be moved to some mutator
// and a single effect should check mutator applied to the item in your hands
str_or_var w_skill = get_str_or_var( jo.get_member( member ), member, true );
return [w_skill, is_npc]( dialogue const & d ) {

return d.actor( is_npc )->wielded_with_weapon_skill( skill_id( w_skill.evaluate( d ) ) );
};
}

conditional_t::func f_has_wielded_with_ammotype( const JsonObject &jo, std::string_view member,
bool is_npc )
{
str_or_var w_ammotype = get_str_or_var( jo.get_member( member ), member, true );
return [w_ammotype, is_npc]( dialogue const & d ) {

return d.actor( is_npc )->wielded_with_item_ammotype( ammotype( w_ammotype.evaluate( d ) ) );
};
}

conditional_t::func f_can_see( bool is_npc )
{
return [is_npc]( dialogue const & d ) {
Expand Down Expand Up @@ -2542,6 +2554,7 @@ parsers = {
{"u_has_wielded_with_flag", "npc_has_wielded_with_flag", jarg::member, &conditional_fun::f_has_wielded_with_flag },
{"u_has_wielded_with_weapon_category", "npc_has_wielded_with_weapon_category", jarg::member, &conditional_fun::f_has_wielded_with_weapon_category },
{"u_has_wielded_with_skill", "npc_has_wielded_with_skill", jarg::member, &conditional_fun::f_has_wielded_with_skill },
{"u_has_wielded_with_ammotype", "npc_has_wielded_with_ammotype", jarg::member, &conditional_fun::f_has_wielded_with_ammotype },
{"u_is_on_terrain", "npc_is_on_terrain", jarg::member, &conditional_fun::f_is_on_terrain },
{"u_is_on_terrain_with_flag", "npc_is_on_terrain_with_flag", jarg::member, &conditional_fun::f_is_on_terrain_with_flag },
{"u_is_in_field", "npc_is_in_field", jarg::member, &conditional_fun::f_is_in_field },
Expand Down
2 changes: 2 additions & 0 deletions src/magic_enchantment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ namespace io
case enchant_vals::mod::PAIN_PENALTY_MOD_SPEED: return "PAIN_PENALTY_MOD_SPEED";
case enchant_vals::mod::MELEE_DAMAGE: return "MELEE_DAMAGE";
case enchant_vals::mod::RANGED_DAMAGE: return "RANGED_DAMAGE";
case enchant_vals::mod::RANGED_ARMOR_PENETRATION: return "RANGED_ARMOR_PENETRATION";
case enchant_vals::mod::DODGE_CHANCE: return "DODGE_CHANCE";
case enchant_vals::mod::BONUS_BLOCK: return "BONUS_BLOCK";
case enchant_vals::mod::BONUS_DODGE: return "BONUS_DODGE";
Expand Down Expand Up @@ -202,6 +203,7 @@ namespace io
case enchant_vals::mod::SWEAT_MULTIPLIER: return "SWEAT_MULTIPLIER";
case enchant_vals::mod::STAMINA_REGEN_MOD: return "STAMINA_REGEN_MOD";
case enchant_vals::mod::MOVEMENT_EXERTION_MODIFIER: return "MOVEMENT_EXERTION_MODIFIER";
case enchant_vals::mod::WEAKPOINT_ACCURACY: return "WEAKPOINT_ACCURACY";
case enchant_vals::mod::NUM_MOD: break;
}
cata_fatal( "Invalid enchant_vals::mod" );
Expand Down
2 changes: 2 additions & 0 deletions src/magic_enchantment.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ enum class mod : int {
BONUS_BLOCK,
MELEE_DAMAGE,
RANGED_DAMAGE,
RANGED_ARMOR_PENETRATION,
ATTACK_NOISE,
SHOUT_NOISE,
FOOTSTEP_NOISE,
Expand Down Expand Up @@ -179,6 +180,7 @@ enum class mod : int {
SWEAT_MULTIPLIER,
STAMINA_REGEN_MOD,
MOVEMENT_EXERTION_MODIFIER,
WEAKPOINT_ACCURACY,
NUM_MOD
};
} // namespace enchant_vals
Expand Down
2 changes: 2 additions & 0 deletions src/ranged.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,8 @@ int Character::fire_gun( const tripoint &target, int shots, item &gun, item_loca

for( damage_unit &elem : proj.impact.damage_units ) {
elem.amount = enchantment_cache->modify_value( enchant_vals::mod::RANGED_DAMAGE, elem.amount );
elem.res_pen = enchantment_cache->modify_value( enchant_vals::mod::RANGED_ARMOR_PENETRATION,
elem.amount );
}

dispersion_sources dispersion = total_gun_dispersion( gun, recoil_total(), proj.shot_spread );
Expand Down
3 changes: 3 additions & 0 deletions src/talker.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ class talker
virtual bool wielded_with_weapon_skill( const skill_id & ) const {
return false;
}
virtual bool wielded_with_item_ammotype( const ammotype & ) const {
return false;
}
virtual bool has_item_with_flag( const flag_id & ) const {
return false;
}
Expand Down
21 changes: 21 additions & 0 deletions src/talker_character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,27 @@ bool talker_character_const::wielded_with_weapon_skill( const skill_id &w_skill
}
}

bool talker_character_const::wielded_with_item_ammotype( const ammotype &w_ammotype ) const
{
if( !me_chr_const->get_wielded_item() ) {
return false;
}
item *it = me_chr_const->get_wielded_item().get_item();
if( it->ammo_types().empty() ) {
return false;
}
std::set<ammotype> it_ammotype = it->ammo_types();
bool match = false;

for( ammotype ammo : it_ammotype ) {
if( ammo == w_ammotype ) {
match = true;
}
return match;
}

}

bool talker_character_const::has_item_with_flag( const flag_id &flag ) const
{
return me_chr_const->cache_has_item_with( flag );
Expand Down
1 change: 1 addition & 0 deletions src/talker_character.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class talker_character_const: public talker_cloner<talker_character_const>
bool wielded_with_flag( const flag_id &flag ) const override;
bool wielded_with_weapon_category( const weapon_category_id &w_cat ) const override;
bool wielded_with_weapon_skill( const skill_id &w_skill ) const override;
bool wielded_with_item_ammotype( const ammotype &w_ammotype ) const override;
bool has_item_with_flag( const flag_id &flag ) const override;
int item_rads( const flag_id &flag, aggregate_type agg_func ) const override;

Expand Down
15 changes: 13 additions & 2 deletions src/weakpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,9 @@ void weakpoint::load( const JsonObject &jo )
assign( jo, "id", id );
assign( jo, "name", name );
assign( jo, "coverage", coverage, false, 0.0f, 100.0f );
if( jo.has_bool( "is_good" ) ) {
assign( jo, "is_good", is_good );
}
if( jo.has_object( "armor_mult" ) ) {
armor_mult = load_damage_map( jo.get_object( "armor_mult" ) );
}
Expand Down Expand Up @@ -536,8 +539,16 @@ float weakpoint::hit_chance( const weakpoint_attack &attack ) const
// exceeding the difficulty.
float diff = attack.wp_skill - difficulty.of( attack );
float difficulty_mult = 0.5f * ( 1.0f + erf( diff / ( 2.0f * sqrt( 2.0f ) ) ) );
// Compute the total value
return constant_mult * difficulty_mult * coverage;
float final_coverage;

if( attack.source && attack.source->as_character() && is_good ) {
final_coverage = attack.source->as_character()->enchantment_cache->modify_value(
enchant_vals::mod::WEAKPOINT_ACCURACY, coverage );
} else {
final_coverage = coverage;
}

return constant_mult * difficulty_mult * final_coverage;
}

// Reweighs the probability distribution of hitting a weakpoint.
Expand Down
2 changes: 2 additions & 0 deletions src/weakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ struct weakpoint {
translation name;
// Percent chance of hitting the weakpoint. Can be increased by skill.
float coverage = 100.0f;
// Separate wp that benefit attacker and hurt monster from wp that do not
bool is_good = true;
// Multiplier for existing armor values. Defaults to 1.
std::unordered_map<damage_type_id, float> armor_mult;
// Flat penalty to armor values. Applied after the multiplier.
Expand Down

0 comments on commit dcda137

Please sign in to comment.