From 50a304d923d9a81f76a60996141ab0681378611c Mon Sep 17 00:00:00 2001 From: doug1234 Date: Fri, 16 Feb 2024 22:13:22 -0500 Subject: [PATCH 1/3] Added shield feats from Sagenlicht Co-authored-by: Sagenlicht --- .../tpgamefiles/mes/help/new_feats_help.tab | 24 +++++---- .../rules/feats/active shield defense.txt | 5 ++ .../tpgamefiles/rules/feats/shield charge.txt | 5 ++ .../rules/feats/shield specialization.txt | 5 ++ .../tpgamefiles/rules/feats/shield ward.txt | 5 ++ .../scr/feats/feat - Active Shield Defense.py | 9 ++++ .../scr/feats/feat - Shield Charge.py | 10 ++++ .../scr/feats/feat - Shield Specialization.py | 7 +++ .../scr/feats/feat - Shield Ward.py | 9 ++++ .../scr/tpModifiers/active_shield_defense.py | 40 ++++++++++++++ .../scr/tpModifiers/shield_charge.py | 41 +++++++++++++++ .../scr/tpModifiers/shield_specialization.py | 34 ++++++++++++ .../scr/tpModifiers/shield_ward.py | 52 +++++++++++++++++++ .../scr/tpModifiers/total_defense.py | 18 +++++-- 14 files changed, 249 insertions(+), 15 deletions(-) create mode 100644 tpdatasrc/tpgamefiles/rules/feats/active shield defense.txt create mode 100644 tpdatasrc/tpgamefiles/rules/feats/shield charge.txt create mode 100644 tpdatasrc/tpgamefiles/rules/feats/shield specialization.txt create mode 100644 tpdatasrc/tpgamefiles/rules/feats/shield ward.txt create mode 100644 tpdatasrc/tpgamefiles/scr/feats/feat - Active Shield Defense.py create mode 100644 tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py create mode 100644 tpdatasrc/tpgamefiles/scr/feats/feat - Shield Specialization.py create mode 100644 tpdatasrc/tpgamefiles/scr/feats/feat - Shield Ward.py create mode 100644 tpdatasrc/tpgamefiles/scr/tpModifiers/active_shield_defense.py create mode 100644 tpdatasrc/tpgamefiles/scr/tpModifiers/shield_charge.py create mode 100644 tpdatasrc/tpgamefiles/scr/tpModifiers/shield_specialization.py create mode 100644 tpdatasrc/tpgamefiles/scr/tpModifiers/shield_ward.py diff --git a/tpdatasrc/tpgamefiles/mes/help/new_feats_help.tab b/tpdatasrc/tpgamefiles/mes/help/new_feats_help.tab index 398cdb18d..60f280c14 100644 --- a/tpdatasrc/tpgamefiles/mes/help/new_feats_help.tab +++ b/tpdatasrc/tpgamefiles/mes/help/new_feats_help.tab @@ -1,10 +1,14 @@ -TAG_AXIOMATIC_STRIKE TAG_FEATS_DES Axiomatic Strike You can turn your fist into an instrument of law. Prerequisite: ~Stunning Fist~[TAG_STUNNING_FIST], ~Ki strike~[TAG_CLASS_FEATURES_MONK_KI_STRIKE] (lawful) Benefit: Against a chaotic opponent, you can make an unarmed attack that does an extra 2d6 points of damage. You must declare that you are using this feat before you make your attack roll (thus, a failed attack ruins the attempt). Each attempt counts as one of your uses of the Stunning Fist feat for the day. Creatures immune to stunning can be affected by this extra damage. -TAG_BRUTAL_THROW TAG_FEATS_DES Brutal Throw You have learned how to hurl weapons to deadly effect. Prerequisite: Benefit: You can add your Strength modifier (instead of your Dexterity modifier) to ~attack rolls~[TAG_RANGED_ATTACKS] with thrown weapons. Special: A fighter may select Brutal Throw as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. Normal: A character attacking with a ranged weapon adds his Dexterity modifier to the attack roll. -TAG_FIERY_FIST TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Fiery Fist By channeling your Ki energy, you sheathe your limbs in magical fire. Your unarmed strikes deal extra fire damage. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: As a swift action, you can expend one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat to surround your fists and feet in flame. For the rest of your turn, you gain an extra 1d6 points of firedamage on your unarmed strikes. When you select this feat, you gain an additional daily use of Stunning Fist. Special: A fighter can select Fiery Fist as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Fiery Fist as her bonus feat at 2nd level, even if she does not meet the other prerequisites. -TAG_FIERY_KI_DEFENSE TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Fiery Ki Defense You channel your ki energy into a cloak of fl ame that injures all who attempt to strike you. Prerequisite: ~Fiery Fist~[TAG_FIERY_FIST], ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: As a swift action, you can expend one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat to cloak yourself in flame. Any creature that strikes you with a ~melee attack~[TAG_MELEE_ATTACKS] takes 1d6 points of fire damage. This benefit lasts until the start of your next turn. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Fiery Ki Defense as her bonus feat at 6th level, as long as she also possesses the Fiery Fist feat (other prerequisites can be ignored). -TAG_FISTS_OF_IRON TAG_FEATS_DES Fists of Iron You have learned the secrets of imbuing your unarmed attacks with extra force. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], base attack bonus +2, Benefit: Declare that you are using this feat before you make your attack roll (thus, a missed attack roll ruins the attempt). You deal an extra 1d6 points of damage when you make a successful unarmed attack. Each attempt counts as one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat for the day. -TAG_FLYING_KICK TAG_FEATS_DES Flying Kick You literally leap into battle, dealing devastating damage. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Power Attack~[TAG_POWER_ATTACK], ~Strength~[TAG_STRENGTH] 13, Jump 4 ranks (omitted as jump is not in the game) Benefit: When fighting unarmed and using the ~charge~[TAG_CHARGE] action, you deal an extra 1d12 points of damage with your unarmed attack. -TAG_FREEZING_THE_LIFEBLOOD TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Freezing the Lifeblood You can paralyze a humanoid opponent with an unarmed attack. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Wisdom~[TAG_WISDOM] 17, base attack bonus +10 Benefit: Declare that you are using this feat before you make your attack roll (thus, a missed attack roll ruins the attempt). Against a humanoid opponent, you can make an unarmed attack that deals no damage but has a chance of ~paralyzing~[TAG_PARALYZED] your target. If your attack is successful, your target must attempt a Fortitude saving throw (DC 10 + 1/2 your character level + your Wis modifier). If the target fails this saving throw, it is paralyzed for 1d4+1 rounds. Each attempt to paralyze an opponent counts as one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat for the day. Creatures immune to stunning cannot be paralyzed in this manner. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. -TAG_KI_BLAST TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Ki Blast You focus your ki into a ball of energy that you can hurl at an opponent. Prerequisite: ~Fiery Fist~[TAG_FIERY_FIST], ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: You can expend two daily uses of your ~Stunning Fist~[TAG_STUNNING_FIST] feat as a move action to create an orb of raw ki energy. You can then throw the seething orb as a standard action with a range of 60 feet. This ranged touch attack deals damage equal to 3d6 points + your Wis modifier. The ki orb is a force effect. If you fail to throw the orb before the end of your turn, it dissipates harmlessly. When you take this feat, you gain an additional daily use of ~Stunning Fist~[TAG_STUNNING_FIST]. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Ki Blast as her bonus feat at 6th level, as long as she also possesses the Fiery Fist feat (other prerequisites can be ignored). -TAG_POWER_THROW TAG_FEATS_DES Power Throw You have learned how to hurl weapons to deadly effect. Prerequisite: ~Strength~[TAG_STRENGTH] 13, ~Brutal Throw~[TAG_BRUTAL_THROW], ~Power Attack~[TAG_POWER_ATTACK] Benefit: On your turn, before making any attack rolls, you can choose to subtract a number from all ~thrown weapon attack rolls~[TAG_RANGED_ATTACKS] and add the same number to all thrown weapon damage rolls. This number may not exceed your base attack bonus. The penalty on attack rolls and the bonus on damage rolls applies until your next turn. Special: A fighter may select Brutal Throw as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. -TAG_ZEN_ARCHERY TAG_FEATS_DES Zen Archery Your intuition guides your hand when you use a ranged weapon. Prerequisite: ~Wisdom~[TAG_WISDOM] 13, base attack bonus +1 Benefit: You can use your Wisdom modifier instead of your Dexterity modifier when making a ~ranged attack~[TAG_RANGED_ATTACKS] roll. +TAG_ACTIVE_SHIELD_DEFENSE TAG_FEATS_DES Active Shield Defense Your expert use of your shield allows you to strike at vulnerable foes even when you forgo your own attacks in favor of defense. Prerequisite: ~Proficiency with Shields~[TAG_SHIELD_PROF], ~Shield Specialization~[TAG_SHIELD_SPECIALIZATION]. Benefit: When ~fighting defensively~[TAG_RADIAL_MENU_FIGHT_DEFENSIVELY] and using a shield, you do not take the standard fighting defensively penalties on ~attacks of opportunity~[TAG_AOO]. When using the ~total defense~[TAG_RADIAL_MENU_TOTAL_DEFENSE] action and a shield, you still threaten the area around you as normal. You can make ~attacks of opportunity~[TAG_AOO] with a -4 penalty. Normal: You take a -4 penalty on all attacks while fighting defensively. You cannot attack while using the total defense action. Special: A fighter can select Active Shield Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_AXIOMATIC_STRIKE TAG_FEATS_DES Axiomatic Strike You can turn your fist into an instrument of law. Prerequisite: ~Stunning Fist~[TAG_STUNNING_FIST], ~Ki strike~[TAG_CLASS_FEATURES_MONK_KI_STRIKE] (lawful) Benefit: Against a chaotic opponent, you can make an unarmed attack that does an extra 2d6 points of damage. You must declare that you are using this feat before you make your attack roll (thus, a failed attack ruins the attempt). Each attempt counts as one of your uses of the Stunning Fist feat for the day. Creatures immune to stunning can be affected by this extra damage. +TAG_BRUTAL_THROW TAG_FEATS_DES Brutal Throw You have learned how to hurl weapons to deadly effect. Prerequisite: Benefit: You can add your Strength modifier (instead of your Dexterity modifier) to ~attack rolls~[TAG_RANGED_ATTACKS] with thrown weapons. Special: A fighter may select Brutal Throw as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. Normal: A character attacking with a ranged weapon adds his Dexterity modifier to the attack roll. +TAG_FIERY_FIST TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Fiery Fist By channeling your Ki energy, you sheathe your limbs in magical fire. Your unarmed strikes deal extra fire damage. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: As a swift action, you can expend one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat to surround your fists and feet in flame. For the rest of your turn, you gain an extra 1d6 points of firedamage on your unarmed strikes. When you select this feat, you gain an additional daily use of Stunning Fist. Special: A fighter can select Fiery Fist as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Fiery Fist as her bonus feat at 2nd level, even if she does not meet the other prerequisites. +TAG_FIERY_KI_DEFENSE TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Fiery Ki Defense You channel your ki energy into a cloak of fl ame that injures all who attempt to strike you. Prerequisite: ~Fiery Fist~[TAG_FIERY_FIST], ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: As a swift action, you can expend one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat to cloak yourself in flame. Any creature that strikes you with a ~melee attack~[TAG_MELEE_ATTACKS] takes 1d6 points of fire damage. This benefit lasts until the start of your next turn. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Fiery Ki Defense as her bonus feat at 6th level, as long as she also possesses the Fiery Fist feat (other prerequisites can be ignored). +TAG_FISTS_OF_IRON TAG_FEATS_DES Fists of Iron You have learned the secrets of imbuing your unarmed attacks with extra force. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], base attack bonus +2, Benefit: Declare that you are using this feat before you make your attack roll (thus, a missed attack roll ruins the attempt). You deal an extra 1d6 points of damage when you make a successful unarmed attack. Each attempt counts as one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat for the day. +TAG_FLYING_KICK TAG_FEATS_DES Flying Kick You literally leap into battle, dealing devastating damage. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Power Attack~[TAG_POWER_ATTACK], ~Strength~[TAG_STRENGTH] 13, Jump 4 ranks (omitted as jump is not in the game) Benefit: When fighting unarmed and using the ~charge~[TAG_CHARGE] action, you deal an extra 1d12 points of damage with your unarmed attack. +TAG_FREEZING_THE_LIFEBLOOD TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Freezing the Lifeblood You can paralyze a humanoid opponent with an unarmed attack. Prerequisite: ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Wisdom~[TAG_WISDOM] 17, base attack bonus +10 Benefit: Declare that you are using this feat before you make your attack roll (thus, a missed attack roll ruins the attempt). Against a humanoid opponent, you can make an unarmed attack that deals no damage but has a chance of ~paralyzing~[TAG_PARALYZED] your target. If your attack is successful, your target must attempt a Fortitude saving throw (DC 10 + 1/2 your character level + your Wis modifier). If the target fails this saving throw, it is paralyzed for 1d4+1 rounds. Each attempt to paralyze an opponent counts as one of your uses of the ~Stunning Fist~[TAG_STUNNING_FIST] feat for the day. Creatures immune to stunning cannot be paralyzed in this manner. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_KI_BLAST TAG_FEATS_DES TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS Ki Blast You focus your ki into a ball of energy that you can hurl at an opponent. Prerequisite: ~Fiery Fist~[TAG_FIERY_FIST], ~Improved Unarmed Strike~[TAG_CLASS_FEATURES_MONK_UNARMED_STRIKE], ~Stunning Fist~[TAG_STUNNING_FIST], ~Dexterity~[TAG_DEXTERITY] 13, ~Wisdom~[TAG_WISDOM] 13, base attack bonus +8 Benefit: You can expend two daily uses of your ~Stunning Fist~[TAG_STUNNING_FIST] feat as a move action to create an orb of raw ki energy. You can then throw the seething orb as a standard action with a range of 60 feet. This ranged touch attack deals damage equal to 3d6 points + your Wis modifier. The ki orb is a force effect. If you fail to throw the orb before the end of your turn, it dissipates harmlessly. When you take this feat, you gain an additional daily use of ~Stunning Fist~[TAG_STUNNING_FIST]. Special: A fighter can select Fiery Ki Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. A monk with the Stunning Fist feat can select Ki Blast as her bonus feat at 6th level, as long as she also possesses the Fiery Fist feat (other prerequisites can be ignored). +TAG_POWER_THROW TAG_FEATS_DES Power Throw You have learned how to hurl weapons to deadly effect. Prerequisite: ~Strength~[TAG_STRENGTH] 13, ~Brutal Throw~[TAG_BRUTAL_THROW], ~Power Attack~[TAG_POWER_ATTACK] Benefit: On your turn, before making any attack rolls, you can choose to subtract a number from all ~thrown weapon attack rolls~[TAG_RANGED_ATTACKS] and add the same number to all thrown weapon damage rolls. This number may not exceed your base attack bonus. The penalty on attack rolls and the bonus on damage rolls applies until your next turn. Special: A fighter may select Brutal Throw as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_SHIELD_CHARGE TAG_FEATS_DES Shield Charge You deal extra damage if you use your shield as a weapon when charging. Prerequisite: ~Proficiency with Shields~[TAG_SHIELD_PROF], ~Improved Shield Bash~[TAG_IMPROVED_SHIELD_BASH], Base Attack Bonus +3. Benefit: If you hit an opponent with your shield as part of a ~charge action~[TAG_CHARGE], in addition to dealing damage normally, you may make a ~trip attack~[TAG_TRIP] without provoking an ~attack of opportunity~[TAG_AOO]. If you lose, the defender does not get to try to trip you in return. Special: A fighter can select Active Shield Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_SHIELD_SPECIALIZATION TAG_FEATS_DES Shield Specialization You are skilled in using a shield, allowing you to gain greater defensive benefits from it. Prerequisite: ~Proficiency with Shields~[TAG_SHIELD_PROF] Benefit: When using a shield, you increase its shield bonus to AC by 1. Special: A fighter can select Active Shield Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_SHIELD_WARD TAG_FEATS_DES Shield Ward You use your shield like a wall of steel and wood. When an opponent attempts to draw in close to you, your shield forces him away or ruins his attacks. Prerequisite: ~Proficiency with Shields~[TAG_SHIELD_PROF], ~Shield Specialization~[TAG_SHIELD_SPECIALIZATION]. Benefit: You apply your shield bonus to your ~touch~[TAG_TOUCH_ATTACK] AC, and on checks or rolls to resist ~bull rush~[TAG_BULLRUSH], ~disarm~[TAG_DISARM], ~grapple~[TAG_GRAPPLE], overrun, or ~trip~[TAG_TRIP] attempts against you. Special: A fighter can select Active Shield Defense as one of his ~fighter bonus feats~[TAG_CLASS_FEATURES_FIGHTER_BONUS_FEATS]. +TAG_ZEN_ARCHERY TAG_FEATS_DES Zen Archery Your intuition guides your hand when you use a ranged weapon. Prerequisite: ~Wisdom~[TAG_WISDOM] 13, base attack bonus +1 Benefit: You can use your Wisdom modifier instead of your Dexterity modifier when making a ~ranged attack~[TAG_RANGED_ATTACKS] roll. diff --git a/tpdatasrc/tpgamefiles/rules/feats/active shield defense.txt b/tpdatasrc/tpgamefiles/rules/feats/active shield defense.txt new file mode 100644 index 000000000..6346c4b74 --- /dev/null +++ b/tpdatasrc/tpgamefiles/rules/feats/active shield defense.txt @@ -0,0 +1,5 @@ +name: Active Shield Defense +flags: 12582928 +prereqs: +description: Your expert use of your shield allows you to strike at vulnerable foes even when you forgo your own attacks in favor of defense. +prereq descr: Proficiency with shields, Shield Specialization. \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt b/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt new file mode 100644 index 000000000..968615086 --- /dev/null +++ b/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt @@ -0,0 +1,5 @@ +name: Shield Charge +flags: 12582928 +prereqs: 266 3 +description: If you hit an opponent with your shield as part of a charge action, in addition to dealing damage normally, you may make a trip attack without provoking an attack of opportunity. If you lose, the defender does not get to try to trip you in return. +prereq descr: Proficiency with shields, Improved Shield Bash, Base Attack Bonus +3 \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/rules/feats/shield specialization.txt b/tpdatasrc/tpgamefiles/rules/feats/shield specialization.txt new file mode 100644 index 000000000..cdcdf3442 --- /dev/null +++ b/tpdatasrc/tpgamefiles/rules/feats/shield specialization.txt @@ -0,0 +1,5 @@ +name: Shield Specialization +flags: 12582928 +prereqs: +description: You are skilled in using a shield, allowing you to gain greater defensive benefits from it. +prereq descr: Proficiency with shields. \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/rules/feats/shield ward.txt b/tpdatasrc/tpgamefiles/rules/feats/shield ward.txt new file mode 100644 index 000000000..b57d8192a --- /dev/null +++ b/tpdatasrc/tpgamefiles/rules/feats/shield ward.txt @@ -0,0 +1,5 @@ +name: Shield Ward +flags: 12582928 +prereqs: +description: You use your shield like a wall of steel and wood. When an opponent attempts to draw in close to you, your shield forces him away or ruins his attacks. +prereq descr: Proficiency with shields, Shield Specialization. \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Active Shield Defense.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Active Shield Defense.py new file mode 100644 index 000000000..7b3a16fdd --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Active Shield Defense.py @@ -0,0 +1,9 @@ +from toee import * +import char_editor + +def CheckPrereq(attachee, classLevelled, abilityScoreRaised): + if not char_editor.has_feat(feat_shield_proficiency): + return 0 + elif not char_editor.has_feat("Shield Specialization"): + return 0 + return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py new file mode 100644 index 000000000..84319fdf1 --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py @@ -0,0 +1,10 @@ +from toee import * +import char_editor + +def CheckPrereq(attachee, classLevelled, abilityScoreRaised): + #Prerequisite of Base Attack Bonus of 3 is handled by Engine + if not char_editor.has_feat(feat_shield_proficiency): + return 0 + elif not char_editor.has_feat("Shield Specialization"): + return 0 + return 1 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Specialization.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Specialization.py new file mode 100644 index 000000000..d230c76e1 --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Specialization.py @@ -0,0 +1,7 @@ +from toee import * +import char_editor + +def CheckPrereq(attachee, classLevelled, abilityScoreRaised): + if char_editor.has_feat(feat_shield_proficiency): + return 1 + return 0 diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Ward.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Ward.py new file mode 100644 index 000000000..7b3a16fdd --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Ward.py @@ -0,0 +1,9 @@ +from toee import * +import char_editor + +def CheckPrereq(attachee, classLevelled, abilityScoreRaised): + if not char_editor.has_feat(feat_shield_proficiency): + return 0 + elif not char_editor.has_feat("Shield Specialization"): + return 0 + return 1 diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/active_shield_defense.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/active_shield_defense.py new file mode 100644 index 000000000..33f154e73 --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/active_shield_defense.py @@ -0,0 +1,40 @@ +from templeplus.pymod import PythonModifier +from toee import * +import tpdp + +# Active Shield Defense: PHB II, p. 71 + +def getFeatName(): + return "Active Shield Defense" + +print "Registering {}".format(getFeatName) + +def getFeatTag(featName): + return "TAG_{}".format(featName.upper().replace(" ", "_")) + +def nullifyToHitPenalty(attachee, args, evt_obj): + flags = evt_obj.attack_packet.get_flags() + if not flags & D20CAF_ATTACK_OF_OPPORTUNITY: + return 0 + elif not attachee.d20_query("Fighting Defensively Checked"): + return 0 + elif attachee.item_worn_at(item_wear_shield) == OBJ_HANDLE_NULL: + return 0 + elif attachee.d20_query("PQ_Total_Defense_Activated"): + return 0 + else: + featName = getFeatName() + featTag = getFeatTag(featName) + #Fighting Defensively has a vanilla bonus type of 0, which means it can't be negated + #So I add the penalty as a bonus again + bonusValue = 4 + bonusType = 0 #ID 0 = Untyped (stacking!) + evt_obj.bonus_list.add(bonusValue, bonusType, "Feat: ~{}~[{}]".format(featName, featTag)) + return 0 + +# Allowing AoO's while in Total Defense is directly handled in +# total_defense.py (an already existing PythonModifier Extender) + +activeShieldDefenseFeat = PythonModifier(getFeatName(), 2) #featEnum, empty +activeShieldDefenseFeat.MapToFeat(getFeatName(), feat_cond_arg2 = 0) +activeShieldDefenseFeat.AddHook(ET_OnToHitBonus2, EK_NONE, nullifyToHitPenalty, ()) diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_charge.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_charge.py new file mode 100644 index 000000000..9d5f63d6c --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_charge.py @@ -0,0 +1,41 @@ +from templeplus.pymod import PythonModifier +from toee import * +import tpdp + +# Shield Charge: Complete Warrior, p. 105 + +def getFeatName(): + return "Shield Charge" + +print "Registering {}".format(getFeatName) + +def getFeatTag(featName): + return "TAG_{}".format(featName.upper().replace(" ", "_")) + +def radialEntry(attachee, args, evt_obj): + featName = getFeatName() + featTag = getFeatTag(featName) + toggleRadialId = tpdp.RadialMenuEntryToggle(featName, featTag) + toggleRadialId.link_to_args(args, 1) + toggleRadialId.add_child_to_standard(attachee, tpdp.RadialMenuStandardNode.Options) + return 0 + +def tripAttempt(attachee, args, evt_obj): + enabledFlag = args.get_arg(1) + if enabledFlag and attachee.d20_query("Charging"): + if attachee.item_worn_at(item_wear_shield) != OBJ_HANDLE_NULL: + target = evt_obj.attack_packet.target + if attachee.trip_check(target): + combatMesId = 104 # ID 104 = Tripped! + target.float_mesfile_line('mes\\combat.mes', combatMesId) + target.condition_add_with_args("Prone") + target.fall_down() + else: + combatMesId = 144 #ID 144 = Attempt Fails + attachee.float_mesfile_line('mes\\combat.mes', combatMesId) + return 0 + +shieldChargeFeat = PythonModifier(getFeatName(), 3) #featEnum, enabledFlag, empty +shieldChargeFeat.MapToFeat(getFeatName(), feat_cond_arg2 = 1) +shieldChargeFeat.AddHook(ET_OnBuildRadialMenuEntry, EK_NONE, radialEntry, ()) +shieldChargeFeat.AddHook(ET_OnDealingDamage2, EK_NONE, tripAttempt, ()) diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_specialization.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_specialization.py new file mode 100644 index 000000000..2a663169d --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_specialization.py @@ -0,0 +1,34 @@ +from templeplus.pymod import PythonModifier +from toee import * +import tpdp + +# Shield Specialization: PHB II, p. 82 + +def getFeatName(): + return "Shield Specialization" + +print "Registering {}".format(getFeatName) + +def getFeatTag(featName): + return "TAG_{}".format(featName.upper().replace(" ", "_")) + +#def getSubFeatList(): +# return {0:"Buckler", 1:"Heavy", 2:"Light"} + +def applyBonus(attachee, args, evt_obj): + flags = evt_obj.attack_packet.get_flags() + if attachee.item_worn_at(item_wear_shield) == OBJ_HANDLE_NULL: + return 0 + elif flags & D20CAF_TOUCH_ATTACK: + return 0 + else: + featName = getFeatName() + featTag = getFeatTag(featName) + bonusValue = 1 + bonusType = 0 #ID 0 = Untyped (stacking!) + evt_obj.bonus_list.add(bonusValue, bonusType, "Feat: ~{}~[{}]".format(featName, featTag)) + return 0 + +shieldSpecializationFeat = PythonModifier(getFeatName(), 2) #featEnum, empty +shieldSpecializationFeat.MapToFeat(getFeatName(), feat_cond_arg2 = 0) +shieldSpecializationFeat.AddHook(ET_OnGetAC, EK_NONE, applyBonus, ()) diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_ward.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_ward.py new file mode 100644 index 000000000..c56232435 --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/shield_ward.py @@ -0,0 +1,52 @@ +from templeplus.pymod import PythonModifier +from toee import * +import tpactions + +# Shield Ward: PHB II, p. 82 + +def getFeatName(): + return "Shield Ward" + +print "Registering {}".format(getFeatName) + +def getFeatTag(featName): + return "TAG_{}".format(featName.upper().replace(" ", "_")) + +def getShieldBonus(wornShield): + bonusValue = wornShield.item_d20_query(Q_Armor_Get_AC_Bonus) + bonusValue += 1 #Add Shield Specialization Bonus as well; SP is a prereq for this feat + return bonusValue + +def applyBonus(attachee, args, evt_obj): + flags = evt_obj.attack_packet.get_flags() + wornShield = attachee.item_worn_at(item_wear_shield) + if wornShield == OBJ_HANDLE_NULL: + return 0 + elif not flags & D20CAF_TOUCH_ATTACK: + return 0 + else: + featName = getFeatName() + featTag = getFeatTag(featName) + bonusValue = getShieldBonus(wornShield) + bonusType = 0 #ID 0 = Untyped (stacking!) + evt_obj.bonus_list.add(bonusValue, bonusType, "Feat: ~{}~[{}]".format(featName, featTag)) + return 0 + +def addBonusAgainstSpecialAttacks(attachee, args, evt_obj): + currentSequence = tpactions.get_cur_seq() + performer = currentSequence.performer + if performer != attachee: + wornShield = attachee.item_worn_at(item_wear_shield) + flags = evt_obj.flags + if wornShield != OBJ_HANDLE_NULL and flags == 3: + featName = getFeatName() + featTag = getFeatTag(featName) + bonusValue = getShieldBonus(wornShield) + bonusType = 0 #ID 0 = Untyped (stacking!) + evt_obj.bonus_list.add(bonusValue, bonusType, "Feat: ~{}~[{}]".format(featName, featTag)) + return 0 + +shieldWardFeat = PythonModifier(getFeatName(), 2) #featEnum, empty +shieldWardFeat.MapToFeat(getFeatName(), feat_cond_arg2 = 0) +shieldWardFeat.AddHook(ET_OnGetAC, EK_NONE, applyBonus, ()) +shieldWardFeat.AddHook(ET_OnGetAbilityCheckModifier, EK_NONE, addBonusAgainstSpecialAttacks, ()) diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/total_defense.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/total_defense.py index 4886877ce..2b780610e 100644 --- a/tpdatasrc/tpgamefiles/scr/tpModifiers/total_defense.py +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/total_defense.py @@ -5,18 +5,26 @@ print "Registering Total Defense extender" #The fighting defensively query needs to cover both fighting defensively and total defense -def FightingDefensivelyQuery(attachee, args, evt_obj): - if (args.get_arg(0) != 0): - evt_obj.return_val = 1 - return 0 +def FightingDefensivelyQuery(attachee, args, evt_obj): + #If args.get_arg(0)clause removed by Sagenlicht + #as Total Defense has no args and resulted in an error with the newly added Python Query + #Total Defense is a condition, that will be only added, if the action is actually triggered + #So the query only triggers if the action is activated anyways. + evt_obj.return_val = 1 return 0 # No making AOOs when using total defense def TotalDefenseAOOPossible(attachee, args, evt_obj): - evt_obj.return_val = 0 + #If clause added by Sagenlicht to allow AoO's if character has + #the Active Shield Defense Feat + if not attachee.has_feat("Active Shield Defense"): + evt_obj.return_val = 0 return 0 modExtender = PythonModifier() modExtender.ExtendExisting("Total Defense") modExtender.AddHook(ET_OnD20Query, EK_Q_FightingDefensively, FightingDefensivelyQuery, ()) modExtender.AddHook(ET_OnD20Query, EK_Q_AOOPossible, TotalDefenseAOOPossible, ()) +#PythonQuery added by Sagenlicht, as Active Shield Defense needs +#A query that is only responding to Total Defense +modExtender.AddHook(ET_OnD20PythonQuery, "PQ_Total_Defense_Activated", FightingDefensivelyQuery, ()) From 28a3d7089943a3f60b4369fbeddafb906f5a3556 Mon Sep 17 00:00:00 2001 From: doug1234 Date: Fri, 16 Feb 2024 22:40:00 -0500 Subject: [PATCH 2/3] Changed shield charge requirement to shield bash. --- tpdatasrc/tpgamefiles/rules/feats/shield charge.txt | 2 +- tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt b/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt index 968615086..25a77e988 100644 --- a/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt +++ b/tpdatasrc/tpgamefiles/rules/feats/shield charge.txt @@ -1,5 +1,5 @@ name: Shield Charge flags: 12582928 -prereqs: 266 3 +prereqs: 266 3 1216 1 description: If you hit an opponent with your shield as part of a charge action, in addition to dealing damage normally, you may make a trip attack without provoking an attack of opportunity. If you lose, the defender does not get to try to trip you in return. prereq descr: Proficiency with shields, Improved Shield Bash, Base Attack Bonus +3 \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py index 84319fdf1..808cf675a 100644 --- a/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Shield Charge.py @@ -5,6 +5,4 @@ def CheckPrereq(attachee, classLevelled, abilityScoreRaised): #Prerequisite of Base Attack Bonus of 3 is handled by Engine if not char_editor.has_feat(feat_shield_proficiency): return 0 - elif not char_editor.has_feat("Shield Specialization"): - return 0 return 1 From c44d8237cec6a96d5b43a024dc01821ed9f8c031 Mon Sep 17 00:00:00 2001 From: doug1234 Date: Sat, 17 Feb 2024 11:44:24 -0500 Subject: [PATCH 3/3] Added agile shield fighter feat. --- TemplePlus/condition.cpp | 61 ++++++++++++------- .../rules/feats/agile shield fighter.txt | 5 ++ .../scr/feats/feat - Agile Shield Fighter.py | 11 ++++ .../scr/tpModifiers/agile_shield_fighter.py | 42 +++++++++++++ 4 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 tpdatasrc/tpgamefiles/rules/feats/agile shield fighter.txt create mode 100644 tpdatasrc/tpgamefiles/scr/feats/feat - Agile Shield Fighter.py create mode 100644 tpdatasrc/tpgamefiles/scr/tpModifiers/agile_shield_fighter.py diff --git a/TemplePlus/condition.cpp b/TemplePlus/condition.cpp index b35d631e5..a0ec2fbd1 100644 --- a/TemplePlus/condition.cpp +++ b/TemplePlus/condition.cpp @@ -1928,14 +1928,28 @@ int __cdecl GlobalToHitBonus(DispatcherCallbackArgs args) } if (dualWielding) { - if (d20Sys.UsingSecondaryWeapon(args.objHndCaller, attackCode)) - bonusSys.bonusAddToBonusList(&dispIo->bonlist, -10, 26, 121); // penalty for dualwield on offhand attack - else - bonusSys.bonusAddToBonusList(&dispIo->bonlist, -6, 27, 122); // penalty for dualwield on primary attack - if (critterSys.OffhandIsLight(args.objHndCaller)) - { - bonusSys.bonusAddToBonusList(&dispIo->bonlist, 2, 0, 167); // Light Off-hand Weapon + //See if python is going to handle the penalty + const bool overridePenalty = d20Sys.D20QueryPython(args.objHndCaller, "Override Two Weapon Penalty", dualWielding ? 1 :0); + if (overridePenalty) { + auto penalty = d20Sys.D20QueryPython(args.objHndCaller, "Get Two Weapon Penalty", dualWielding ? 1 : 0); + if (d20Sys.UsingSecondaryWeapon(args.objHndCaller, attackCode)) { + bonusSys.bonusAddToBonusList(&dispIo->bonlist, penalty, 26, 121); + } + else { + bonusSys.bonusAddToBonusList(&dispIo->bonlist, penalty, 27, 122); + } + } + else { + if (d20Sys.UsingSecondaryWeapon(args.objHndCaller, attackCode)) + bonusSys.bonusAddToBonusList(&dispIo->bonlist, -10, 26, 121); // penalty for dualwield on offhand attack + else + bonusSys.bonusAddToBonusList(&dispIo->bonlist, -6, 27, 122); // penalty for dualwield on primary attack + + if (critterSys.OffhandIsLight(args.objHndCaller)) + { + bonusSys.bonusAddToBonusList(&dispIo->bonlist, 2, 0, 167); // Light Off-hand Weapon + } } } } @@ -3507,22 +3521,25 @@ int __cdecl GreaterTWFRanger(DispatcherCallbackArgs args) int __cdecl TwoWeaponFightingBonus(DispatcherCallbackArgs args) { - DispIoAttackBonus *dispIo = dispatch.DispIoCheckIoType5((DispIoAttackBonus*)args.dispIO); - char *featName; + DispIoAttackBonus* dispIo = dispatch.DispIoCheckIoType5((DispIoAttackBonus*)args.dispIO); - feat_enums feat = (feat_enums)conds.CondNodeGetArg(args.subDispNode->condNode, 0); - int attackCode = dispIo->attackPacket.dispKey; - int dualWielding = 0; - int attackNumber = 1; - if (d20Sys.UsingSecondaryWeapon(args.objHndCaller, attackCode)) - { - featName = feats.GetFeatName(feat); - bonusSys.bonusAddToBonusListWithDescr(&dispIo->bonlist, 6, 0, 114, featName); - } - else if ( d20Sys.ExtractAttackNumber(args.objHndCaller, attackCode, &attackNumber, &dualWielding), dualWielding != 0) - { - featName = feats.GetFeatName(feat); - bonusSys.bonusAddToBonusListWithDescr(&dispIo->bonlist, 2, 0, 114, featName); + //Disable when using agile shield fighter for examle + if (d20Sys.D20QueryPython(args.objHndCaller, "Disable Two Weapon Fighting Bonus") == 0) { + char* featName; + feat_enums feat = (feat_enums)conds.CondNodeGetArg(args.subDispNode->condNode, 0); + int attackCode = dispIo->attackPacket.dispKey; + int dualWielding = 0; + int attackNumber = 1; + if (d20Sys.UsingSecondaryWeapon(args.objHndCaller, attackCode)) + { + featName = feats.GetFeatName(feat); + bonusSys.bonusAddToBonusListWithDescr(&dispIo->bonlist, 6, 0, 114, featName); + } + else if (d20Sys.ExtractAttackNumber(args.objHndCaller, attackCode, &attackNumber, &dualWielding), dualWielding != 0) + { + featName = feats.GetFeatName(feat); + bonusSys.bonusAddToBonusListWithDescr(&dispIo->bonlist, 2, 0, 114, featName); + } } return 0; } diff --git a/tpdatasrc/tpgamefiles/rules/feats/agile shield fighter.txt b/tpdatasrc/tpgamefiles/rules/feats/agile shield fighter.txt new file mode 100644 index 000000000..1de7039ce --- /dev/null +++ b/tpdatasrc/tpgamefiles/rules/feats/agile shield fighter.txt @@ -0,0 +1,5 @@ +name: Agile Shield Fighter +flags: 12582928 +prereqs: +description: When making a shield bash and armed strike attack as part of a full attack action, you take a -2 penalty on each attack. These penalties replace the normal ones you incur for fighting with two weapons. +prereq descr: Improved Shield Bash, Shield Specialization and Shield Specialization. \ No newline at end of file diff --git a/tpdatasrc/tpgamefiles/scr/feats/feat - Agile Shield Fighter.py b/tpdatasrc/tpgamefiles/scr/feats/feat - Agile Shield Fighter.py new file mode 100644 index 000000000..a558802af --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/feats/feat - Agile Shield Fighter.py @@ -0,0 +1,11 @@ +from toee import * +import char_editor + +def CheckPrereq(attachee, classLevelled, abilityScoreRaised): + if not char_editor.has_feat(feat_shield_proficiency): + return 0 + if not char_editor.has_feat(feat_improved_shield_bash): + return 0 + if not char_editor.has_feat("Shield Specialization"): + return 0 + return 1 diff --git a/tpdatasrc/tpgamefiles/scr/tpModifiers/agile_shield_fighter.py b/tpdatasrc/tpgamefiles/scr/tpModifiers/agile_shield_fighter.py new file mode 100644 index 000000000..bd0e84950 --- /dev/null +++ b/tpdatasrc/tpgamefiles/scr/tpModifiers/agile_shield_fighter.py @@ -0,0 +1,42 @@ +from templeplus.pymod import PythonModifier +from toee import * +import tpdp + +# Agile Shield Fighter: PHB II, p. 74 + +def getFeatName(): + return "Agile Shield Fighter" + +print "Registering {}".format(getFeatName) + +def AgileShieldFighterDisableTwoWeaponFightingBonus(attachee, args, evt_obj): + shield = attachee.item_worn_at(item_wear_shield) + if shield == OBJ_HANDLE_NULL: + return 0 + + evt_obj.return_val = 1 #This feat takes over two weapon fighting + return 0 + +def AgileShieldFighterOverrideTwoWeaponPenalty(attachee, args, evt_obj): + shield = attachee.item_worn_at(item_wear_shield) + if shield == OBJ_HANDLE_NULL: + return 0 + + evt_obj.return_val = 1 + return 0 + +def AgileShieldFighterGetTwoWeaponPenalty(attachee, args, evt_obj): + shield = attachee.item_worn_at(item_wear_shield) + if shield == OBJ_HANDLE_NULL: + return 0 + + evt_obj.return_val = -2 + return 0 + +#Need to block two weapon fighting + +agileShieldFighter = PythonModifier(getFeatName(), 2) #Spare, Spare +agileShieldFighter.MapToFeat(getFeatName()) +agileShieldFighter.AddHook(ET_OnD20PythonQuery, "Disable Two Weapon Fighting Bonus", AgileShieldFighterDisableTwoWeaponFightingBonus, ()) +agileShieldFighter.AddHook(ET_OnD20PythonQuery, "Get Two Weapon Penalty", AgileShieldFighterGetTwoWeaponPenalty, ()) +agileShieldFighter.AddHook(ET_OnD20PythonQuery, "Override Two Weapon Penalty", AgileShieldFighterOverrideTwoWeaponPenalty, ())