Skip to content

Commit 2c41bdf

Browse files
authored
Add ability to count character flags, move all trait flag checks over to character flag (#55061)
Co-authored-by: Venera3 <[email protected]>
1 parent d489019 commit 2c41bdf

23 files changed

+106
-88
lines changed

data/json/npcs/TALK_COMMON_ALLY.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"text": "Mind if we just chat for a bit about your history?",
7171
"topic": "TALK_FRIEND_CONVERSATION",
7272
"condition": {
73-
"and": [ "at_safe_space", { "or": [ { "npc_has_trait_flag": "BG_SURVIVAL_STORY" }, { "npc_has_trait": "NPC_STATIC_NPC" } ] } ]
73+
"and": [ "at_safe_space", { "or": [ { "npc_has_flag": "BG_SURVIVAL_STORY" }, { "npc_has_trait": "NPC_STATIC_NPC" } ] } ]
7474
},
7575
"//": "If the NPC already has a BG story, or started out as a static NPC (and so probably doesn't need a random bg story), then go on.",
7676
"switch": true

data/json/npcs/TALK_FRIEND_CONVERSATION.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{
88
"text": "It's fine, we've got a moment.",
99
"topic": "TALK_FRIEND_CONVERSATION",
10-
"condition": { "or": [ { "npc_has_trait_flag": "BG_SURVIVAL_STORY" }, { "npc_has_trait": "NPC_STATIC_NPC" } ] },
10+
"condition": { "or": [ { "npc_has_flag": "BG_SURVIVAL_STORY" }, { "npc_has_trait": "NPC_STATIC_NPC" } ] },
1111
"//": "If the NPC already has a BG story, or started out as a static NPC (and so probably doesn't need a random bg story), then go on.",
1212
"switch": true
1313
},

data/json/npcs/TALK_MARLOSS_VOICE.json

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
{
2626
"text": "I don't know what kind of heresy you are spreading, but I'm putting an end to it!",
2727
"topic": "TALK_DONE",
28-
"condition": { "and": [ { "u_has_trait": "SPIRITUAL" }, { "not": { "u_has_trait_flag": "mycus" } } ] },
28+
"condition": { "and": [ { "u_has_trait": "SPIRITUAL" }, { "not": { "u_has_flag": "mycus" } } ] },
2929
"effect": "hostile"
3030
},
3131
{
@@ -54,15 +54,11 @@
5454
"dynamic_line": "I'm a priest or guide of a sort. I sing the hymns along my companions so that we may learn to live in unity, both with each other and with our ailing world.",
5555
"responses": [
5656
{ "text": "Alright.", "topic": "TALK_MARLOSS_VOICE" },
57-
{
58-
"text": "Can I join you?",
59-
"topic": "TALK_MARLOSS_VOICE_WITH_US",
60-
"condition": { "u_has_trait_flag": "mycus" }
61-
},
57+
{ "text": "Can I join you?", "topic": "TALK_MARLOSS_VOICE_WITH_US", "condition": { "u_has_flag": "mycus" } },
6258
{
6359
"text": "Understood. Can I join you?",
6460
"topic": "TALK_MARLOSS_VOICE_OFFER_BERRY",
65-
"condition": { "and": [ { "not": { "u_has_trait_flag": "mycus" } }, { "not": { "u_has_effect": "u_given_berry" } } ] }
61+
"condition": { "and": [ { "not": { "u_has_flag": "mycus" } }, { "not": { "u_has_effect": "u_given_berry" } } ] }
6662
},
6763
{ "text": "Well, I gotta go.", "topic": "TALK_DONE" }
6864
]
@@ -87,7 +83,7 @@
8783
{
8884
"text": "I'm joining no stinking cult! Take your berry and shove it!",
8985
"topic": "TALK_DONE",
90-
"condition": { "not": { "u_has_trait_flag": "mycus" } },
86+
"condition": { "not": { "u_has_flag": "mycus" } },
9187
"effect": "hostile"
9288
}
9389
]

data/json/npcs/TALK_TEST.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,12 @@
8383
{
8484
"text": "This is a trait flags test response.",
8585
"topic": "TALK_DONE",
86-
"condition": { "u_has_trait_flag": "CANNIBAL" }
86+
"condition": { "u_has_flag": "CANNIBAL" }
8787
},
8888
{
8989
"text": "This is a npc trait flags test response.",
9090
"topic": "TALK_DONE",
91-
"condition": { "npc_has_trait_flag": "CANNIBAL" }
91+
"condition": { "npc_has_flag": "CANNIBAL" }
9292
}
9393
]
9494
},

