Added support for NPCs with Combat Feats
Added support for NPCs with Charge, Pounce, Trample, Overrun, Awesome Blow & Bull Rush. Full compile. Updated release archive.
This commit is contained in:
parent
582b9dbb49
commit
b0a9d7abac
@ -6357,7 +6357,7 @@
|
|||||||
},
|
},
|
||||||
"Version": {
|
"Version": {
|
||||||
"type": "dword",
|
"type": "dword",
|
||||||
"value": 514
|
"value": 515
|
||||||
},
|
},
|
||||||
"Width": {
|
"Width": {
|
||||||
"type": "int",
|
"type": "int",
|
||||||
|
BIN
_module/ncs/awesomeblow_hb.ncs
Normal file
BIN
_module/ncs/awesomeblow_hb.ncs
Normal file
Binary file not shown.
BIN
_module/ncs/bullrusher_hb.ncs
Normal file
BIN
_module/ncs/bullrusher_hb.ncs
Normal file
Binary file not shown.
BIN
_module/ncs/charger_hb.ncs
Normal file
BIN
_module/ncs/charger_hb.ncs
Normal file
Binary file not shown.
Binary file not shown.
BIN
_module/ncs/overrunner_hb.ncs
Normal file
BIN
_module/ncs/overrunner_hb.ncs
Normal file
Binary file not shown.
Binary file not shown.
BIN
_module/ncs/trampler_hb.ncs
Normal file
BIN
_module/ncs/trampler_hb.ncs
Normal file
Binary file not shown.
BIN
_module/ncs/x2_def_heartbeat.ncs
Normal file
BIN
_module/ncs/x2_def_heartbeat.ncs
Normal file
Binary file not shown.
115
_module/nss/awesomeblow_hb.nss
Normal file
115
_module/nss/awesomeblow_hb.nss
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
//:: awesomeblow_hb.nss
|
||||||
|
//::
|
||||||
|
//:: Makes a creature pick a target & run DoAwesomeBlow() occasionally.
|
||||||
|
//::
|
||||||
|
#include "prc_inc_combmove"
|
||||||
|
#include "prc_inc_spells"
|
||||||
|
|
||||||
|
void DoAwesomeBlow(object oTarget, object oNPC = OBJECT_SELF)
|
||||||
|
{
|
||||||
|
int nHP = GetCurrentHitPoints(oTarget);
|
||||||
|
int nSizeBonus;
|
||||||
|
effect eNone;
|
||||||
|
|
||||||
|
// Apply the VFX
|
||||||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_REFLEX_SAVE_THROW_USE), oTarget);
|
||||||
|
|
||||||
|
PerformAttack(oTarget, oNPC, eNone, 0.0, -4);
|
||||||
|
|
||||||
|
if (GetLocalInt(oTarget, "PRCCombat_StruckByAttack"))
|
||||||
|
{
|
||||||
|
int nDC = nHP - GetCurrentHitPoints(oTarget); // This should be the amount caused by the attack
|
||||||
|
|
||||||
|
if ((PRCGetCreatureSize(oNPC) + nSizeBonus) > PRCGetCreatureSize(oTarget))
|
||||||
|
{
|
||||||
|
if (!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_NONE))
|
||||||
|
{
|
||||||
|
_DoBullRushKnockBack(oTarget, oNPC, 10.0);
|
||||||
|
|
||||||
|
// Apply knockdown effect after the knockback with a slight delay
|
||||||
|
DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0));
|
||||||
|
|
||||||
|
// Trigger dust explosion when the target stops moving
|
||||||
|
DelayCommand(0.6, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DUST_EXPLOSION), oTarget));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
|
||||||
|
string sName = GetName(oNPC);
|
||||||
|
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
|
||||||
|
// Define a range for target selection
|
||||||
|
float fRange;
|
||||||
|
|
||||||
|
if (nNPCSize == CREATURE_SIZE_INVALID) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_TINY) fRange = FeetToMeters(2.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_SMALL) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_MEDIUM) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_LARGE) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_HUGE) fRange = FeetToMeters(15.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_GARGANTUAN) fRange = FeetToMeters(20.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_COLOSSAL) fRange = FeetToMeters(30.0);
|
||||||
|
|
||||||
|
if(DEBUG) DoDebug("awesomeblow_hb: Starting script on "+sName+".");
|
||||||
|
|
||||||
|
// Check if the cooldown is active
|
||||||
|
if (GetLocalInt(oNPC, "AwesomeBlowCooldown") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("awesomeblow_hb: "+sName+" can't use Awesome Blow while it is on cooldown.");
|
||||||
|
return; // Exit if cooldown is active
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleOriginator") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("awesomeblow_hb: "+sName+" can't use Awesome Blow while you are grappling an opponent.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleTarget") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("awesomeblow_hb: "+sName+" can't use Awesome Blow while you are being grappled.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly decide whether to trigger an Awesome Blow (e.g., 33% chance)
|
||||||
|
if (1 + Random(100) <= 33)
|
||||||
|
{
|
||||||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
int nTargetSize = PRCGetCreatureSize(oTarget);
|
||||||
|
|
||||||
|
// If we find a valid target, proceed
|
||||||
|
while (GetIsObjectValid(oTarget))
|
||||||
|
{
|
||||||
|
// Check if the target is a valid enemy, alive, and at least one size smaller
|
||||||
|
if (oTarget != oNPC && GetIsEnemy(oTarget, oNPC) && !GetIsDead(oTarget) && nTargetSize < nNPCSize)
|
||||||
|
{
|
||||||
|
// Call the DoAwesomeBlow function
|
||||||
|
DoAwesomeBlow(oTarget, oNPC);
|
||||||
|
|
||||||
|
// Create a message using the names of the creatures
|
||||||
|
string sMessage = GetName(oNPC) + " assaults " + GetName(oTarget) + " with an Awesome Blow!";
|
||||||
|
|
||||||
|
// Show floating text message
|
||||||
|
FloatingTextStringOnCreature(sMessage, oNPC, FALSE);
|
||||||
|
SendMessageToPC(oTarget, sMessage);
|
||||||
|
|
||||||
|
// Set cooldown flag
|
||||||
|
SetLocalInt(oNPC, "AwesomeBlowCooldown", 1);
|
||||||
|
|
||||||
|
// Delay removal of the cooldown after 1-4 rounds
|
||||||
|
DelayCommand(RoundsToSeconds(d4(1)), DeleteLocalInt(oNPC, "AwesomeBlowCooldown"));
|
||||||
|
|
||||||
|
break; // Exit the loop after using Awesome Blow
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the next target within the spell shape
|
||||||
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("awesomeblow_hb: "+sName+" skipped Awesome Blow");
|
||||||
|
}
|
91
_module/nss/bullrusher_hb.nss
Normal file
91
_module/nss/bullrusher_hb.nss
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//:: bullrusher_hb.nss
|
||||||
|
//::
|
||||||
|
//:: Makes a creature pick a target & run DoBullrush() occasionally.
|
||||||
|
//::
|
||||||
|
#include "prc_inc_combmove"
|
||||||
|
#include "prc_inc_spells"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
|
||||||
|
string sName = GetName(oNPC);
|
||||||
|
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
|
||||||
|
// Define a range for target selection
|
||||||
|
float fRange;
|
||||||
|
|
||||||
|
if (nNPCSize == CREATURE_SIZE_INVALID) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_TINY) fRange = FeetToMeters(2.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_SMALL) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_MEDIUM) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_LARGE) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_HUGE) fRange = FeetToMeters(15.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_GARGANTUAN) fRange = FeetToMeters(20.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_COLOSSAL) fRange = FeetToMeters(30.0);
|
||||||
|
|
||||||
|
if(DEBUG) DoDebug("bullrusher_hb: Starting script on "+sName+".");
|
||||||
|
|
||||||
|
int bImpBullRush = GetHasFeat(FEAT_IMPROVED_BULLRUSH, oNPC);
|
||||||
|
|
||||||
|
// Check if the cooldown is active
|
||||||
|
if (GetLocalInt(oNPC, "BullRushCooldown") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("bullrusher_hb: "+sName+" can't use Bull Rush while it is on cooldown.");
|
||||||
|
return; // Exit if cooldown is active
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleOriginator") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("bullrusher_hb: "+sName+" can't use Bull Rush while you are grappling an opponent.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleTarget") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("bullrusher_hb: "+sName+" can't use Bull Rush while you are being grappled.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly decide whether to trigger the trample effect (e.g., 33% chance)
|
||||||
|
if (1 + Random(100) <= 33)
|
||||||
|
{
|
||||||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
|
||||||
|
// If we find a valid target, proceed
|
||||||
|
while (GetIsObjectValid(oTarget))
|
||||||
|
{
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
int nTargetSize = PRCGetCreatureSize(oTarget);
|
||||||
|
|
||||||
|
// Check if the target is a valid enemy, alive, and at least one size smaller
|
||||||
|
if (oTarget != oNPC && GetIsEnemy(oTarget, oNPC) && !GetIsDead(oTarget) && (nTargetSize <= nNPCSize + 1))
|
||||||
|
{
|
||||||
|
// Get the location of the target
|
||||||
|
location lTarget = GetLocation(oTarget);
|
||||||
|
|
||||||
|
// Set cooldown flag
|
||||||
|
SetLocalInt(oNPC, "BullRushCooldown", 1);
|
||||||
|
|
||||||
|
// Create a message using the names of the creatures
|
||||||
|
string sMessage = GetName(oNPC) + " is bull rushing " + GetName(oTarget) + "!";
|
||||||
|
SendMessageToPC(oTarget, sMessage);
|
||||||
|
|
||||||
|
// Show floating text message
|
||||||
|
FloatingTextStringOnCreature(sMessage, oNPC, FALSE);
|
||||||
|
|
||||||
|
// Call the DoBullRush function
|
||||||
|
DoBullRush(oNPC, oTarget, 0, bImpBullRush);
|
||||||
|
|
||||||
|
// Delay removal of the cooldown after 6-18 seconds (1-3 rounds)
|
||||||
|
DelayCommand(RoundsToSeconds(d3(1)), DeleteLocalInt(oNPC, "BullRushCooldown"));
|
||||||
|
|
||||||
|
break; // Exit the loop after bull rushing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the next target within the spell shape
|
||||||
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("bullrusher_hb: "+sName+" skipped Bull Rush");
|
||||||
|
}
|
80
_module/nss/charger_hb.nss
Normal file
80
_module/nss/charger_hb.nss
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
//:: charger_hb.nss
|
||||||
|
//::
|
||||||
|
//:: Makes a creature pick a target & run DoCharge occasionally.
|
||||||
|
//::
|
||||||
|
#include "prc_inc_combmove"
|
||||||
|
#include "prc_inc_spells"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
|
||||||
|
string sName = GetName(oNPC);
|
||||||
|
|
||||||
|
int bImpBullRush = GetHasFeat(FEAT_IMPROVED_BULLRUSH, oNPC);
|
||||||
|
int bAcrobaticCharge = GetHasFeat(FEAT_ACROBATIC_CHARGE, oNPC);
|
||||||
|
int bPouncer = GetLocalInt(oNPC, "POUNCER");
|
||||||
|
|
||||||
|
if(DEBUG) DoDebug("charger_hb: Starting script on "+sName+".");
|
||||||
|
|
||||||
|
// Check if the cooldown is active
|
||||||
|
if (GetLocalInt(oNPC, "ChargeCooldown") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("charger_hb: "+sName+" can't use Charge while it is on cooldown.");
|
||||||
|
return; // Exit if cooldown is active
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleOriginator") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("charger_hb: "+sName+" can't use Charge while grappling.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleTarget") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("charger_hb: "+sName+" can't use Charge while being grappled.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the minimum and maximum range for target selection
|
||||||
|
float fMinRange = FeetToMeters(20.0); // Minimum range in meters (15 feet)
|
||||||
|
float fMaxRange = FeetToMeters(45.0); // Maximum range in meters (45 feet)
|
||||||
|
|
||||||
|
// Randomly decide whether to trigger the charge effect (e.g., 20% chance)
|
||||||
|
if (1 + Random(100) <= 25) // 25% chance
|
||||||
|
{
|
||||||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fMaxRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
|
||||||
|
// If we find a valid target, proceed
|
||||||
|
while (GetIsObjectValid(oTarget))
|
||||||
|
{
|
||||||
|
// Calculate the distance to the target
|
||||||
|
float fDistance = GetDistanceBetween(oNPC, oTarget);
|
||||||
|
|
||||||
|
// Check if the target is a valid enemy, alive, and within the distance constraints
|
||||||
|
if (oTarget != oNPC && GetIsEnemy(oTarget, oNPC) && !GetIsDead(oTarget) && fDistance > fMinRange && fDistance <= fMaxRange)
|
||||||
|
{
|
||||||
|
// Create a message using the names of the creatures
|
||||||
|
string sMessage = GetName(oNPC) + " is charging " + GetName(oTarget) + "!";
|
||||||
|
|
||||||
|
// Show floating text message
|
||||||
|
FloatingTextStringOnCreature(sMessage, oNPC, FALSE);
|
||||||
|
SendMessageToPC(oTarget, sMessage);
|
||||||
|
|
||||||
|
// Call the DoCharge function
|
||||||
|
DoCharge(oNPC, oTarget, TRUE, bAcrobaticCharge, 0, -1, bImpBullRush, 0, bPouncer);
|
||||||
|
|
||||||
|
// Set cooldown flag
|
||||||
|
SetLocalInt(oNPC, "ChargeCooldown", 1);
|
||||||
|
|
||||||
|
// Delay removal of the cooldown after 6-18 seconds (1-3 rounds)
|
||||||
|
DelayCommand(RoundsToSeconds(d3(1)), DeleteLocalInt(oNPC, "ChargeCooldown"));
|
||||||
|
|
||||||
|
break; // Exit the loop after charging
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the next target within the shape
|
||||||
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fMaxRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("charger_hb: "+sName+" skipped Charging");
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
//:: Created By: Naomi Novik
|
//:: Created By: Naomi Novik
|
||||||
//:: Created On: 12/22/2002
|
//:: Created On: 12/22/2002
|
||||||
//:://////////////////////////////////////////////////
|
//:://////////////////////////////////////////////////
|
||||||
|
#include "prc_inc_spells"
|
||||||
#include "nw_i0_generic"
|
#include "nw_i0_generic"
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
@ -44,6 +44,37 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//:: Declare major variables
|
||||||
|
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
object oArea = GetArea(oNPC);
|
||||||
|
|
||||||
|
string sResRef = GetResRef(oNPC);
|
||||||
|
string sAreaResRef = GetResRef(oArea);
|
||||||
|
|
||||||
|
int nTrampleScore = (GetLocalInt(oNPC, "TRAMPLER") + GetHasFeat(FEAT_CENTAUR_TRAMPLE, oNPC));
|
||||||
|
|
||||||
|
int nChargeScore = (GetLocalInt(oNPC, "CHARGER") +
|
||||||
|
GetLocalInt(oNPC, "POUNCER") +
|
||||||
|
GetHasFeat(FEAT_MINOTAUR_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_ACROBATIC_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_SHIELD_CHARGE ,oNPC) +
|
||||||
|
GetHasFeat(FEAT_POWERFUL_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_GREATER_POWERFUL_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_RHINO_TRIBE_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_FURIOUS_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_RECKLESS_CHARGE, oNPC) +
|
||||||
|
GetHasFeat(FEAT_COBALT_CHARGE, oNPC));
|
||||||
|
|
||||||
|
int nBullRushScore = (GetLocalInt(oNPC, "BULLRUSHER") +
|
||||||
|
GetHasFeat(FEAT_IMPROVED_BULLRUSH, oNPC) +
|
||||||
|
GetHasFeat(FEAT_RAMPAGING_BULL_RUSH, oNPC) +
|
||||||
|
GetHasFeat(5241, oNPC) + //:: Expert Bull Rush
|
||||||
|
GetHasFeat(5247, oNPC)); //:: Superior Bull Rush
|
||||||
|
|
||||||
|
int iAwesomeBlow = GetHasFeat(FEAT_AWESOME_BLOW, oNPC);
|
||||||
|
|
||||||
|
int iOverrun = GetHasFeat(FEAT_IMPROVED_OVERRUN, oNPC);
|
||||||
|
|
||||||
if(GetHasEffect(EFFECT_TYPE_SLEEP))
|
if(GetHasEffect(EFFECT_TYPE_SLEEP))
|
||||||
{
|
{
|
||||||
@ -97,6 +128,58 @@ void main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//:: Run Various Combat Maneuver Heartbeats
|
||||||
|
if(iOverrun)
|
||||||
|
{
|
||||||
|
if (GetLocalInt(oNPC, "OverrrunCooldown") != 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug( "x2_def_heartbeat: Creature w/ Overrun Detected");
|
||||||
|
DelayCommand(0.0f, ExecuteScript("overrunner_hb", oNPC));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Overrun is on cooldown.");
|
||||||
|
}
|
||||||
|
if(iAwesomeBlow)
|
||||||
|
{
|
||||||
|
if (GetLocalInt(oNPC, "AwesomeBlowCooldown") != 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Creature w/ Awesome Blow Detected");
|
||||||
|
DelayCommand(0.0f, ExecuteScript("awesomeblow_hb", oNPC));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Awesome Blow is on cooldown.");
|
||||||
|
}
|
||||||
|
if(nTrampleScore)
|
||||||
|
{
|
||||||
|
if (GetLocalInt(oNPC, "TrampleCooldown") != 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Trampler Detected");
|
||||||
|
DelayCommand(0.0f, ExecuteScript("trampler_hb", oNPC));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Trample is on cooldown.");
|
||||||
|
}
|
||||||
|
if(nChargeScore)
|
||||||
|
{
|
||||||
|
if (GetLocalInt(oNPC, "ChargeCooldown") != 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Charger Detected");
|
||||||
|
DelayCommand(0.0f, ExecuteScript("charger_hb", oNPC));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Charge is on cooldown.");
|
||||||
|
}
|
||||||
|
if(nBullRushScore)
|
||||||
|
{
|
||||||
|
if (GetLocalInt(oNPC, "BullRushCooldown") != 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Bull Rusher Detected");
|
||||||
|
DelayCommand(0.0f, ExecuteScript("bullrusher_hb", oNPC));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("x2_def_heartbeat: Bull Rush is on cooldown.");
|
||||||
|
}
|
||||||
|
|
||||||
// Send the user-defined event signal if specified
|
// Send the user-defined event signal if specified
|
||||||
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
|
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
|
||||||
{
|
{
|
||||||
|
91
_module/nss/overrunner_hb.nss
Normal file
91
_module/nss/overrunner_hb.nss
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//:: overruner_hb.nss
|
||||||
|
//::
|
||||||
|
//:: Makes a creature pick a target & run DoOverrun() occasionally.
|
||||||
|
//::
|
||||||
|
#include "prc_inc_combmove"
|
||||||
|
#include "prc_inc_spells"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
|
||||||
|
string sName = GetName(oNPC);
|
||||||
|
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
|
||||||
|
// Define a range for target selection
|
||||||
|
float fRange;
|
||||||
|
|
||||||
|
if (nNPCSize == CREATURE_SIZE_INVALID) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_TINY) fRange = FeetToMeters(2.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_SMALL) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_MEDIUM) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_LARGE) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_HUGE) fRange = FeetToMeters(15.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_GARGANTUAN) fRange = FeetToMeters(20.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_COLOSSAL) fRange = FeetToMeters(30.0);
|
||||||
|
|
||||||
|
if(DEBUG) DoDebug("overruner_hb: Starting script on "+sName+".");
|
||||||
|
|
||||||
|
int bImpOverrun = GetHasFeat(FEAT_IMPROVED_OVERRUN, oNPC);
|
||||||
|
|
||||||
|
// Check if the cooldown is active
|
||||||
|
if (GetLocalInt(oNPC, "OverrunCooldown") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("overruner_hb: "+sName+" can't use Overrun while it is on cooldown.");
|
||||||
|
return; // Exit if cooldown is active
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleOriginator") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("overruner_hb: "+sName+" can't use Overrun while you are grappling an opponent.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleTarget") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("overruner_hb: "+sName+" can't use Overrun while you are being grappled.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Randomly decide whether to trigger the trample effect (e.g., 33% chance)
|
||||||
|
if (1 + Random(100) <= 33)
|
||||||
|
{
|
||||||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
|
||||||
|
// If we find a valid target, proceed
|
||||||
|
while (GetIsObjectValid(oTarget))
|
||||||
|
{
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
int nTargetSize = PRCGetCreatureSize(oTarget);
|
||||||
|
|
||||||
|
// Check if the target is a valid enemy, alive, and at least one size smaller
|
||||||
|
if (oTarget != oNPC && GetIsEnemy(oTarget, oNPC) && !GetIsDead(oTarget) && (nTargetSize <= nNPCSize + 1))
|
||||||
|
{
|
||||||
|
// Get the location of the target
|
||||||
|
location lTarget = GetLocation(oTarget);
|
||||||
|
|
||||||
|
// Set cooldown flag
|
||||||
|
SetLocalInt(oNPC, "OverrunCooldown", 1);
|
||||||
|
|
||||||
|
// Create a message using the names of the creatures
|
||||||
|
string sMessage = GetName(oNPC) + " is overrunning " + GetName(oTarget) + "!";
|
||||||
|
SendMessageToPC(oTarget, sMessage);
|
||||||
|
|
||||||
|
// Show floating text message
|
||||||
|
FloatingTextStringOnCreature(sMessage, oNPC, FALSE);
|
||||||
|
|
||||||
|
// Call the DoOverrun function
|
||||||
|
DoOverrun(oNPC, oTarget, lTarget, TRUE, 0, bImpOverrun, TRUE);
|
||||||
|
|
||||||
|
// Delay removal of the cooldown after 6-18 seconds (1-3 rounds)
|
||||||
|
DelayCommand(RoundsToSeconds(d3(1)), DeleteLocalInt(oNPC, "OverrunCooldown"));
|
||||||
|
|
||||||
|
break; // Exit the loop after overrunning
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the next target within the spell shape
|
||||||
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("overruner_hb: "+sName+" skipped Overrun");
|
||||||
|
}
|
88
_module/nss/trampler_hb.nss
Normal file
88
_module/nss/trampler_hb.nss
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//:: trampler_hb.nss
|
||||||
|
//::
|
||||||
|
//:: Makes a creature pick a target & run DoTrample occasionally.
|
||||||
|
//::
|
||||||
|
#include "prc_inc_combmove"
|
||||||
|
#include "prc_inc_spells"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
object oNPC = OBJECT_SELF;
|
||||||
|
|
||||||
|
string sName = GetName(oNPC);
|
||||||
|
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
|
||||||
|
// Define a range for target selection
|
||||||
|
float fRange;
|
||||||
|
|
||||||
|
if (nNPCSize == CREATURE_SIZE_INVALID) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_TINY) fRange = FeetToMeters(2.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_SMALL) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_MEDIUM) fRange = FeetToMeters(5.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_LARGE) fRange = FeetToMeters(10.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_HUGE) fRange = FeetToMeters(15.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_GARGANTUAN) fRange = FeetToMeters(20.0);
|
||||||
|
if (nNPCSize == CREATURE_SIZE_COLOSSAL) fRange = FeetToMeters(30.0);
|
||||||
|
|
||||||
|
if(DEBUG) DoDebug("trampler_hb: Starting script on "+sName+".");
|
||||||
|
|
||||||
|
// Check if the cooldown is active
|
||||||
|
if (GetLocalInt(oNPC, "TrampleCooldown") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("trampler_hb: "+sName+" can't use Trample while it is on cooldown.");
|
||||||
|
return; // Exit if cooldown is active
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleOriginator") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("trampler_hb: "+sName+" can't use Trample while grappling.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
if (GetLocalInt(oNPC, "GrappleTarget") == 1)
|
||||||
|
{
|
||||||
|
if(DEBUG) DoDebug("trampler_hb: "+sName+" can't use Trample while grappled.");
|
||||||
|
return; // Exit
|
||||||
|
}
|
||||||
|
// Randomly decide whether to trigger the trample effect (e.g., 33% chance)
|
||||||
|
if (1 + Random(100) <= 33)
|
||||||
|
{
|
||||||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
|
||||||
|
// If we find a valid target, proceed
|
||||||
|
while (GetIsObjectValid(oTarget))
|
||||||
|
{
|
||||||
|
int nNPCSize = PRCGetCreatureSize(oNPC);
|
||||||
|
int nTargetSize = PRCGetCreatureSize(oTarget);
|
||||||
|
|
||||||
|
// Check if the target is a valid enemy, alive, and at least one size smaller
|
||||||
|
if (oTarget != oNPC && GetIsEnemy(oTarget, oNPC) && !GetIsDead(oTarget) && nTargetSize < nNPCSize)
|
||||||
|
{
|
||||||
|
// Get the location of the target
|
||||||
|
location lTarget = GetLocation(oTarget);
|
||||||
|
|
||||||
|
// Set cooldown flag
|
||||||
|
SetLocalInt(oNPC, "TrampleCooldown", 1);
|
||||||
|
|
||||||
|
// Create a message using the names of the creatures
|
||||||
|
string sMessage = GetName(oNPC) + " is trampling " + GetName(oTarget) + "!";
|
||||||
|
|
||||||
|
// Show floating text message
|
||||||
|
FloatingTextStringOnCreature(sMessage, oNPC, FALSE);
|
||||||
|
SendMessageToPC(oTarget, sMessage);
|
||||||
|
|
||||||
|
// Call the DoTrample function
|
||||||
|
DoTrample(oNPC, oTarget, lTarget);
|
||||||
|
|
||||||
|
// Delay removal of the cooldown after 6-18 seconds (1-3 rounds)
|
||||||
|
DelayCommand(RoundsToSeconds(d3(1)), DeleteLocalInt(oNPC, "TrampleCooldown"));
|
||||||
|
|
||||||
|
break; // Exit the loop after trampling
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the next target within the spell shape
|
||||||
|
oTarget = MyNextObjectInShape(SHAPE_SPHERE, fRange, GetLocation(oNPC), TRUE, OBJECT_TYPE_CREATURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(DEBUG) DoDebug("trampler_hb: "+sName+" skipped Trample");
|
||||||
|
}
|
16
_module/nss/x2_def_heartbeat.nss
Normal file
16
_module/nss/x2_def_heartbeat.nss
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//::///////////////////////////////////////////////
|
||||||
|
//:: Name x2_def_heartbeat
|
||||||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||||||
|
//:://////////////////////////////////////////////
|
||||||
|
/*
|
||||||
|
Default Heartbeat script
|
||||||
|
*/
|
||||||
|
//:://////////////////////////////////////////////
|
||||||
|
//:: Created By: Keith Warner
|
||||||
|
//:: Created On: June 11/03
|
||||||
|
//:://////////////////////////////////////////////
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
ExecuteScript("nw_c2_default1", OBJECT_SELF);
|
||||||
|
}
|
@ -581,6 +581,26 @@
|
|||||||
"type": "resref",
|
"type": "resref",
|
||||||
"value": "cougar001"
|
"value": "cougar001"
|
||||||
},
|
},
|
||||||
|
"VarTable": {
|
||||||
|
"type": "list",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"__struct_id": 0,
|
||||||
|
"Name": {
|
||||||
|
"type": "cexostring",
|
||||||
|
"value": "POUNCER"
|
||||||
|
},
|
||||||
|
"Type": {
|
||||||
|
"type": "dword",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
"Value": {
|
||||||
|
"type": "int",
|
||||||
|
"value": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"WalkRate": {
|
"WalkRate": {
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"value": 7
|
"value": 7
|
||||||
|
@ -164,6 +164,13 @@
|
|||||||
"value": 17
|
"value": 17
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2805
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
@ -171,6 +178,13 @@
|
|||||||
"value": 23
|
"value": 23
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2811
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
|
@ -143,6 +143,20 @@
|
|||||||
"value": 63
|
"value": 63
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2805
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2811
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
|
@ -140,6 +140,20 @@
|
|||||||
"value": 4
|
"value": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2810
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 3413
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
@ -147,6 +161,13 @@
|
|||||||
"value": 228
|
"value": 228
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 2806
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
|
@ -175,6 +175,13 @@
|
|||||||
"value": 40
|
"value": 40
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__struct_id": 1,
|
||||||
|
"Feat": {
|
||||||
|
"type": "word",
|
||||||
|
"value": 8824
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__struct_id": 1,
|
"__struct_id": 1,
|
||||||
"Feat": {
|
"Feat": {
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user