2026/02/22 Update
Added scripting for Combat Form feats: Combat Focus, Combat Awareness, Combat Stability, Combat Defense, Combat Vitality & Combat Strike. Updated fighter bonus feat lists for Champion of Torm, Dragon Devotee, Eldritch Knight, Fighter, Hospitaler, Psychic Warrior, Serene Guardian, Spellsword and Warblade.
This commit is contained in:
83
nwn/nwnprc/trunk/scripts/ft_combat_strike.nss
Normal file
83
nwn/nwnprc/trunk/scripts/ft_combat_strike.nss
Normal file
@@ -0,0 +1,83 @@
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Combat Strike
|
||||
|
||||
Your intense, focused state allows you to see the one critical
|
||||
moment in a battle when you hang suspended between victory and
|
||||
defeat. By pouring the energy required to maintain your focus
|
||||
into your assault, you batter through your foe's defenses.
|
||||
|
||||
Prerequisite: Combat Focus, WIS 13, any two other combat form
|
||||
feats, base attack bonus +15
|
||||
|
||||
Specifics: If you choose to end your combat focus as a swift
|
||||
action, you gain a bonus on attack rolls and damage rolls equal
|
||||
to your total number of combat form feats for the rest of your
|
||||
current turn. You immediately lose all BENEFITS of combat form
|
||||
feats that affect you only while you are maintaining your combat
|
||||
focus.
|
||||
|
||||
Use: Selected.
|
||||
|
||||
Special: A fighter can select Combat Focus as one of his fighter
|
||||
bonus feats.
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//:: Script: ft_combat_strike.nss
|
||||
//:: Author: Jaysyn
|
||||
//:: Created: 2026-02-22 12:29:37
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
#include "prc_inc_spells"
|
||||
#include "prc_inc_cmbtform"
|
||||
#include "prc_x2_itemprop"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
if (!GetHasFeat(FEAT_COMBAT_STRIKE, oPC)) return;
|
||||
|
||||
if (!GetLocalInt(oPC, COMBAT_FOCUS_VAR))
|
||||
{
|
||||
FloatingTextStringOnCreature("Combat Strike requires active Combat Focus.", oPC, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CountCombatFormFeats(oPC) < 2)
|
||||
{
|
||||
FloatingTextStringOnCreature("Combat Strike requires two other Combat Form feats.", oPC, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// End Combat Focus immediately
|
||||
DeleteLocalInt(oPC, COMBAT_FOCUS_VAR);
|
||||
DeleteLocalInt(oPC, COMBAT_FOCUS_END);
|
||||
|
||||
// Remove all Combat Form effects by tag immediately
|
||||
RemoveCombatFocusWillBonus(oPC);
|
||||
RemoveCombatAwarenessBlindsight(oPC);
|
||||
RemoveCombatDefenseAC(oPC);
|
||||
RemoveCombatStabilityBonus(oPC);
|
||||
RemoveCombatVigorFastHeal(oPC);
|
||||
|
||||
// Apply temporary attack/damage bonus for the current turn
|
||||
int nBonus = CountCombatFormFeats(oPC) + 1;
|
||||
effect eImpact = EffectVisualEffect(VFX_IMP_PDK_WRATH);
|
||||
effect eAtk = EffectAttackIncrease(nBonus);
|
||||
effect eDam = EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nBonus), DAMAGE_TYPE_BASE_WEAPON);
|
||||
effect eLink = EffectLinkEffects(eAtk, eDam);
|
||||
eLink = TagEffect(eLink, "CombatStrike_Bonus");
|
||||
eLink = SupernaturalEffect(eLink);
|
||||
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eImpact, oPC);
|
||||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 7.0f);
|
||||
|
||||
FloatingTextStringOnCreature("*Combat Strike Activated*", oPC, FALSE);
|
||||
}
|
||||
205
nwn/nwnprc/trunk/scripts/prc_combatfocus.nss
Normal file
205
nwn/nwnprc/trunk/scripts/prc_combatfocus.nss
Normal file
@@ -0,0 +1,205 @@
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//:: ;-. ,-. ,-. ,-.
|
||||
//:: | ) | ) / ( )
|
||||
//:: |-' |-< | ;-:
|
||||
//:: | | \ \ ( )
|
||||
//:: ' ' ' `-' `-'
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//::
|
||||
/*
|
||||
Combat Focus
|
||||
Type of Feat: Combat Form, Fighter Bonus Feat.
|
||||
|
||||
The way of the warrior requires more than simple, brute strength.
|
||||
Some warriors bring their minds to such keen focus during the heat
|
||||
of battle that they can attain superhuman levels of endurance,
|
||||
perception, and mental toughness. Through intense mental exercise
|
||||
and training, you learn to enter a state of perfect martial
|
||||
clarity.
|
||||
|
||||
Prerequisite: WIS 13
|
||||
|
||||
Specifics: In battle, you push aside the chaos of the fight and
|
||||
attain a focused state that grants you a keen, clear picture of
|
||||
the battle. Fear and pain ebb away as you focus solely on
|
||||
defeating your enemy. The first time you make a successful
|
||||
attack during an encounter, you gain your combat focus. In this
|
||||
state, your mind and body become one, allowing you to overcome
|
||||
mundane physical limits. You can maintain your combat focus for
|
||||
10 rounds after entering it, +1 additional round per combat form
|
||||
feat you possess aside from this one. You can only gain your
|
||||
combat focus once per encounter. While you are maintaining your
|
||||
combat focus, you gain a +2 bonus on Will saves. If you have
|
||||
three or more combat form feats, this bonus increases to +4.
|
||||
|
||||
Use: Automatic.
|
||||
|
||||
Special: A fighter can select Combat Focus as one of his fighter
|
||||
bonus feats.
|
||||
*/
|
||||
//::
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
//:: Script: prc_combatfocus.nss
|
||||
//:: Author: Jaysyn
|
||||
//:: Created: 2026-02-22 12:29:37
|
||||
//:://////////////////////////////////////////////////////////////////
|
||||
#include "prc_alterations"
|
||||
#include "prc_inc_function"
|
||||
#include "prc_inc_cmbtform"
|
||||
#include "inc_eventhook"
|
||||
|
||||
void CombatFocus_AddOnHitToItem(object oItem)
|
||||
{
|
||||
if (!GetIsObjectValid(oItem)) return;
|
||||
itemproperty ipOnHit = ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1);
|
||||
ipOnHit = TagItemProperty(ipOnHit, "Tag_PRC_OnHitKeeper");
|
||||
IPSafeAddItemProperty(oItem, ipOnHit, 999999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
|
||||
AddEventScript(oItem, EVENT_ITEM_ONHIT, "prc_combatfocus", TRUE, FALSE);
|
||||
}
|
||||
|
||||
// Helper to remove OnHit property from a weapon/ammo
|
||||
void CombatFocus_RemoveOnHitFromItem(object oItem)
|
||||
{
|
||||
if (!GetIsObjectValid(oItem)) return;
|
||||
RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "prc_combatfocus", TRUE, FALSE);
|
||||
RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int nEvent = GetRunningEvent();
|
||||
object oPC;
|
||||
|
||||
// Resolve the correct PC based on the event
|
||||
switch (nEvent)
|
||||
{
|
||||
case EVENT_ONPLAYERREST_FINISHED: oPC = GetLastBeingRested(); break;
|
||||
case EVENT_ONPLAYEREQUIPITEM: oPC = GetItemLastEquippedBy(); break;
|
||||
case EVENT_ONPLAYERUNEQUIPITEM: oPC = GetItemLastUnequippedBy(); break;
|
||||
case EVENT_ONHEARTBEAT: oPC = OBJECT_SELF; break;
|
||||
case EVENT_ITEM_ONHIT: oPC = OBJECT_SELF; break;
|
||||
default: oPC = OBJECT_SELF; break;
|
||||
}
|
||||
|
||||
if (nEvent == FALSE) // EvalPRCFeats entry
|
||||
{
|
||||
if (!GetHasFeat(FEAT_COMBAT_FOCUS, oPC)) return;
|
||||
|
||||
// Register EVENT_ITEM_ONHIT once if not already registered
|
||||
if (!GetLocalInt(oPC, "CmbtFocus_OnHit_Registered"))
|
||||
{
|
||||
AddEventScript(oPC, EVENT_ITEM_ONHIT, "prc_combatfocus", TRUE, FALSE);
|
||||
SetLocalInt(oPC, "CmbtFocus_OnHit_Registered", TRUE);
|
||||
}
|
||||
|
||||
// Register equip/unequip events once
|
||||
if (!GetLocalInt(oPC, "CmbtFocus_EquipHooks_Registered"))
|
||||
{
|
||||
AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "prc_combatfocus", TRUE, FALSE);
|
||||
AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "prc_combatfocus", TRUE, FALSE);
|
||||
SetLocalInt(oPC, "CmbtFocus_EquipHooks_Registered", TRUE);
|
||||
}
|
||||
|
||||
// Register rest-finished event once
|
||||
if (!GetLocalInt(oPC, "CmbtFocus_RestHook_Registered"))
|
||||
{
|
||||
AddEventScript(oPC, EVENT_ONPLAYERREST_FINISHED, "prc_combatfocus", TRUE, FALSE);
|
||||
SetLocalInt(oPC, "CmbtFocus_RestHook_Registered", TRUE);
|
||||
}
|
||||
|
||||
// Apply Will bonus if focus is active
|
||||
if (GetLocalInt(oPC, COMBAT_FOCUS_VAR))
|
||||
{
|
||||
ApplyCombatFocusWillBonus(oPC);
|
||||
// Always ensure heartbeat is registered while focus is active
|
||||
if (!GetLocalInt(oPC, "CmbtFocus_HB_Registered"))
|
||||
{
|
||||
AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_combatfocus", TRUE, FALSE);
|
||||
SetLocalInt(oPC, "CmbtFocus_HB_Registered", TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove Will bonus if focus is not active
|
||||
if (GetLocalInt(oPC, "CombatFocus_Will"))
|
||||
RemoveCombatFocusWillBonus(oPC);
|
||||
}
|
||||
}
|
||||
else if (nEvent == EVENT_ONPLAYEREQUIPITEM)
|
||||
{
|
||||
object oItem = GetItemLastEquipped();
|
||||
if (!GetIsObjectValid(oItem)) return;
|
||||
// Skip VoP and Forsaker to avoid conflicts
|
||||
if (GetHasFeat(FEAT_VOWOFPOVERTY, oPC) || GetLevelByClass(CLASS_TYPE_FORSAKER, oPC)) return;
|
||||
if (IPGetIsMeleeWeapon(oItem))
|
||||
{
|
||||
CombatFocus_AddOnHitToItem(oItem);
|
||||
// Also add to ammo if ranged
|
||||
object oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oPC);
|
||||
if (GetIsObjectValid(oAmmo)) CombatFocus_AddOnHitToItem(oAmmo);
|
||||
oAmmo = GetItemInSlot(INVENTORY_SLOT_BULLETS, oPC);
|
||||
if (GetIsObjectValid(oAmmo)) CombatFocus_AddOnHitToItem(oAmmo);
|
||||
oAmmo = GetItemInSlot(INVENTORY_SLOT_ARROWS, oPC);
|
||||
if (GetIsObjectValid(oAmmo)) CombatFocus_AddOnHitToItem(oAmmo);
|
||||
}
|
||||
}
|
||||
else if (nEvent == EVENT_ONPLAYERUNEQUIPITEM)
|
||||
{
|
||||
object oItem = GetItemLastUnequipped();
|
||||
if (!GetIsObjectValid(oItem)) return;
|
||||
if (IPGetIsMeleeWeapon(oItem))
|
||||
{
|
||||
CombatFocus_RemoveOnHitFromItem(oItem);
|
||||
// Also remove from ammo if ranged
|
||||
CombatFocus_RemoveOnHitFromItem(GetItemInSlot(INVENTORY_SLOT_BOLTS, oPC));
|
||||
CombatFocus_RemoveOnHitFromItem(GetItemInSlot(INVENTORY_SLOT_BULLETS, oPC));
|
||||
CombatFocus_RemoveOnHitFromItem(GetItemInSlot(INVENTORY_SLOT_ARROWS, oPC));
|
||||
}
|
||||
}
|
||||
else if (nEvent == EVENT_ONHEARTBEAT)
|
||||
{
|
||||
if (!GetIsPC(oPC) || !GetLocalInt(oPC, COMBAT_FOCUS_VAR)) return;
|
||||
|
||||
// Combat Awareness HP display only
|
||||
if (GetHasFeat(FEAT_COMBAT_AWARENESS, oPC))
|
||||
ShowAdjacentHP(oPC);
|
||||
}
|
||||
else if (nEvent == EVENT_ONPLAYERREST_FINISHED)
|
||||
{
|
||||
RemoveCombatFocusWillBonus(oPC);
|
||||
DeleteLocalInt(oPC, COMBAT_FOCUS_VAR);
|
||||
DeleteLocalInt(oPC, "CombatFocus_RoundsRemaining");
|
||||
DeleteLocalInt(oPC, COMBAT_FOCUS_ENC);
|
||||
if (GetLocalInt(oPC, "CmbtFocus_HB_Registered"))
|
||||
{
|
||||
RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_combatfocus", TRUE, FALSE);
|
||||
DeleteLocalInt(oPC, "CmbtFocus_HB_Registered");
|
||||
}
|
||||
|
||||
object oRightHand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
|
||||
if (GetIsObjectValid(oRightHand) && IPGetIsMeleeWeapon(oRightHand))
|
||||
{
|
||||
DelayCommand(1.0f, CombatFocus_AddOnHitToItem(oRightHand));
|
||||
}
|
||||
}
|
||||
else if (nEvent == EVENT_ITEM_ONHIT)
|
||||
{
|
||||
if (!GetIsPC(oPC)) return;
|
||||
if (!GetHasFeat(FEAT_COMBAT_FOCUS, oPC)) return;
|
||||
if (GetLocalInt(oPC, COMBAT_FOCUS_VAR)) return;
|
||||
if (GetLocalInt(oPC, COMBAT_FOCUS_ENC)) return;
|
||||
|
||||
CombatFocus_OnAttackHit(oPC);
|
||||
|
||||
// Start round decay heartbeat
|
||||
if (!GetLocalInt(oPC, "CmbtFocus_HB_Registered"))
|
||||
{
|
||||
AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_combatfocus", TRUE, FALSE);
|
||||
SetLocalInt(oPC, "CmbtFocus_HB_Registered", TRUE);
|
||||
DelayCommand(6.0, CombatFocus_DecayRounds(oPC));
|
||||
}
|
||||
|
||||
// Start combat-end detection
|
||||
DelayCommand(6.0, CombatFocus_CombatEndHeartbeat(oPC));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user