data/json/npcs/refugee_center/surface_staff/Smokes/free_merchant_shopkeep_talk_fluff.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{
1010
"text": "[Cannibal + Psychopath] Wait, I thought you were having food problems.",
1111
"topic": "TALK_FREE_MERCHANTS_MERCHANT_AboutGreeting_Cannibal",
12-
"condition": { "and": [ { "u_has_trait_flag": "CANNIBAL" }, { "u_has_trait": "PSYCHOPATH" } ] }
12+
"condition": { "and": [ { "u_has_flag": "CANNIBAL" }, { "u_has_trait": "PSYCHOPATH" } ] }
1313
}
1414
]
1515
},

doc/JSON_FLAGS.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [Covers](#covers)
1212
- [Flags](#flags)
1313
- [Bionics](#bionics)
14+
- [Bodyparts](#bodyparts)
1415
- [Books](#books)
1516
- [Use actions](#use-actions)
1617
- [Character - (Bionic/Mutation/Effect)](#character)
@@ -1090,7 +1091,6 @@ Special attacks have been moved to [MONSTER_SPECIAL_ATTACKS.md](MONSTER_SPECIAL_
10901091
10911092
#### Flags
10921093
1093-
- ```HARDTOHIT``` Whenever something attacks you, RNG gets rolled twice and you get the better result.
10941094
- ```UNARMED_BONUS``` You get a bonus to unarmed bash and cut damage equal to unarmed_skill/2 up to 4.
10951095
10961096
### Categories
@@ -1515,6 +1515,7 @@ Gun fault flags:
15151515
- ```NO_MINIMAL_HEALING``` This mutation disables the minimal healing of 1 hp a day.
15161516
- ```SUPER_HEARING``` You can hear much better than a normal person.
15171517
- ```IMMUNE_HEARING_DAMAGE``` Immune to hearing damage from loud sounds.
1518+
- ```CANNIBAL``` Butcher humans, eat foods with the `CANNIBALISM` and `STRICT_HUMANITARIANISM` flags without a morale penalty
15181519
-````CLIMB_NO_LADDER``` Capable of climbing up single-level walls without support.
15191520
- ```DEAF``` Makes you deaf.
15201521
- ```BLIND``` Makes you blind.
@@ -1550,7 +1551,21 @@ Gun fault flags:
15501551
- ```THERMOMETER``` You always know what temperature it is.
15511552
- ```CBQ_LEARN_BONUS``` You learn CBQ from the bionic bio_cqb faster.
15521553
- ```GILLS``` You can breathe underwater.
1554+
- ```HARDTOHIT``` Whenever something attacks you, RNG gets rolled twice and you get the better result.
1555+
- ````HUGE``` Changes your size to `creature_size::huge`. Checked last of the size category flags, if no size flags are found your size defaults to `creature_size::medium`.
1556+
- ````LARGE``` Changes your size to `creature_size::large`. Checked third of the size category flags.
1557+
- ```PSYCHOPATH``` Butcher humans without a morale penalty
1558+
- ```PRED1``` Small morale bonus from foods with the `PREDATOR_FUN` flag. Lower morale panalty from the guilt mondeath effect.
1559+
- ```PRED2``` Learn combat skills wit double catchup modifier. Resist skill rust on combat skills. Small morale bonus from foods with the `PREDATOR_FUN` flag. Lower morale panalty from the guilt mondeath effect.
1560+
- ```PRED3``` Learn combat skills wit double catchup modifier. Resist skill rust on combat skills. Medium morale bonus from foods with the `PREDATOR_FUN` flag. Immune to the guilt mondeath effect.
1561+
- ```PRED4``` Learn combat skills wit triple catchup modifier. Learn combat skills without spending focus. Resist skill rust on combat skills. Large morale bonus from foods with the `PREDATOR_FUN` flag. Immune to the guilt mondeath effect.
1562+
- ```SAPIOVORE``` Butcher humans without a morale penalty
1563+
- ````SMALL``` Changes your size to `creature_size::small`. Checked second of the size category flags.
1564+
- ```STEADY``` Your speed can never go below base speed, bonuses from effects etc can still apply.
1565+
- ````STRICT_HUMANITARIAN``` You can eat foodstuffs tagged with `STRICT_HUMANITARIANISM` without morale penalties.
1566+
- ````TINY``` Changes your size to `creature_size::tiny`. Checked first of the size category flags.
15531567
- ```WEB_RAPPEL``` You can rappel down staircases and sheer drops of any height.
15541568
- ```WALL_CLING``` You can ascend/descend sheer cliffs as long as the tile above borders at least one wall. Chance to slip and fall each step.
1569+
- ````WALL_CLING_FOURTH``` Same as `WALL_CLING`, but you need four instances of the flag for it to function (ex. four bodyparts with the flag).
15551570
- ```WINGS_1``` You have 50% chance to ignore falling traps (including ledges).
1556-
- ```WINGS_2``` You have 100% chance to ignore falling traps (including ledges).
1571+
- ```WINGS_2``` You have 100% chance to ignore falling traps (including ledges). Requires two flag instances.

doc/NPCs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ Condition | Type | Description
809809
`"u_female"`<br/>`"npc_female"` | simple string | `true` if the player character or NPC is female.
810810
`"u_at_om_location"`<br/>`"npc_at_om_location"` | string | `true` if the player character or NPC is standing on an overmap tile with `u_at_om_location`'s id. The special string `"FACTION_CAMP_ANY"` changes it to return true if the player or NPC is standing on a faction camp overmap tile. The special string `"FACTION_CAMP_START"` changes it to return true if the overmap tile that the player or NPC is standing on can be turned into a faction camp overmap tile.
811811
`"u_has_trait"`<br/>`"npc_has_trait"` | string | `true` if the player character or NPC has a specific trait. Simpler versions of `u_has_any_trait` and `npc_has_any_trait` that only checks for one trait.
812-
`"u_has_trait_flag"`<br/>`"npc_has_trait_flag"` | string | `true` if the player character or NPC has any traits with the specific trait flag. More robust versions of `u_has_any_trait` and `npc_has_any_trait`. The special trait flag `"MUTATION_THRESHOLD"` checks to see if the player or NPC has crossed a mutation threshold.
812+
`"u_has_flag"`<br/>`"npc_has_flag"` | string | `true` if the player character or NPC has the specified character flag. The special trait flag `"MUTATION_THRESHOLD"` checks to see if the player or NPC has crossed a mutation threshold.
813813
`"u_has_any_trait"`<br/>`"npc_has_any_trait"` | array | `true` if the player character or NPC has any trait or mutation in the array. Used to check multiple specific traits.
814814
`"u_has_var"`, `"npc_has_var"` | string | `"type": type_str`, `"context": context_str`, and `"value": value_str` are required fields in the same dictionary as `"u_has_var"` or `"npc_has_var"`.<br/>`true` is the player character or NPC has a variable set by `"u_add_var"` or `"npc_add_var"` with the string, `type_str`, `context_str`, and `value_str`.
815815
`"u_compare_var"`, `"npc_compare_var"` | dictionary | `"type": type_str`, `"context": context_str`, `"op": op_str`, `"value": value_num or variable_object` are required fields, referencing a var as in `"u_add_var"` or `"npc_add_var"`.<br/>`true` if the player character or NPC has a stored variable that is true for the provided operator `op_str` (one of `==`, `!=`, `<`, `>`, `<=`, `>=`) and value (or the value of the variable described by `value` see `variable_object` above).

src/activity_handlers.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,9 @@ static void set_up_butchery( player_activity &act, Character &you, butcher_type
573573
// applies to all butchery actions
574574
const bool is_human = corpse.id == mtype_id::NULL_ID() || ( corpse.in_species( species_HUMAN ) &&
575575
!corpse.in_species( species_ZOMBIE ) );
576-
if( is_human && !( you.has_trait_flag( json_flag_CANNIBAL ) ||
577-
you.has_trait_flag( json_flag_PSYCHOPATH ) ||
578-
you.has_trait_flag( json_flag_SAPIOVORE ) ) ) {
576+
if( is_human && !( you.has_flag( json_flag_CANNIBAL ) ||
577+
you.has_flag( json_flag_PSYCHOPATH ) ||
578+
you.has_flag( json_flag_SAPIOVORE ) ) ) {
579579

580580
if( you.is_avatar() ) {
581581
if( query_yn( _( "Would you dare desecrate the mortal remains of a fellow human being?" ) ) ) {

src/ballistics.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ dealt_projectile_attack projectile_attack( const projectile &proj_arg, const tri
214214
projectile_attack_aim aim = projectile_attack_roll( dispersion, range, target_size );
215215

216216
if( target_critter && target_critter->as_character() &&
217-
target_critter->as_character()->has_trait_flag( json_flag_HARDTOHIT ) ) {
217+
target_critter->as_character()->has_flag( json_flag_HARDTOHIT ) ) {
218218

219219
projectile_attack_aim lucky_aim = projectile_attack_roll( dispersion, range, target_size );
220220
// if the target's lucky they're more likely to be missed

src/character.cpp

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,10 +1711,10 @@ bool Character::uncanny_dodge()
17111711

17121712
const bool can_dodge_bio = get_power_level() >= trigger_cost &&
17131713
has_active_bionic( bio_uncanny_dodge );
1714-
const bool can_dodge_mut = get_stamina() >= 300 && has_trait_flag( json_flag_UNCANNY_DODGE );
1714+
const bool can_dodge_mut = get_stamina() >= 300 && count_trait_flag( json_flag_UNCANNY_DODGE );
17151715
const bool can_dodge_both = get_power_level() >= ( trigger_cost / 2 ) &&
17161716
has_active_bionic( bio_uncanny_dodge ) &&
1717-
get_stamina() >= 150 && has_trait_flag( json_flag_UNCANNY_DODGE );
1717+
get_stamina() >= 150 && count_trait_flag( json_flag_UNCANNY_DODGE );
17181718

17191719
if( !( can_dodge_bio || can_dodge_mut || can_dodge_both ) ) {
17201720
return false;
@@ -2287,11 +2287,11 @@ void Character::recalc_sight_limits()
22872287
vision_mode_cache.set( IR_VISION );
22882288
}
22892289

2290-
if( has_trait_flag( json_flag_SUPER_CLAIRVOYANCE ) ) {
2290+
if( has_flag( json_flag_SUPER_CLAIRVOYANCE ) ) {
22912291
vision_mode_cache.set( VISION_CLAIRVOYANCE_SUPER );
2292-
} else if( has_trait_flag( json_flag_CLAIRVOYANCE_PLUS ) ) {
2292+
} else if( has_flag( json_flag_CLAIRVOYANCE_PLUS ) ) {
22932293
vision_mode_cache.set( VISION_CLAIRVOYANCE_PLUS );
2294-
} else if( has_trait_flag( json_flag_CLAIRVOYANCE ) ) {
2294+
} else if( has_flag( json_flag_CLAIRVOYANCE ) ) {
22952295
vision_mode_cache.set( VISION_CLAIRVOYANCE );
22962296
}
22972297
}
@@ -2422,14 +2422,14 @@ bool Character::practice( const skill_id &id, int amount, int cap, bool suppress
24222422
if( has_trait( trait_PACIFIST ) && skill.is_combat_skill() ) {
24232423
amount /= 3.0f;
24242424
}
2425-
if( has_trait_flag( json_flag_PRED2 ) && skill.is_combat_skill() ) {
2425+
if( has_flag( json_flag_PRED2 ) && skill.is_combat_skill() ) {
24262426
catchup_modifier *= 2.0f;
24272427
}
2428-
if( has_trait_flag( json_flag_PRED3 ) && skill.is_combat_skill() ) {
2428+
if( has_flag( json_flag_PRED3 ) && skill.is_combat_skill() ) {
24292429
catchup_modifier *= 2.0f;
24302430
}
24312431

2432-
if( has_trait_flag( json_flag_PRED4 ) && skill.is_combat_skill() ) {
2432+
if( has_flag( json_flag_PRED4 ) && skill.is_combat_skill() ) {
24332433
catchup_modifier *= 3.0f;
24342434
}
24352435

@@ -2471,7 +2471,7 @@ bool Character::practice( const skill_id &id, int amount, int cap, bool suppress
24712471

24722472
// Apex Predators don't think about much other than killing.
24732473
// They don't lose Focus when practicing combat skills.
2474-
if( !( has_trait_flag( json_flag_PRED4 ) && skill.is_combat_skill() ) ) {
2474+
if( !( has_flag( json_flag_PRED4 ) && skill.is_combat_skill() ) ) {
24752475
// Base reduction on the larger of 1% of total, or practice amount.
24762476
// The latter kicks in when long actions like crafting
24772477
// apply many turns of gains at once.
@@ -3296,9 +3296,9 @@ void Character::do_skill_rust()
32963296
SkillLevel &skill_level_obj = pair.second;
32973297

32983298
if( aSkill.is_combat_skill() &&
3299-
( ( has_trait_flag( json_flag_PRED2 ) && calendar::once_every( 8_hours ) ) ||
3300-
( has_trait_flag( json_flag_PRED3 ) && calendar::once_every( 4_hours ) ) ||
3301-
( has_trait_flag( json_flag_PRED4 ) && calendar::once_every( 3_hours ) ) ) ) {
3299+
( ( has_flag( json_flag_PRED2 ) && calendar::once_every( 8_hours ) ) ||
3300+
( has_flag( json_flag_PRED3 ) && calendar::once_every( 4_hours ) ) ||
3301+
( has_flag( json_flag_PRED4 ) && calendar::once_every( 3_hours ) ) ) ) {
33023302
// Their brain is optimized to remember this
33033303
if( one_in( 13 ) ) {
33043304
// They've already passed the roll to avoid rust at
@@ -3852,7 +3852,7 @@ int Character::get_enchantment_speed_bonus() const
38523852

38533853
int Character::get_speed() const
38543854
{
3855-
if( has_trait_flag( json_flag_STEADY ) ) {
3855+
if( has_flag( json_flag_STEADY ) ) {
38563856
return get_speed_base() + std::max( 0, get_speed_bonus() ) + std::max( 0,
38573857
get_speedydex_bonus( get_dex() ) );
38583858
}
@@ -10143,41 +10143,43 @@ int Character::book_fun_for( const item &book, const Character &p ) const
1014310143
return fun_bonus;
1014410144
}
1014510145

10146-
bool Character::has_bionic_with_flag( const json_character_flag &flag ) const
10146+
int Character::count_bionic_with_flag( const json_character_flag &flag ) const
1014710147
{
10148+
int ret = 0;
1014810149
for( const bionic &bio : *my_bionics ) {
1014910150
if( bio.info().has_flag( flag ) ) {
10150-
return true;
10151+
ret++;
1015110152
}
1015210153
if( bio.info().activated ) {
1015310154
if( ( bio.info().has_active_flag( flag ) && has_active_bionic( bio.id ) ) ||
1015410155
( bio.info().has_inactive_flag( flag ) && !has_active_bionic( bio.id ) ) ) {
10155-
return true;
10156+
ret++;
1015610157
}
1015710158
}
1015810159
}
1015910160

10160-
return false;
10161+
return ret;
1016110162
}
1016210163

10163-
bool Character::has_bodypart_with_flag( const json_character_flag &flag ) const
10164+
int Character::count_bodypart_with_flag( const json_character_flag &flag ) const
1016410165
{
10166+
int ret = 0;
1016510167
for( const bodypart_id &bp : get_all_body_parts() ) {
1016610168
if( bp->has_flag( flag ) ) {
10167-
return true;
10169+
ret++;
1016810170
}
1016910171
if( get_part( bp )->has_conditional_flag( flag ) ) {
10170-
return true;
10172+
ret++;
1017110173
}
1017210174
}
10173-
return false;
10175+
return ret;
1017410176
}
1017510177

10176-
bool Character::has_flag( const json_character_flag &flag ) const
10178+
int Character::has_flag( const json_character_flag &flag ) const
1017710179
{
1017810180
// If this is a performance problem create a map of flags stored for a character and updated on trait, mutation, bionic add/remove, activate/deactivate, effect gain/loss
10179-
return has_trait_flag( flag ) || has_bionic_with_flag( flag ) || has_effect_with_flag( flag ) ||
10180-
has_bodypart_with_flag( flag );
10181+
return count_trait_flag( flag ) + count_bionic_with_flag( flag ) + has_effect_with_flag(
10182+
flag ) + count_bodypart_with_flag( flag );
1018110183
}
1018210184

1018310185
bool Character::is_driving() const

0 commit comments

Comments
 (0)