From f9dc830d3b8b976bc6733b67a293d602da734094 Mon Sep 17 00:00:00 2001 From: Venera3 <72006894+Venera3@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:34:14 +0200 Subject: [PATCH] Add conditionals to martial art techniques and audit techs to use them (#66034) * First Conditions, in-repo tech conditioning, documentation lint Update src/item.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Tests * Test, Clang * Clang, material test failure * Clangg --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- data/json/effects.json | 7 + data/json/martialarts_fictional.json | 12 +- .../monster_attacks.json | 6 +- data/json/techniques.json | 1165 ++++++++++++++++- data/mods/MMA/techniques.json | 182 +++ data/mods/TEST_DATA/martialarts.json | 86 +- data/mods/TEST_DATA/monsters.json | 18 + doc/MARTIALART_JSON.md | 5 +- doc/NPCs.md | 8 +- src/character.h | 3 + src/condition.cpp | 36 + src/condition.h | 4 +- src/item.cpp | 3 +- src/martialarts.cpp | 34 +- src/martialarts.h | 8 +- src/melee.cpp | 69 +- src/monster.cpp | 10 +- src/monster.h | 1 + src/talker.h | 16 + src/talker_character.cpp | 24 + src/talker_character.h | 3 + src/talker_monster.cpp | 28 +- src/talker_monster.h | 4 + tests/iteminfo_test.cpp | 8 +- tests/martial_art_test.cpp | 103 +- tests/materials_test.cpp | 2 + 26 files changed, 1765 insertions(+), 80 deletions(-) diff --git a/data/json/effects.json b/data/json/effects.json index ba5efcdc5b45f..7fc3d84ca2a46 100644 --- a/data/json/effects.json +++ b/data/json/effects.json @@ -507,6 +507,13 @@ "//": "Exposes certain weakpoints", "desc": [ "You feel exposed -and pretty buggy- without your shell." ] }, + { + "type": "effect_type", + "id": "maimed_arm", + "name": [ "Broken Arm" ], + "//": "Disables base grabs and scratches", + "desc": [ "Your arms are broken. Your imaginary monster arms, so this is probably a bug." ] + }, { "type": "effect_type", "id": "maimed_mandible", diff --git a/data/json/martialarts_fictional.json b/data/json/martialarts_fictional.json index cc9e84f1e4472..3f5151bc93311 100644 --- a/data/json/martialarts_fictional.json +++ b/data/json/martialarts_fictional.json @@ -417,6 +417,8 @@ "unarmed_weapons_allowed": false, "weighting": 2, "crit_ok": true, + "condition": { "not": { "npc_has_effect": "downed" } }, + "condition_desc": "* Only works on a non-downed target", "down_dur": 2, "attack_vectors": [ "FOOT" ] }, @@ -528,7 +530,8 @@ "messages": [ "You beat %s down with a powerful Viper Tail", " beats %s down with a powerful Viper Tail" ], "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, - "stunned_target": true, + "condition": { "npc_has_effect": "stunned" }, + "condition_desc": "Requires a stunned target", "weighting": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ], "attack_vectors": [ "HAND" ] @@ -540,7 +543,8 @@ "messages": [ "You devastate %s with a spectacular Viper Strike", " devastates %s with a spectacular Viper Strike" ], "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, - "stunned_target": true, + "condition": { "npc_has_effect": "stunned" }, + "condition_desc": "Requires a stunned target", "weighting": 2, "crit_tec": true, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], @@ -613,6 +617,8 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_toad_ongethit" ], "crit_ok": true, + "condition": { "not": { "npc_has_effect": "downed" } }, + "condition_desc": "* Only works on a non-downed target", "down_dur": 2, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ], "attack_vectors": [ "HAND" ] @@ -649,6 +655,8 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { "not": { "npc_has_effect": "downed" } }, + "condition_desc": "* Only works on a non-downed target", "down_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ], "attack_vectors": [ "PALM" ] diff --git a/data/json/monster_special_attacks/monster_attacks.json b/data/json/monster_special_attacks/monster_attacks.json index bee335246da30..7a086bb386dea 100644 --- a/data/json/monster_special_attacks/monster_attacks.json +++ b/data/json/monster_special_attacks/monster_attacks.json @@ -66,7 +66,7 @@ "grab": true, "grab_data": { "grab_effect": "grabbed" }, "//": "grab_strength preferentially set in the monster definition for clarity", - "condition": { "not": { "u_has_flag": "GRAB_FILTER" } }, + "condition": { "and": [ { "not": { "u_has_flag": "GRAB_FILTER" } }, { "not": { "u_has_effect": "maimed_arm" } } ] }, "hit_dmg_u": "%1$s grabs your %2$s!", "hit_dmg_npc": "%1$s grabs 's %2$s!", "miss_msg_u": "%s tries to grab you, but you dodge!", @@ -100,7 +100,7 @@ "hitsize_min": 1, "range": 5, "grab": true, - "condition": { "not": { "u_has_flag": "GRAB_FILTER" } }, + "condition": { "and": [ { "not": { "u_has_flag": "GRAB_FILTER" } }, { "not": { "u_has_effect": "maimed_arm" } } ] }, "damage_max_instance": [ { "damage_type": "bash", "amount": 0 } ], "grab_data": { "pull_chance": 100, "pull_weight_ratio": 0.75 }, "no_dmg_msg_u": "", @@ -369,7 +369,7 @@ "cooldown": 20, "move_cost": 150, "damage_max_instance": [ { "damage_type": "cut", "amount": 8 } ], - "condition": { "not": { "u_has_flag": "GRAB_FILTER" } }, + "condition": { "and": [ { "not": { "u_has_flag": "GRAB_FILTER" } }, { "not": { "u_has_effect": "maimed_arm" } } ] }, "hit_dmg_u": "%1$s claws at your %2$s!", "hit_dmg_npc": "%1$s claws at !", "miss_msg_u": "%1$s claws at you, but you dodge!", diff --git a/data/json/techniques.json b/data/json/techniques.json index a0c2e73e79564..bce8ee11f65a5 100644 --- a/data/json/techniques.json +++ b/data/json/techniques.json @@ -93,6 +93,47 @@ "crit_tec": true, "stun_dur": 1, "knockback_dist": 1, + "//condition": "Basic size filtering, if the target is grabbing you contested roll of strength vs grab strength", + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size, may fail on enemies grabbing you", "messages": [ "You send %s reeling", " sends %s reeling" ], "description": "Stun 1 turn, knockback 1 tile, crit only", "attack_vectors": [ "WEAPON" ] @@ -132,6 +173,17 @@ "id": "WRAP", "name": "Wrap Attack", "melee_allowed": true, + "//condition": "Similar size, no wrapping tiny or very nonstandard targets", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_bodytype": "blob" } }, + { "not": { "npc_bodytype": "fish" } }, + { "not": { "npc_bodytype": "snake" } } + ] + }, + "condition_desc": "* Only works on a target of similar size with limbs to catch", "stun_dur": 2, "messages": [ "You wrap up %s", " wraps up %s" ], "description": "Stun 2 turns", @@ -142,6 +194,17 @@ "id": "SWEEP", "name": "Sweep Attack", "melee_allowed": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "messages": [ "You sweep %s", " sweeps %s" ], "description": "Down 2 turns", @@ -175,6 +238,15 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "crit_tec": true, + "//condition": "Humanoids of similar size", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] } + ] + }, + "condition_desc": "* Only works on a non-stunned humanoid target of similar or smaller size", "messages": [ "You precisely hit %s", " precisely hits %s" ], "stun_dur": 2, "description": "Stun 2 turns, crit only, min 3 melee", @@ -214,6 +286,15 @@ "name": "Precise Strike", "melee_allowed": true, "crit_tec": true, + "//condition": "Humanoids of similar size", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] } + ] + }, + "condition_desc": "* Only works on a non-stunned humanoid target of similar or smaller size", "messages": [ "You jab deftly at %s", " jabs deftly at %s" ], "stun_dur": 2, "attack_vectors": [ "WEAPON" ] @@ -229,6 +310,33 @@ "unarmed_weapons_allowed": false, "required_buffs_all": [ "buff_aikido_onblock" ], "crit_ok": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight, may fail on targets grabbing you", "down_dur": 1, "knockback_dist": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.7 } ], @@ -244,6 +352,33 @@ "unarmed_weapons_allowed": false, "required_buffs_all": [ "buff_aikido_ondodge" ], "crit_ok": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight, may fail on targets grabbing you", "down_dur": 1, "knockback_dist": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.7 } ], @@ -261,6 +396,33 @@ "required_buffs_all": [ "buff_aikido_onblock" ], "crit_ok": true, "disarms": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight, may fail on targets grabbing you", "down_dur": 1, "knockback_dist": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.7 } ], @@ -278,6 +440,33 @@ "required_buffs_all": [ "buff_aikido_ondodge" ], "crit_ok": true, "disarms": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight, may fail on targets grabbing you", "down_dur": 1, "knockback_dist": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.7 } ], @@ -320,6 +509,17 @@ "melee_allowed": true, "block_counter": true, "crit_ok": true, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ], "attack_vectors": [ "WEAPON" ] @@ -336,6 +536,16 @@ "melee_allowed": true, "block_counter": true, "crit_ok": true, + "//condition": "Similar size", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { "not": { "npc_bodytype": "blob" } } + ] + }, + "condition_desc": "* Only works on a non-stunned target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "WEAPON" ] @@ -430,6 +640,16 @@ "knockback_dist": 1, "knockback_spread": 1, "stun_dur": 1, + "//condition": "Humanoids of similar size and no flying", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ], "attack_vectors": [ "HAND" ] @@ -457,6 +677,25 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "//condition": "Things of similar size in both directions that keep their heads high", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size') - 1", "<=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "or": [ + { "npc_bodytype": "human" }, + { "npc_bodytype": "mi-go" }, + { "npc_bodytype": "kangoroo" }, + { "npc_bodytype": "horse" }, + { "npc_bodytype": "bear" }, + { "npc_bodytype": "angel" } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned target of similar size incapable of flight", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "HAND" ] @@ -531,6 +770,16 @@ "crit_tec": true, "knockback_dist": 1, "stun_dur": 1, + "//condition": "Similar size and no flying or blobs", + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "not": { "npc_has_effect": "stunned" } }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed and non-stunned target of similar or smaller size incapable of flight", "attack_vectors": [ "HAND" ] }, { @@ -540,6 +789,16 @@ "messages": [ "You trip %s", " trip %s" ], "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "u_val('size') - 1", "<=", "n_val('size')" ] }, + { "or": [ { "npc_bodytype": "angel" }, { "npc_bodytype": "human" } ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar size incapable of flight", "down_dur": 1, "attack_vectors": [ "HAND" ] }, @@ -590,6 +849,16 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_capoeira_onmove" ], "weighting": 2, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "u_val('size') - 1", "<=", "n_val('size')" ] }, + { "or": [ { "npc_bodytype": "angel" }, { "npc_bodytype": "human" } ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 }, @@ -609,6 +878,8 @@ "required_buffs_all": [ "buff_capoeira_onmove" ], "weighting": 2, "crit_tec": true, + "condition": { "and": [ { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, { "not": { "npc_has_effect": "stunned" } } ] }, + "condition_desc": "* Only works on a non-stunned target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 }, @@ -636,6 +907,15 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_crane_ondodge" ], "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 }, @@ -666,6 +946,32 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_crane_ondodge" ], "crit_ok": true, + "//condition": "TODO: differentiate the stun from the damage, though 1.5x flat is excessive", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, @@ -691,6 +997,16 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "u_val('size') - 1", "<=", "n_val('size')" ] }, + { "or": [ { "npc_bodytype": "angel" }, { "npc_bodytype": "human" } ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 }, @@ -707,7 +1023,8 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "crit_tec": true, - "downed_target": true, + "condition": { "npc_has_effect": "downed" }, + "condition_desc": "* Only works on a downed target", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, @@ -770,6 +1087,31 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 } ], "attack_vectors": [ "WEAPON" ] @@ -782,6 +1124,16 @@ "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "attack_vectors": [ "WEAPON" ] }, @@ -850,6 +1202,31 @@ "required_buffs_all": [ "buff_fencing_onblock" ], "crit_ok": true, "weighting": 2, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.66 }, @@ -869,6 +1246,16 @@ "required_buffs_all": [ "buff_medievalpole_onblock" ], "crit_ok": true, "weighting": 2, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 }, @@ -924,6 +1311,16 @@ "required_buffs_all": "buff_medievalpole_onmiss", "crit_ok": true, "weighting": 2, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 }, @@ -939,7 +1336,8 @@ "messages": [ "You swing down hard and execute %s", " swings down hard and executes %s" ], "skill_requirements": [ { "name": "melee", "level": 5 } ], "melee_allowed": true, - "downed_target": true, + "condition": { "npc_has_effect": "downed" }, + "condition_desc": "* Only works on a downed target", "crit_tec": true, "weighting": 2, "mult_bonuses": [ @@ -958,6 +1356,16 @@ "melee_allowed": true, "unarmed_weapons_allowed": false, "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", "<=", "n_val('size')" ] }, + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "npc_bodytype": "human" }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of identical size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ], "attack_vectors": [ "THROW" ] @@ -972,6 +1380,16 @@ "melee_allowed": true, "unarmed_weapons_allowed": false, "disarms": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", "<=", "n_val('size')" ] }, + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "npc_bodytype": "human" }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of identical size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ], "attack_vectors": [ "THROW" ] @@ -987,6 +1405,16 @@ "unarmed_weapons_allowed": false, "crit_tec": true, "side_switch": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", "<=", "n_val('size')" ] }, + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "npc_bodytype": "human" }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of identical size incapable of flight", "down_dur": 1, "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 } ], @@ -1014,6 +1442,31 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 }, @@ -1071,6 +1524,16 @@ "melee_allowed": true, "weapon_categories_allowed": "QUARTERSTAVES", "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.1 }, @@ -1102,6 +1565,43 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "//condition": "Things of similar size in both directions that keep their heads high", + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size') - 1", "<=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "or": [ + { "npc_bodytype": "human" }, + { "npc_bodytype": "mi-go" }, + { "npc_bodytype": "kangoroo" }, + { "npc_bodytype": "horse" }, + { "npc_bodytype": "bear" }, + { "npc_bodytype": "angel" } + ] + }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned target of similar size incapable of flight", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "HAND" ] @@ -1144,6 +1644,31 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "KNEE" ] }, @@ -1155,6 +1680,31 @@ "skill_requirements": [ { "name": "unarmed", "level": 5 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "KNEE" ] @@ -1184,6 +1734,31 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "attack_vectors": [ "WEAPON" ], "attack_vectors_random": [ "HAND", "FINGERS", "FOOT", "ELBOW", "KNEE", "LOWER_LEG", "HEAD" ] @@ -1197,6 +1772,15 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "attack_vectors": [ "THROW" ] }, @@ -1209,10 +1793,25 @@ "unarmed_allowed": true, "weighting": 2, "crit_tec": true, - "downed_target": true, - "stunned_target": true, - "human_target": true, - "stun_dur": 1, + "condition": { + "and": [ + { "npc_has_effect": "downed" }, + { "npc_has_effect": "stunned" }, + { "npc_has_species": "HUMAN" }, + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "npc_bodytype": "human" } + ] + }, + "condition_desc": "* Only works on a downed and stunned humanoid target", + "tech_effects": [ + { + "id": "maimed_arm", + "chance": 100, + "permanent": true, + "on_damage": true, + "message": "The %s's arm is mangled beyond recognition!" + } + ], "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scaling-stat": "str", "scale": 1.0 } ], "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], "attack_vectors": [ "GRAPPLE" ] @@ -1246,6 +1845,31 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ], "attack_vectors": [ "HAND" ] @@ -1282,6 +1906,15 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_leopard_oncrit" ], "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of identical or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.8 }, { "stat": "damage", "type": "bash", "scale": 2.0 } ], "attack_vectors": [ "HAND" ] @@ -1300,6 +1933,15 @@ { "stat": "damage", "type": "stab", "scale": 0.33 } ], "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "attack_vectors": [ "WEAPON" ] }, @@ -1367,6 +2009,31 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 1, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 } ], "attack_vectors": [ "KNEE" ] }, @@ -1417,6 +2084,31 @@ "forbidden_buffs_all": [ "buff_ninjutsu_onattack" ], "crit_tec": true, "stun_dur": 1, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.3 }, { "stat": "damage", "type": "cut", "scale": 1.3 }, @@ -1433,6 +2125,34 @@ "unarmed_allowed": true, "forbidden_buffs_all": [ "buff_ninjutsu_onattack" ], "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed and non-stunned mundane humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "stun_dur": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], @@ -1459,6 +2179,15 @@ "messages": [ "Your strike knocks %s off balance", "'s strike knocks %s off balance" ], "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "attack_vectors": [ "WEAPON" ] }, @@ -1470,6 +2199,31 @@ "skill_requirements": [ { "name": "melee", "level": 5 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, @@ -1487,6 +2241,31 @@ "melee_allowed": true, "required_buffs_all": [ "buff_niten_ondodge" ], "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 }, @@ -1527,6 +2306,31 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 2, "attack_vectors": [ "FOOT" ] }, @@ -1547,7 +2351,8 @@ "messages": [ "You grab and knee %s", " grabs and knees %s" ], "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, - "stunned_target": true, + "condition": { "npc_has_effect": "stunned" }, + "condition_desc": "* Only works on a stunned target", "weighting": 3, "mult_bonuses": [ { "stat": "movecost", "scale": 0.5 } ], "attack_vectors": [ "KNEE" ] @@ -1559,7 +2364,8 @@ "messages": [ "You disarm %s with an arm lock", " disarms %s with an arm lock" ], "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, - "stunned_target": true, + "condition": { "npc_has_effect": "stunned" }, + "condition_desc": "* Only works on a stunned target", "crit_ok": true, "weighting": 3, "disarms": true, @@ -1580,7 +2386,34 @@ "down_dur": 2, "knockback_dist": 2, "knockback_spread": 2, - "stunned_target": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed and non-stunned mundane humanoid target of similar or smaller size incapable of flight", "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 2.0 } ], "attack_vectors": [ "THROW" ] }, @@ -1592,6 +2425,15 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 2, "attack_vectors": [ "WEAPON" ] }, @@ -1603,7 +2445,8 @@ "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, "crit_ok": true, - "downed_target": true, + "condition": { "npc_has_effect": "downed" }, + "condition_desc": "* Only works on a downed target", "weighting": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 }, @@ -1620,6 +2463,31 @@ "skill_requirements": [ { "name": "melee", "level": 4 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 2, "attack_vectors": [ "WEAPON" ] }, @@ -1631,7 +2499,8 @@ "skill_requirements": [ { "name": "melee", "level": 5 } ], "melee_allowed": true, "crit_ok": true, - "stunned_target": true, + "condition": { "npc_has_effect": "stunned" }, + "condition_desc": "* Only works on a stunned target", "weighting": 2, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.33 }, @@ -1684,6 +2553,31 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_snake_onpause" ], "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 1.0 }, @@ -1701,6 +2595,28 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "knockback_dist": 1, + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a target of similar or smaller size, may fail on enemies grabbing you", "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 }, { "stat": "damage", "type": "cut", "scale": 0.5 }, @@ -1715,6 +2631,15 @@ "messages": [ "You deftly trip %s", " deftly trips %s" ], "skill_requirements": [ { "name": "melee", "level": 3 } ], "melee_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 0.5 }, @@ -1758,6 +2683,31 @@ "unarmed_allowed": true, "crit_tec": true, "stun_dur": 2, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "knockback_dist": 2, "mult_bonuses": [ { "stat": "movecost", "scale": 1.5 }, @@ -1774,6 +2724,28 @@ "messages": [ "You turn slightly and side-kick %s", " turns slightly and side-kicks %s" ], "melee_allowed": true, "unarmed_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a target of similar or smaller size, may fail on enemies grabbing you", "knockback_dist": 1, "attack_vectors": [ "FOOT" ] }, @@ -1786,6 +2758,15 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "attack_vectors_random": [ "FOOT", "LOWER_LEG" ] }, @@ -1832,6 +2813,28 @@ "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, "required_buffs_all": [ "buff_tai_chi_onpause" ], + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a target of similar or smaller size, may fail on enemies grabbing you", "knockback_dist": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.5 }, @@ -1849,6 +2852,15 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_tai_chi_onblock" ], "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "movecost", "scale": 0.75 }, @@ -1867,6 +2879,47 @@ "unarmed_allowed": true, "crit_tec": true, "required_buffs_all": [ "buff_tai_chi_onpause" ], + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "knockback_dist": 1, "stun_dur": 1, "mult_bonuses": [ @@ -1895,6 +2948,15 @@ "messages": [ "You slam %s to the ground", " slams %s to the ground" ], "skill_requirements": [ { "name": "unarmed", "level": 1 } ], "unarmed_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 } ], "attack_vectors": [ "THROW" ] @@ -1927,6 +2989,31 @@ "skill_requirements": [ { "name": "unarmed", "level": 4 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 }, @@ -1974,6 +3061,28 @@ "unarmed_allowed": true, "required_buffs_all": [ "buff_wingchun_onpause" ], "weighting": 2, + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a target of similar or smaller size, may fail on enemies grabbing you", "knockback_dist": 1, "knockback_follow": true, "mult_bonuses": [ @@ -1991,6 +3100,15 @@ "skill_requirements": [ { "name": "unarmed", "level": 2 } ], "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.2 }, @@ -2009,6 +3127,31 @@ "required_buffs_all": [ "buff_wingchun_onpause" ], "weighting": 2, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size')", ">=", "n_val('size')" ] }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight, may fail on targets grabbing you", "down_dur": 1, "knockback_dist": 1, "knockback_follow": true, diff --git a/data/mods/MMA/techniques.json b/data/mods/MMA/techniques.json index 075f2188c8eee..796cfd1cc63a9 100644 --- a/data/mods/MMA/techniques.json +++ b/data/mods/MMA/techniques.json @@ -135,6 +135,31 @@ "skill_requirements": [ { "name": "melee", "level": 5 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.25 }, @@ -151,6 +176,31 @@ "skill_requirements": [ { "name": "melee", "level": 2 } ], "melee_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "mult_bonuses": [ { "stat": "damage", "type": "bash", "scale": 1.4 }, @@ -213,6 +263,31 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "flat_bonuses": [ { "stat": "arpen", "type": "bash", "scaling-stat": "per", "scale": 1.0 }, @@ -293,6 +368,15 @@ "skill_requirements": [ { "name": "unarmed", "level": 3 } ], "unarmed_allowed": true, "crit_ok": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "condition_desc": "* Only works on a non-downed humanoid target of similar or smaller size incapable of flight", "down_dur": 1, "attack_vectors_random": [ "FOOT", "LOWER_LEG" ] }, @@ -305,6 +389,31 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "attack_vectors": [ "WEAPON", "HAND" ] }, @@ -317,6 +426,29 @@ "melee_allowed": true, "unarmed_allowed": true, "required_buffs_all": [ "mma_buff_setting_sun_onpause" ], + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed target of similar or smaller size, may fail on enemies grabbing you", "down_dur": 2, "knockback_dist": 2, "mult_bonuses": [ @@ -336,6 +468,29 @@ "unarmed_allowed": true, "required_buffs_all": [ "mma_buff_setting_sun_onpause" ], "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-downed target of similar or smaller size, may fail on enemies grabbing you", "down_dur": 2, "knockback_dist": 4, "powerful_knockback": true, @@ -396,6 +551,31 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_tec": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "condition_desc": "* Only works on a non-stunned mundane target of similar or smaller size", "stun_dur": 1, "attack_vectors": [ "WEAPON", "HAND" ] }, @@ -408,6 +588,8 @@ "melee_allowed": true, "unarmed_allowed": true, "crit_ok": true, + "condition": { "not": { "npc_has_effect": "downed" } }, + "condition_desc": "* Only works on a non-downed target", "down_dur": 1, "knockback_dist": 2, "mult_bonuses": [ diff --git a/data/mods/TEST_DATA/martialarts.json b/data/mods/TEST_DATA/martialarts.json index 090e88f3781f9..ca92c14b9d2c4 100644 --- a/data/mods/TEST_DATA/martialarts.json +++ b/data/mods/TEST_DATA/martialarts.json @@ -9,6 +9,90 @@ "weapon_categories_allowed": [ "TEST_CAT1", "BLADES" ], "stun_dur": 2 }, + { + "type": "technique", + "id": "test_tech_condition_sweep", + "name": "Test Sweep", + "unarmed_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "math": [ "n_val('size')", "!=", "1" ] }, + { "not": { "npc_has_effect": "downed" } }, + { "or": [ { "npc_bodytype": "human" }, { "npc_bodytype": "angel" } ] }, + { "or": [ { "not": { "npc_has_flag": "FLIES" } }, { "npc_has_flag": "DISABLE_FLIGHT" } ] } + ] + }, + "down_dur": 2, + "messages": [ "You see if you can sweep %s", " sees if they can sweep %s" ], + "attack_vectors": [ "FOOT" ] + }, + { + "type": "technique", + "id": "test_tech_condition_stun", + "name": "Test Stun", + "messages": [ "You see if you can stun %s", " tries stunning %s" ], + "melee_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "stunned" } }, + { + "and": [ + { "not": { "npc_has_species": "ZOMBIE" } }, + { "not": { "npc_has_species": "NETHER" } }, + { "not": { "npc_has_species": "NETHER_EMENATION" } }, + { "not": { "npc_has_species": "LEECH_PLANT" } }, + { "not": { "npc_has_species": "MIGO" } }, + { "not": { "npc_has_species": "SLIME" } }, + { "not": { "npc_has_species": "FUNGUS" } }, + { "not": { "npc_has_species": "PLANT" } }, + { "not": { "npc_has_species": "ROBOT" } }, + { "not": { "npc_has_species": "CYBORG" } }, + { "not": { "npc_has_species": "HALLUCINATION" } }, + { "not": { "npc_has_species": "HORROR" } }, + { "not": { "npc_has_species": "ABERRATION" } }, + { "not": { "npc_has_species": "KRAKEN" } } + ] + } + ] + }, + "stun_dur": 1, + "weapon_categories_allowed": [ "MEDIUM_SWORDS" ], + "attack_vectors": [ "WEAPON" ] + }, + { + "type": "technique", + "id": "test_tech_condition_knockback", + "name": "Test Knockback", + "messages": [ "You try to toss %s aside", " tries to toss %s aside" ], + "melee_allowed": true, + "condition": { + "and": [ + { "math": [ "u_val('size') + 1", ">=", "n_val('size')" ] }, + { "not": { "npc_has_effect": "downed" } }, + { + "or": [ + { + "and": [ + { "npc_has_flag": "GRAB_FILTER" }, + { "u_has_flag": "GRAB" }, + { + "roll_contested": { "math": [ "u_val('strength')" ] }, + "die_size": 20, + "difficulty": { "math": [ "n_val('grab_strength')" ] } + } + ] + }, + { "not": { "and": [ { "npc_has_flag": "GRAB_FILTER" }, { "u_has_flag": "GRAB" } ] } } + ] + } + ] + }, + "knockback_dist": 2, + "weapon_categories_allowed": [ "MACES" ], + "attack_vectors": [ "WEAPON" ] + }, { "type": "martial_art", "id": "test_style_ma1", @@ -37,7 +121,7 @@ "weapon_categories_allowed": "KNIVES" } ], - "techniques": [ "test_technique" ], + "techniques": [ "test_technique", "test_tech_condition_sweep", "test_tech_condition_stun", "test_tech_condition_knockback" ], "weapon_category": [ "TEST_CAT1" ] } ] diff --git a/data/mods/TEST_DATA/monsters.json b/data/mods/TEST_DATA/monsters.json index 8b7833ff0d16c..033fc0d548090 100644 --- a/data/mods/TEST_DATA/monsters.json +++ b/data/mods/TEST_DATA/monsters.json @@ -44,6 +44,24 @@ ], "upgrades": false }, + { + "type": "MONSTER", + "id": "mon_test_tech_grabber", + "name": { "str": "MA tech dialog condition test monster" }, + "description": "It exists only to somehow grab you despite not having any grab strength", + "default_faction": "zombie", + "material": [ "flesh" ], + "species": [ "HUMAN", "ZOMBIE" ], + "symbol": "D", + "volume": "81500 ml", + "speed": 100, + "melee_skill": 1000, + "melee_dice": 0, + "morale": 100, + "aggression": 100, + "grab_strength": 0, + "special_attacks": [ { "id": "grab" } ] + }, { "type": "MONSTER", "id": "mon_test_mattack_dialog", diff --git a/doc/MARTIALART_JSON.md b/doc/MARTIALART_JSON.md index 83214162c96e0..4f17ac3ff92e0 100644 --- a/doc/MARTIALART_JSON.md +++ b/doc/MARTIALART_JSON.md @@ -78,9 +78,8 @@ "crit_tec": true, // This technique only works on a critical hit "crit_ok": true, // This technique works on both normal and critical hits "attack_override": false, // This technique replaces the base attack it triggered on, nulling damage and movecost (instead using the tech's flat_bonuses), and counts as unarmed for the purposes of skill training and special melee effects - "downed_target": true, // Technique only works on a downed target - "stunned_target": true, // Technique only works on a stunned target - "human_target": true, // Technique only works on a human-like target + "condition": "u_is_outside",// Optional (array of) dialog conditions the attack requires to trigger. Failing these will disqualify the tech from being selected + "condition_desc": "Needs X",// Description string describing the conditions of this attack (since dialog conditions can't be automatically evaluated) "repeat_min": 1, // Technique's damage and any added effects are repeated rng( repeat_min, repeat_max) times. The target's armor and the effect's chances are applied for each repeat. "repeat_max": 1, "knockback_dist": 1, // Distance target is knocked back diff --git a/doc/NPCs.md b/doc/NPCs.md index 0e98a83d3fa12..926c79df03e6e 100644 --- a/doc/NPCs.md +++ b/doc/NPCs.md @@ -981,7 +981,9 @@ Condition | Type | Description `"u_at_om_location"`
`"npc_at_om_location"` | string or [variable object](#variable-object) | `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. `"u_has_trait"`
`"npc_has_trait"` | string or [variable object](#variable-object) | `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. `"u_has_martial_art"`
`"npc_has_martial_art"` | string or [variable object](#variable-object) | `true` if the player character or NPC knows a specific martial arts style. -`"u_has_flag"`
`"npc_has_flag"` | string or [variable object](#variable-object) | `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. +`"u_has_flag"`
`"npc_has_flag"` | string or [variable object](#variable-object) | `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. Monsters are checked for both JSON flags (conferred by effects) and monster flags. +`"u_has_species"`
`npc_has_species` | string or [variable object](#variable-object) | `true` if the alpha / beta talker have the defined species. +`"u_bodytype"`
`npc_bodytype` | string or [variable object](#variable-object) | `true` if the alpha / beta talker monster has the defined bodytype. For Characters it returns true when queried with bodytype `human`. `"u_has_any_trait"`
`"npc_has_any_trait"` | array of strings and/or [variable objects](#variable-object) | `true` if the player character or NPC has any trait or mutation in the array. Used to check multiple specific traits. `"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"`.
`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`. `"expects_vars"` | array of strings and/or [variable object](#variable-object) | `true` if each value provided is a variable that exists in the context. Gives a debug error if this check fails. @@ -998,7 +1000,7 @@ Condition | Type | Description `"u_has_items"`
`"npc_has_item"` | dictionary | `u_has_items` or `npc_has_items` must be a dictionary with an `item` string or [variable object](#variable-object) and a `count` int or [variable object](#variable-object) or `charges` int or [variable object](#variable-object).
`true` if the player character or NPC has at least `charges` charges or counts of `item` in their inventory. `"u_has_item_category"`
`"npc_has_item_category"` | string or [variable object](#variable-object) | `"count": `int or [variable object](#variable-object) is an optional field that must be in the same dictionary and defaults to 1 if not specified. `true` if the player or NPC has `count` items with the same category as `u_has_item_category` or `npc_has_item_category`. `"u_has_bionics"`
`"npc_has_bionics"` | string or [variable object](#variable-object) | `true` if the player or NPC has an installed bionic with an `bionic_id` matching `"u_has_bionics"` or `"npc_has_bionics"`. The special string "ANY" returns true if the player or NPC has any installed bionics. -`"u_has_effect"`
`"npc_has_effect"`, (*optional* `intensity : int`),(*optional* `bodypart : string`) | string or [variable object](#variable-object) | `true` if the player character or NPC is under the effect with `u_has_effect` or `npc_has_effect`'s `effect_id`. If `intensity` is specified it will need to be at least that strong. If `bodypart` is specified it will check only that bodypart for the effect. +`"u_has_effect"`
`"npc_has_effect"`, (*optional* `intensity : int`),(*optional* `bodypart : string`) | string or [variable object](#variable-object) | `true` if the player character or NPC is under the effect with `u_has_effect` or `npc_has_effect`'s `effect_id`. If `intensity` is specified it will need to be at least that strong. If `bodypart` is specified it will check only that bodypart for the effect. Martial art buff effects need to be queried with the syntax `mabuff:`. `"u_can_stow_weapon"`
`"npc_can_stow_weapon"` | simple string | `true` if the player character or NPC is wielding a weapon and has enough space to put it away. `"u_can_drop_weapon"`
`"npc_can_drop_weapon"` | simple string | `true` if the player character or NPC is wielding a weapon and can drop it on the ground, i.e. weapon isn't unwieldable like retracted bionic claws or monomolecular blade bionics. `"u_has_weapon"`
`"npc_has_weapon"` | simple string | `true` if the player character or NPC is wielding a weapon. @@ -1329,6 +1331,8 @@ Example | Description `"u_val": "age"` | Current age in years. `"u_val": "bmi_permil"` | Current BMI per mille (Body Mass Index x 1000) `"u_val": "height"` | Current height in cm. When setting there is a range for your character size category. Setting it too high or low will use the limit instead. For tiny its 58, and 87. For small its 88 and 144. For medium its 145 and 200. For large its 201 and 250. For huge its 251 and 320. +`"u_val": "size"` | Size category from 1 (tiny) to 5 (huge). Read-only. +`"u_val": "grab_strength"` | Grab strength as defined in the monster definition. Read-only, returns false on characters. `"u_val": "monsters_nearby"` | Number of monsters nearby. Optional params: `target_var` is a variable_object of a location variable to center the effect on, `id` is a variable_object, if its provided only monsters with this id will be counted, `radius` a variable_object of how far around the center to count from. `"u_val": "spell_level"` | Level of a given spell. -1 means the spell is not known when read and that the spell should be forgotten if written. Optional params: `school` gives the highest level of spells known of that school (read only), `spell` reads or writes the level of the spell with matching spell id. If no parameter is provided, you will get the highest spell level of the spells you know (read only). `"u_val": "spell_exp"` | Experience for a given spell. -1 means the spell is not known when read and that the spell should be forgotten if written. Required param: `spell` is the id of the spell in question. diff --git a/src/character.h b/src/character.h index 9a73861e15d44..cb0a218170dec 100644 --- a/src/character.h +++ b/src/character.h @@ -979,6 +979,9 @@ class Character : public Creature, public visitable /** Returns a random valid technique */ matec_id pick_technique( Creature &t, const item_location &weap, bool crit, bool dodge_counter, bool block_counter ); + // Houses the actual picking logic and returns the vector of eligable techniques + std::vector evaluate_techniques( Creature &t, const item_location &weap, + bool crit = false, bool dodge_counter = false, bool block_counter = false ); void perform_technique( const ma_technique &technique, Creature &t, damage_instance &di, int &move_cost, item_location &cur_weapon ); diff --git a/src/condition.cpp b/src/condition.cpp index 092cb2d9db26f..07acc2a3c7216 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -446,6 +446,26 @@ void conditional_t::set_has_flag( const JsonObject &jo, const std::string &membe }; } +void conditional_t::set_has_species( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + str_or_var species_to_check = get_str_or_var( jo.get_member( member ), member, true ); + condition = [species_to_check, is_npc]( dialogue const & d ) { + const talker *actor = d.actor( is_npc ); + return actor->has_species( species_id( species_to_check.evaluate( d ) ) ); + }; +} + +void conditional_t::set_bodytype( const JsonObject &jo, const std::string &member, + bool is_npc ) +{ + str_or_var bt_to_check = get_str_or_var( jo.get_member( member ), member, true ); + condition = [bt_to_check, is_npc]( dialogue const & d ) { + const talker *actor = d.actor( is_npc ); + return actor->bodytype( bodytype_id( bt_to_check.evaluate( d ) ) ); + }; +} + void conditional_t::set_has_activity( bool is_npc ) { condition = [is_npc]( dialogue const & d ) { @@ -1898,6 +1918,14 @@ std::function conditional_t::get_get_dbl( J const &jo ) return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_bmi_permil(); }; + } else if( checked_value == "size" ) { + return [is_npc]( dialogue const & d ) { + return d.actor( is_npc )->get_size(); + }; + } else if( checked_value == "grab_strength" ) { + return [is_npc]( dialogue const & d ) { + return d.actor( is_npc )->get_grab_strength(); + }; } else if( checked_value == "fine_detail_vision_mod" ) { return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_fine_detail_vision_mod(); @@ -3000,6 +3028,14 @@ conditional_t::conditional_t( const JsonObject &jo ) set_has_flag( jo, "u_has_flag" ); } else if( jo.has_member( "npc_has_flag" ) ) { set_has_flag( jo, "npc_has_flag", true ); + } else if( jo.has_member( "u_has_species" ) ) { + set_has_species( jo, "u_has_species" ); + } else if( jo.has_member( "npc_has_species" ) ) { + set_has_species( jo, "npc_has_species", true ); + } else if( jo.has_member( "u_bodytype" ) ) { + set_bodytype( jo, "u_bodytype" ); + } else if( jo.has_member( "npc_bodytype" ) ) { + set_bodytype( jo, "npc_bodytype", true ); } else if( jo.has_member( "npc_has_class" ) ) { set_npc_has_class( jo, "npc_has_class", true ); } else if( jo.has_member( "u_has_class" ) ) { diff --git a/src/condition.h b/src/condition.h index e170d9eddf965..a1da5d1759b56 100644 --- a/src/condition.h +++ b/src/condition.h @@ -32,7 +32,7 @@ const std::unordered_set simple_string_conds = { { }; const std::unordered_set complex_conds = { { "u_has_any_trait", "npc_has_any_trait", "u_has_trait", "npc_has_trait", - "u_has_flag", "npc_has_flag", "npc_has_class", "u_has_mission", "u_monsters_in_direction", "u_safe_mode_trigger", + "u_has_flag", "npc_has_flag", "u_has_species", "npc_has_species", "u_bodytype", "npc_bodytype", "npc_has_class", "u_has_mission", "u_monsters_in_direction", "u_safe_mode_trigger", "u_has_strength", "npc_has_strength", "u_has_dexterity", "npc_has_dexterity", "u_has_intelligence", "npc_has_intelligence", "u_has_perception", "npc_has_perception", "u_is_wearing", "npc_is_wearing", "u_has_item", "npc_has_item", "u_has_move_mode", "npc_has_move_mode", @@ -104,6 +104,8 @@ struct conditional_t { void set_has_trait( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_martial_art( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_flag( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_has_species( const JsonObject &jo, const std::string &member, bool is_npc = false ); + void set_bodytype( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_has_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); void set_expects_vars( const JsonObject &jo, const std::string &member ); void set_compare_var( const JsonObject &jo, const std::string &member, bool is_npc = false ); diff --git a/src/item.cpp b/src/item.cpp index 2eea03e334a36..4a04a17df4059 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -5221,7 +5221,8 @@ void item::melee_combat_info( std::vector &info, const iteminfo_query insert_separation_line( info ); info.emplace_back( "DESCRIPTION", _( "Techniques when wielded: " ) + enumerate_as_string( all_tec_sorted, []( const matec_id & tid ) { - return string_format( "%s: %s", tid.obj().name, tid.obj().description ); + return string_format( "%s: %s %s", tid.obj().name, + tid.obj().description, tid.obj().condition_desc ); } ) ); } } diff --git a/src/martialarts.cpp b/src/martialarts.cpp index 7b82fc3cdc8fb..4750e9dc3f00b 100644 --- a/src/martialarts.cpp +++ b/src/martialarts.cpp @@ -220,10 +220,7 @@ void ma_technique::load( const JsonObject &jo, const std::string &src ) optional( jo, was_loaded, "crit_tec", crit_tec, false ); optional( jo, was_loaded, "crit_ok", crit_ok, false ); optional( jo, was_loaded, "attack_override", attack_override, false ); - optional( jo, was_loaded, "downed_target", downed_target, false ); - optional( jo, was_loaded, "stunned_target", stunned_target, false ); optional( jo, was_loaded, "wall_adjacent", wall_adjacent, false ); - optional( jo, was_loaded, "human_target", human_target, false ); optional( jo, was_loaded, "needs_ammo", needs_ammo, false ); @@ -259,6 +256,13 @@ void ma_technique::load( const JsonObject &jo, const std::string &src ) eocs.push_back( effect_on_conditions::load_inline_eoc( jv, src ) ); } + if( jo.has_member( "condition" ) ) { + read_condition( jo, "condition", condition, false ); + optional( jo, was_loaded, "condition_desc", condition_desc ); + has_condition = true; + } + + reqs.load( jo, src ); bonuses.load( jo ); } @@ -594,6 +598,7 @@ bool ma_requirements::buff_requirements_satisfied( const Character &u ) const bool ma_requirements::is_valid_character( const Character &u ) const { if( !buff_requirements_satisfied( u ) ) { + add_msg_debug( debugmode::DF_MELEE, "Buff requirements not satisfied, attack discarded" ); return false; } @@ -627,6 +632,8 @@ bool ma_requirements::is_valid_character( const Character &u ) const for( const auto &pr : min_skill ) { if( ( cqb ? 5 : static_cast( u.get_skill_level( pr.first ) ) ) < pr.second ) { + add_msg_debug( debugmode::DF_MELEE, "Skill level requirement %d not satisfied, attack discarded", + pr.second ); return false; } } @@ -639,12 +646,14 @@ bool ma_requirements::is_valid_character( const Character &u ) const } } if( !has_flag ) { + add_msg_debug( debugmode::DF_MELEE, "Required flag(any) not found, attack discarded" ); return false; } } for( const json_character_flag &flag : req_char_flags_all ) { if( !u.has_flag( flag ) ) { + add_msg_debug( debugmode::DF_MELEE, "Required flags(all) not found, attack discarded" ); return false; } } @@ -657,6 +666,7 @@ bool ma_requirements::is_valid_character( const Character &u ) const } } if( has_flag ) { + add_msg_debug( debugmode::DF_MELEE, "Forbidden flag found, attack discarded" ); return false; } } @@ -669,6 +679,7 @@ bool ma_requirements::is_valid_character( const Character &u ) const } } if( !valid_weap_cat ) { + add_msg_debug( debugmode::DF_MELEE, "Not using weapon from a valid category, attack discarded" ); return false; } } @@ -826,10 +837,7 @@ ma_technique::ma_technique() block_counter = false; // like tec_counter // conditional - downed_target = false; // only works on downed enemies - stunned_target = false; // only works on stunned enemies wall_adjacent = false; // only works near a wall - human_target = false; // only works on humanoid enemies needs_ammo = false; // technique only works if the item is loaded with ammo @@ -1828,6 +1836,8 @@ std::string ma_technique::get_description() const dump += reqs.get_description(); + dump += string_format( _( condition_desc ) ) + "\n"; + if( weighting > 1 ) { dump += string_format( _( "* Greater chance to activate: +%s%%" ), ( 100 * ( weighting - 1 ) ) ) + "\n"; @@ -1852,18 +1862,6 @@ std::string ma_technique::get_description() const std::string( "\n" ); } - if( downed_target ) { - dump += _( "* Only works on a downed target" ) + std::string( "\n" ); - } - - if( stunned_target ) { - dump += _( "* Only works on a stunned target" ) + std::string( "\n" ); - } - - if( human_target ) { - dump += _( "* Only works on a humanoid target" ) + std::string( "\n" ); - } - if( powerful_knockback ) { dump += _( "* Causes extra damage on knockback collision." ) + std::string( "\n" ); } diff --git a/src/martialarts.h b/src/martialarts.h index 05ff0bd42aecf..5dd71e9067b7a 100644 --- a/src/martialarts.h +++ b/src/martialarts.h @@ -180,13 +180,15 @@ class ma_technique int weighting = 0; //how often this technique is used // conditional - bool downed_target = false; // only works on downed enemies - bool stunned_target = false;// only works on stunned enemies bool wall_adjacent = false; // only works near a wall - bool human_target = false; // only works on humanoid enemies bool needs_ammo = false; // technique only works if the item is loaded with ammo + // Dialogue conditions of the attack + std::function condition; + std::string condition_desc; + bool has_condition = false; + /** All kinds of bonuses by types to damage, hit etc. */ bonus_container bonuses; diff --git a/src/melee.cpp b/src/melee.cpp index c9896ab7b956c..66a9f40f10be9 100644 --- a/src/melee.cpp +++ b/src/melee.cpp @@ -141,8 +141,6 @@ static const skill_id skill_spellcraft( "spellcraft" ); static const skill_id skill_stabbing( "stabbing" ); static const skill_id skill_unarmed( "unarmed" ); -static const species_id species_HUMAN( "HUMAN" ); - static const trait_id trait_ARM_TENTACLES( "ARM_TENTACLES" ); static const trait_id trait_ARM_TENTACLES_4( "ARM_TENTACLES_4" ); static const trait_id trait_ARM_TENTACLES_8( "ARM_TENTACLES_8" ); @@ -1458,17 +1456,22 @@ void Character::roll_damage( const damage_type_id &dt, bool crit, damage_instanc di.add_damage( dt, other_dam, arpen, armor_mult, other_mul ); } } - matec_id Character::pick_technique( Creature &t, const item_location &weap, bool crit, bool dodge_counter, bool block_counter ) { + std::vector possible = evaluate_techniques( t, weap, crit, + dodge_counter, block_counter ); + return random_entry( possible, tec_none ); +} +std::vector Character::evaluate_techniques( Creature &t, const item_location &weap, + bool crit, + bool dodge_counter, bool block_counter ) +{ const std::vector all = martial_arts_data->get_all_techniques( weap, *this ); std::vector possible; - bool downed = t.has_effect( effect_downed ); - bool stunned = t.has_effect( effect_stunned ); bool wall_adjacent = get_map().is_wall_adjacent( pos() ); // this could be more robust but for now it should work fine bool is_loaded = weap && weap->is_magazine_full(); @@ -1476,28 +1479,43 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool // first add non-aoe tecs for( const matec_id &tec_id : all ) { const ma_technique &tec = tec_id.obj(); + add_msg_debug( debugmode::DF_MELEE, "Evaluating technique %s", tec.name ); // ignore "dummy" techniques like WBLOCK_1 if( tec.dummy ) { + add_msg_debug( debugmode::DF_MELEE, "Dummy technique, attack discarded" ); continue; } // skip defensive techniques if( tec.defensive ) { + add_msg_debug( debugmode::DF_MELEE, "Defensive technique, attack discarded" ); continue; } + // Ignore this technique if we fail the doalog conditions + if( tec.has_condition ) { + dialogue d( get_talker_for( this ), get_talker_for( t ) ); + if( !tec.condition( d ) ) { + add_msg_debug( debugmode::DF_MELEE, "Conditionas failed, attack discarded" ); + continue; + } + } + // skip wall adjacent techniques if not next to a wall if( tec.wall_adjacent && !wall_adjacent ) { + add_msg_debug( debugmode::DF_MELEE, "No adjacent walls found, attack discarded" ); continue; } // skip dodge counter techniques if it's not a dodge count, and vice versa if( dodge_counter != tec.dodge_counter ) { + add_msg_debug( debugmode::DF_MELEE, "Not a dodge counter, attack discarded" ); continue; } // likewise for block counters if( block_counter != tec.block_counter ) { + add_msg_debug( debugmode::DF_MELEE, "Not a block counter, attack discarded" ); continue; } @@ -1510,6 +1528,8 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool float move_mult = exertion_adjusted_move_multiplier( EXTRA_EXERCISE ); move_cost *= ( 1.0f / move_mult ); if( get_moves() + get_speed() - move_cost < 0 ) { + add_msg_debug( debugmode::DF_MELEE, + "Counter technique would exhaust remaining moves, attack discarded" ); continue; } } @@ -1517,26 +1537,13 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool // if critical then select only from critical tecs // but allow the technique if its crit ok if( !tec.crit_ok && ( crit != tec.crit_tec ) ) { + add_msg_debug( debugmode::DF_MELEE, "Attack is%s critical, attack discarded", crit ? "" : "n't" ); continue; } // if the technique needs a loaded weapon and it isn't loaded skip it if( tec.needs_ammo && !is_loaded ) { - continue; - } - - // don't apply downing techniques to someone who's already downed - if( downed && tec.down_dur > 0 ) { - continue; - } - - // don't apply "downed only" techniques to someone who's not downed - if( !downed && tec.downed_target ) { - continue; - } - - // don't apply "stunned only" techniques to someone who's not stunned - if( !stunned && tec.stunned_target ) { + add_msg_debug( debugmode::DF_MELEE, "No ammo, attack discarded" ); continue; } @@ -1545,24 +1552,27 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool // dice( dex_cur + get_skill_level("unarmed"), 8) > // dice(p->dex_cur + p->get_skill_level("melee"), 10)) if( tec.disarms && !t.has_weapon() ) { + add_msg_debug( debugmode::DF_MELEE, + "Disarming technique against unarmed opponent, attack discarded" ); continue; } if( tec.take_weapon && ( has_weapon() || !t.has_weapon() ) ) { + add_msg_debug( debugmode::DF_MELEE, "Weapon-taking technique %s, attack discarded", + has_weapon() ? "while armed" : "against an unarmed opponent" ); continue; } - // Don't apply humanoid-only techniques to non-humanoids - if( tec.human_target && !t.in_species( species_HUMAN ) ) { - continue; - } // if aoe, check if there are valid targets if( !tec.aoe.empty() && !valid_aoe_technique( t, tec ) ) { + add_msg_debug( debugmode::DF_MELEE, "AoE technique witout valid AoE targets, attack discarded" ); continue; } // If we have negative weighting then roll to see if it's valid this time if( tec.weighting < 0 && !one_in( std::abs( tec.weighting ) ) ) { + add_msg_debug( debugmode::DF_MELEE, + "Negative technique weighting failed weight roll, attack discarded" ); continue; } @@ -1571,6 +1581,7 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool std::shuffle( shuffled_attack_vectors.begin(), shuffled_attack_vectors.end(), rng_get_engine() ); if( martial_arts_data->get_valid_attack_vector( *this, tec.attack_vectors ) == "NONE" && martial_arts_data->get_valid_attack_vector( *this, shuffled_attack_vectors ) == "NONE" ) { + add_msg_debug( debugmode::DF_MELEE, "No valid attack vector found, attack discarded" ); continue; } @@ -1586,7 +1597,7 @@ matec_id Character::pick_technique( Creature &t, const item_location &weap, bool } } - return random_entry( possible, tec_none ); + return possible; } bool Character::valid_aoe_technique( Creature &t, const ma_technique &technique ) @@ -1739,10 +1750,11 @@ static void print_damage_info( const damage_instance &di ) add_msg_debug( debugmode::DF_MELEE, "%stotal: %d", ss, total ); } -void Character::perform_technique( const ma_technique &technique, Creature &t, damage_instance &di, +void Character::perform_technique( const ma_technique &technique, Creature &t, + damage_instance &di, int &move_cost, item_location &cur_weapon ) { - add_msg_debug( debugmode::DF_MELEE, "dmg before tec:" ); + add_msg_debug( debugmode::DF_MELEE, "Chose technique %s\ndmg before tec:", technique.name ); print_damage_info( di ); int rep = rng( technique.repeat_min, technique.repeat_max ); add_msg_debug( debugmode::DF_MELEE, "Tech repeats %d times", rep ); @@ -2455,7 +2467,8 @@ std::vector Character::mutation_attacks( Creature &t ) const return ret; } -std::string melee_message( const ma_technique &tec, Character &p, const dealt_damage_instance &ddi ) +std::string melee_message( const ma_technique &tec, Character &p, + const dealt_damage_instance &ddi ) { // Those could be extracted to a json diff --git a/src/monster.cpp b/src/monster.cpp index 756ab1851aeb7..9feb05fdf89bc 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -1095,7 +1095,15 @@ bool monster::has_flag( const m_flag f ) const bool monster::has_flag( const flag_id f ) const { - return has_effect_with_flag( f ); + std::optionalchecked = io::string_to_enum_optional( f.c_str() ); + add_msg_debug( debugmode::DF_MONSTER, + "Monster %s checked for flag %s", name(), + f.c_str() ); + if( checked.has_value() ) { + return has_flag( checked.value() ); + } else { + return has_effect_with_flag( f ); + } } bool monster::can_see() const diff --git a/src/monster.h b/src/monster.h index 3eab965d2b130..1a023676df7e7 100644 --- a/src/monster.h +++ b/src/monster.h @@ -159,6 +159,7 @@ class monster : public Creature std::string extended_description() const override; // Inverts color if inv==true bool has_flag( m_flag f ) const override; // Returns true if f is set (see mtype.h) + // Evaluates monster for both JSON and monster flags (converted to m_flag) bool has_flag( flag_id f ) const; bool can_see() const; // MF_SEES and no MF_BLIND bool can_hear() const; // MF_HEARS and no MF_DEAF diff --git a/src/talker.h b/src/talker.h index 4830f0541c266..fce2ea3026152 100644 --- a/src/talker.h +++ b/src/talker.h @@ -5,6 +5,8 @@ #include "coordinates.h" #include "effect.h" #include "item.h" +#include "messages.h" +#include "type_id.h" #include "units.h" #include "units_fwd.h" #include @@ -21,6 +23,8 @@ class recipe; struct tripoint; class vehicle; +using bodytype_id = std::string; + /* * Talker is an entity independent way of providing a participant in a dialogue. * Talker is a virtual abstract class and should never really be used. Instead, @@ -210,6 +214,15 @@ class talker virtual bool has_flag( const json_character_flag & ) const { return false; } + virtual bool has_species( const species_id & ) const { + return false; + } + virtual bool bodytype( const bodytype_id & ) const { + return false; + } + virtual int get_grab_strength() const { + return 0; + } virtual bool crossed_threshold() const { return false; } @@ -457,6 +470,9 @@ class talker virtual int get_healthy_kcal() const { return 0; } + virtual int get_size() const { + return 0; + } virtual int get_stim() const { return 0; } diff --git a/src/talker_character.cpp b/src/talker_character.cpp index 8990a60f2d34c..a94a6cce11b73 100644 --- a/src/talker_character.cpp +++ b/src/talker_character.cpp @@ -251,6 +251,23 @@ bool talker_character_const::has_flag( const json_character_flag &trait_flag_to_ return me_chr_const->has_flag( trait_flag_to_check ); } +bool talker_character_const::has_species( const species_id &species ) const +{ + add_msg_debug( debugmode::DF_TALKER, "Character %s checked for species %s", me_chr_const->name, + species.c_str() ); + return me_chr_const->in_species( species ); +} + +bool talker_character_const::bodytype( const bodytype_id &bt ) const +{ + add_msg_debug( debugmode::DF_TALKER, "Character %s checked for bodytype %s", me_chr_const->name, + bt ); + // All characters are human-bodytyped for now + // TODO: Change that for very limby characters + return bt == "human"; +} + + bool talker_character_const::crossed_threshold() const { return me_chr_const->crossed_threshold(); @@ -566,6 +583,13 @@ int talker_character_const::get_healthy_kcal() const return me_chr_const->get_healthy_kcal(); } +int talker_character_const::get_size() const +{ + add_msg_debug( debugmode::DF_TALKER, "Size category of character %s = %d", me_chr_const->name, + me_chr_const->get_size() - 0 ); + return me_chr_const->get_size() - 0; +} + void talker_character::set_stored_kcal( int value ) { me_chr->set_stored_kcal( value ); diff --git a/src/talker_character.h b/src/talker_character.h index 5b9af42a60838..a73d19b2b33ae 100644 --- a/src/talker_character.h +++ b/src/talker_character.h @@ -69,6 +69,8 @@ class talker_character_const: public talker_cloner bool has_trait( const trait_id &trait_to_check ) const override; bool has_recipe( const recipe_id &recipe_to_check ) const override; bool has_flag( const json_character_flag &trait_flag_to_check ) const override; + bool has_species( const species_id &species ) const override; + bool bodytype( const bodytype_id &bt ) const override; bool crossed_threshold() const override; int num_bionics() const override; bool has_max_power() const override; @@ -117,6 +119,7 @@ class talker_character_const: public talker_cloner int get_instant_thirst() const override; int get_stored_kcal() const override; int get_healthy_kcal() const override; + int get_size() const override; bool is_in_control_of( const vehicle &veh ) const override; bool worn_with_flag( const flag_id &flag, const bodypart_id &bp ) const override; diff --git a/src/talker_monster.cpp b/src/talker_monster.cpp index ea2e635c15c6a..3d0f9c2dc615d 100644 --- a/src/talker_monster.cpp +++ b/src/talker_monster.cpp @@ -3,7 +3,6 @@ #include "effect.h" #include "item.h" #include "magic.h" -#include "messages.h" #include "monster.h" #include "mtype.h" #include "pimpl.h" @@ -99,6 +98,20 @@ bool talker_monster_const::has_flag( const flag_id &f ) const return me_mon_const->has_flag( f ); } +bool talker_monster_const::has_species( const species_id &species ) const +{ + add_msg_debug( debugmode::DF_TALKER, "Monster %s checked for species %s", me_mon_const->name(), + species.c_str() ); + return me_mon_const->in_species( species ); +} + +bool talker_monster_const::bodytype( const bodytype_id &bt ) const +{ + add_msg_debug( debugmode::DF_TALKER, "Monster %s checked for bodytype %s", me_mon_const->name(), + bt ); + return me_mon_const->type->bodytype == bt; +} + void talker_monster::set_value( const std::string &var_name, const std::string &value ) { me_mon->set_value( var_name, value ); @@ -139,6 +152,19 @@ int talker_monster_const::get_friendly() const return me_mon_const->friendly; } +int talker_monster_const::get_size() const +{ + add_msg_debug( debugmode::DF_TALKER, "Size category of monster %s = %d", me_mon_const->name(), + me_mon_const->get_size() - 0 ); + return me_mon_const->get_size() - 0; +} + +int talker_monster_const::get_grab_strength() const +{ + add_msg_debug( debugmode::DF_TALKER, "Grab strength of monster %s = %d", me_mon_const->name(), + me_mon_const->get_grab_strength() ); + return me_mon_const->get_grab_strength(); +} void talker_monster::set_friendly( int new_val ) { me_mon->friendly = new_val; diff --git a/src/talker_monster.h b/src/talker_monster.h index 7169bd47d243d..4cdfa3412fa75 100644 --- a/src/talker_monster.h +++ b/src/talker_monster.h @@ -49,11 +49,15 @@ class talker_monster_const: public talker_cloner std::string get_value( const std::string &var_name ) const override; bool has_flag( const flag_id &f ) const override; + bool has_species( const species_id &species ) const override; + bool bodytype( const bodytype_id &bt ) const override; std::string short_description() const override; int get_anger() const override; int morale_cur() const override; int get_friendly() const override; + int get_size() const override; + int get_grab_strength() const override; bool will_talk_to_u( const Character &u, bool force ) override; std::vector get_topics( bool radio_contact ) override; int get_cur_hp( const bodypart_id & ) const override; diff --git a/tests/iteminfo_test.cpp b/tests/iteminfo_test.cpp index 38731408afed4..9888600bd782e 100644 --- a/tests/iteminfo_test.cpp +++ b/tests/iteminfo_test.cpp @@ -707,18 +707,18 @@ TEST_CASE( "techniques when wielded", "[iteminfo][weapon][techniques]" ) "--\n" "Techniques when wielded:" " Brutal Strike:" - " Stun 1 turn, knockback 1 tile, crit only," + " Stun 1 turn, knockback 1 tile, crit only * Only works on a non-stunned mundane target of similar or smaller size, may fail on enemies grabbing you," " Sweep Attack:" - " Down 2 turns, and" + " Down 2 turns * Only works on a non-downed humanoid target of similar or smaller size incapable of flight, and" " Block:" - " Medium blocking ability\n" ); + " Medium blocking ability \n" ); item plank( "test_2x4" ); CHECK( item_info_str( plank, { iteminfo_parts::DESCRIPTION_TECHNIQUES } ) == "--\n" "Techniques when wielded:" " Block:" - " Medium blocking ability\n" ); + " Medium blocking ability \n" ); } static std::vector bodyparts_to_check() diff --git a/tests/martial_art_test.cpp b/tests/martial_art_test.cpp index 748d49da94cb8..c164ec5da1755 100644 --- a/tests/martial_art_test.cpp +++ b/tests/martial_art_test.cpp @@ -4,13 +4,30 @@ #include "avatar.h" #include "character_martial_arts.h" #include "martialarts.h" +#include "map_helpers.h" +#include "mtype.h" #include "npc.h" +static const efftype_id effect_downed( "downed" ); +static const efftype_id effect_grabbed( "grabbed" ); +static const efftype_id effect_grabbing( "grabbing" ); +static const efftype_id effect_stunned( "stunned" ); + +static const itype_id itype_club_wooden( "club_wooden" ); +static const itype_id itype_sword_wood( "sword_wood" ); static const itype_id itype_test_weapon1( "test_weapon1" ); static const itype_id itype_test_weapon2( "test_weapon2" ); + +static const matec_id test_tech_condition_knockback( "test_tech_condition_knockback" ); +static const matec_id test_tech_condition_stun( "test_tech_condition_stun" ); +static const matec_id test_tech_condition_sweep( "test_tech_condition_sweep" ); +static const matec_id test_technique( "test_technique" ); static const matype_id test_style_ma1( "test_style_ma1" ); +static const species_id species_SLIME( "SLIME" ); +static const species_id species_ZOMBIE( "ZOMBIE" ); + static constexpr tripoint dude_pos( HALF_MAPSIZE_X, HALF_MAPSIZE_Y, 0 ); TEST_CASE( "martial arts", "[martial_arts]" ) @@ -48,7 +65,7 @@ TEST_CASE( "Martial art required weapon categories", "[martial_arts]" ) SECTION( "Weapon categories required for technique" ) { REQUIRE( !test_style_ma1->techniques.empty() ); - const matec_id &tec = *test_style_ma1->techniques.begin(); + const matec_id &tec = *test_style_ma1->techniques.find( test_technique ); REQUIRE( tec->reqs.weapon_categories_allowed[0] == *test_style_ma1->weapon_category.begin() ); standard_npc dude( "TestCharacter", dude_pos, {}, 0, 8, 8, 8, 8 ); @@ -61,3 +78,87 @@ TEST_CASE( "Martial art required weapon categories", "[martial_arts]" ) CHECK( tec->is_valid_character( dude ) ); } } + +TEST_CASE( "Martial art technique conditionals", "[martial_arts]" ) +{ + standard_npc dude( "TestCharacter", dude_pos, {}, 0, 8, 8, 8, 8 ); + const tripoint target_1_pos = dude_pos + tripoint_east; + const tripoint target_2_pos = dude_pos + tripoint_north; + const tripoint target_3_pos = dude_pos + tripoint_west; + clear_character( dude, true ); + clear_creatures(); + dude.martial_arts_data->add_martialart( test_style_ma1 ); + dude.martial_arts_data->set_style( test_style_ma1, false ); + REQUIRE( dude.get_size() == 3 ); + SECTION( "Test sweep" ) { + const matec_id &tec = *test_style_ma1->techniques.find( test_tech_condition_sweep ); + monster &target_1 = spawn_test_monster( "mon_zombie_fat", target_1_pos ); + monster &target_2 = spawn_test_monster( "mon_zombie_hulk", target_2_pos ); + monster &target_3 = spawn_test_monster( "mon_blob", target_3_pos ); + std::vector tech_1 = dude.evaluate_techniques( target_1, dude.used_weapon() ); + + // test sweeping a zombie (succeed) + REQUIRE( target_1.get_size() == 3 ); + CHECK( tech_1.size() == 1 ); + CHECK( std::find( tech_1.begin(), tech_1.end(), tec ) != tech_1.end() ); + // Being downed disables the attack + target_1.add_effect( effect_downed, 1_days ); + CHECK( dude.evaluate_techniques( target_1, dude.used_weapon() ).empty() ); + // test sweeping a big zomb (fail) + REQUIRE( target_2.get_size() == 5 ); + CHECK( dude.evaluate_techniques( target_2, dude.used_weapon() ).empty() ); + // test sweeping a slime (fail) + REQUIRE( target_3.get_size() == 3 ); + REQUIRE( target_3.type->bodytype == "blob" ); + CHECK( dude.evaluate_techniques( target_3, dude.used_weapon() ).empty() ); + } + + SECTION( "Test stun" ) { + const matec_id &tec = *test_style_ma1->techniques.find( test_tech_condition_stun ); + monster &target_1 = spawn_test_monster( "mon_feral_human_pipe", target_1_pos ); + monster &target_2 = spawn_test_monster( "mon_zombie_fat", target_2_pos ); + monster &target_3 = spawn_test_monster( "mon_blob", target_3_pos ); + item weap( itype_sword_wood ); + dude.wield( weap ); + // test stunning a feral (succeed) + std::vector tech_1 = dude.evaluate_techniques( target_1, dude.used_weapon() ); + REQUIRE( target_1.get_size() == 3 ); + REQUIRE( !target_1.type->in_species( species_ZOMBIE ) ); + CHECK( std::find( tech_1.begin(), tech_1.end(), tec ) != tech_1.end() ); + // Being downed disables the attack + target_1.add_effect( effect_stunned, 1_days ); + CHECK( dude.evaluate_techniques( target_1, dude.used_weapon() ).empty() ); + // test stunning a zombie (fail) + REQUIRE( target_2.get_size() == 3 ); + REQUIRE( target_2.type->in_species( species_ZOMBIE ) ); + CHECK( dude.evaluate_techniques( target_2, dude.used_weapon() ).empty() ); + // test stunning a slime (fail) + REQUIRE( target_3.get_size() == 3 ); + REQUIRE( target_3.type->in_species( species_SLIME ) ); + CHECK( dude.evaluate_techniques( target_3, dude.used_weapon() ).empty() ); + } + SECTION( "Test knockback" ) { + const matec_id &tec = *test_style_ma1->techniques.find( test_tech_condition_knockback ); + monster &target_1 = spawn_test_monster( "mon_feral_human_pipe", target_1_pos ); + monster &target_2 = spawn_test_monster( "mon_zombie_hulk", target_2_pos ); + monster &target_3 = spawn_test_monster( "mon_test_tech_grabber", target_3_pos ); + item weap( itype_club_wooden ); + dude.wield( weap ); + // test throwing a feral (succeed) + std::vector tech_1 = dude.evaluate_techniques( target_1, dude.used_weapon() ); + REQUIRE( target_1.get_size() == 3 ); + CHECK( std::find( tech_1.begin(), tech_1.end(), tec ) != tech_1.end() ); + // Being downed disables the attack + target_1.add_effect( effect_downed, 1_days ); + CHECK( dude.evaluate_techniques( target_1, dude.used_weapon() ).empty() ); + // test throwing a large target (fail) + REQUIRE( target_2.get_size() == 5 ); + CHECK( dude.evaluate_techniques( target_2, dude.used_weapon() ).empty() ); + // test throwing a monster grabbing you (succeed) + dude.add_effect( effect_grabbed, 1_days ); + target_3.add_effect( effect_grabbing, 1_days ); + REQUIRE( target_3.get_size() == 4 ); + REQUIRE( target_3.get_grab_strength() == 0 ); + CHECK( dude.evaluate_techniques( target_3, dude.used_weapon() ).size() == 1 ); + } +} diff --git a/tests/materials_test.cpp b/tests/materials_test.cpp index 67fc095d44329..a2cf17bb2c2de 100644 --- a/tests/materials_test.cpp +++ b/tests/materials_test.cpp @@ -3,6 +3,7 @@ #include "fire.h" #include "item.h" #include "cata_catch.h" +#include "map_helpers.h" #include "npc.h" #include "projectile.h" @@ -70,6 +71,7 @@ TEST_CASE( "Portioned material flammability", "[material]" ) TEST_CASE( "Glass portion breakability", "[material] [slow]" ) { + clear_creatures(); standard_npc dude( "TestCharacter", dude_pos, {}, 0, 8, 8, 8, 8 ); item mostly_glass( "test_glass_pipe_mostly_glass" ); item mostly_steel( "test_glass_pipe_mostly_steel" );