250 lines
10 KiB
Plaintext
250 lines
10 KiB
Plaintext
// Hellcat OnUserDefined
|
|
// 05.28.04
|
|
// by Invizible420
|
|
// Hellcat Heartbeat script
|
|
// 04.28.05
|
|
// by Invizible420
|
|
|
|
// Line 129 - 132 you can configure the chances to grapple and rake
|
|
|
|
#include "inc_utility"
|
|
|
|
// Colors
|
|
object oCOLOR_OBJ = GetObjectByTag("i420_COLOR_OBJ");
|
|
string COLOR_RED = GetStringLeft(GetName(oCOLOR_OBJ),6);
|
|
string COLOR_BLUE = GetStringRight(GetName(oCOLOR_OBJ),6);
|
|
|
|
// Debugger
|
|
//int DEBUG = FALSE;
|
|
void DB(string sDebug)
|
|
{
|
|
if (DEBUG == TRUE) SendMessageToPC(GetFirstPC(), sDebug);
|
|
}
|
|
// Function that is used to determine if a PC is in the area, to save HB CPU cycles
|
|
int GetIsPCInArea(object oArea)
|
|
{
|
|
int iRValue = FALSE;
|
|
object oPC = GetFirstPC();
|
|
while(GetIsObjectValid(oPC) == TRUE)
|
|
{
|
|
if (GetArea(oPC) == oArea && GetIsDead(oPC) != TRUE) iRValue = TRUE;
|
|
oPC = GetNextPC();
|
|
}
|
|
return iRValue;
|
|
}
|
|
|
|
int GetHasEffect(object oCreature, effect eEffect)
|
|
{
|
|
int iRValue = FALSE;
|
|
effect e1stEffect = GetFirstEffect(oCreature);
|
|
while (GetIsEffectValid(e1stEffect) == TRUE)
|
|
{
|
|
if (e1stEffect == eEffect) iRValue = TRUE;
|
|
e1stEffect = GetNextEffect(oCreature);
|
|
}
|
|
return iRValue;
|
|
}
|
|
|
|
void DoGrapple(object oTarget, object oGrappler, int iRakeChance, int iRakeAmount)
|
|
{
|
|
if (GetLocalInt(oTarget, "AoO_SUCCESS") != 1)
|
|
{
|
|
|
|
DB(GetName(oTarget)+" missed the Attack of Opportunity"); // Debug Line
|
|
|
|
// Grapple Vars for formula calculation
|
|
int iGrapplerAtkBonus = GetBaseAttackBonus(OBJECT_SELF);
|
|
int iTargetAtkBonus = GetBaseAttackBonus(oTarget);
|
|
int iGrapplersStrMod = GetAbilityModifier(ABILITY_STRENGTH, OBJECT_SELF);
|
|
int iTargetsStrMod = GetAbilityModifier(ABILITY_STRENGTH, oTarget);
|
|
int iTempTargetSize = GetCreatureSize(oTarget);
|
|
int iTargetSize;
|
|
switch(iTempTargetSize)
|
|
{
|
|
case CREATURE_SIZE_HUGE: iTargetSize = 5;
|
|
case CREATURE_SIZE_INVALID: iTargetSize = 0;
|
|
case CREATURE_SIZE_LARGE: iTargetSize = 4;
|
|
case CREATURE_SIZE_MEDIUM: iTargetSize = 3;
|
|
case CREATURE_SIZE_SMALL: iTargetSize = 2;
|
|
case CREATURE_SIZE_TINY: iTargetSize = 1;
|
|
}
|
|
int id20 = d20(1);
|
|
int id20_2 = d20(1);
|
|
|
|
// Grapple Check Formulas
|
|
int iGrapplersGCheck = id20_2+iGrapplerAtkBonus+iGrapplersStrMod+4; // 4 because the Hellcat is a large creature
|
|
int iTargetGCheck = id20+iTargetAtkBonus+iTargetsStrMod+iTargetSize; // PC's grapple check
|
|
DB(GetName(oTarget)+"'s GCheck = "+IntToString(iTargetGCheck)+" versus "+GetName(OBJECT_SELF)+"'s GCheck = "+IntToString(iGrapplersGCheck));
|
|
|
|
if (GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN) == TRUE)
|
|
{
|
|
DeleteLocalInt(oTarget, "AoO_SUCCESS");
|
|
DeleteLocalInt(oTarget, "AoO_TO_RESIST_GRAPPLE");
|
|
DeleteLocalObject(OBJECT_SELF,"IS_GRAPPLING");
|
|
|
|
// removed this feedback... not necessary
|
|
// SendMessageToPC(oTarget, "Immunity to knockdown resists the grapple attempt from the "+GetName(oGrappler)+".");
|
|
}
|
|
else if (iGrapplersGCheck > iTargetGCheck)
|
|
{
|
|
SetLocalObject(oGrappler, "IS_GRAPPLING", oTarget);
|
|
SendMessageToPC(oTarget,COLOR_BLUE+GetName(oTarget)+"'s Grapple Check vs. "+GetName(OBJECT_SELF)+"'s : *failure* ("+IntToString(iTargetGCheck)+" vs. "+IntToString(iGrapplersGCheck)+")");
|
|
ActionAttack(oTarget);
|
|
ActionForceMoveToObject(oTarget, TRUE, 0.25, 0.25);
|
|
AssignCommand(oTarget, ActionDoCommand(ActionForceMoveToObject(oGrappler,TRUE,0.25,0.25)));
|
|
// knock down the PC for 1 round, and set int to say they are grappled and held
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0);
|
|
// Do Rake Stuff
|
|
if (iRakeChance > d100(1))
|
|
{
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_BLOOD_REG_RED), oTarget);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(iRakeAmount,DAMAGE_TYPE_PIERCING), oTarget);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// per d&d 3rd ed... if the PC wins the grapple check 1d3 damage to other
|
|
SendMessageToPC(oTarget,COLOR_BLUE+GetName(oTarget)+"'s Grapple Check vs. "+GetName(OBJECT_SELF)+"'s : *success* ("+IntToString(iTargetGCheck)+" vs. "+IntToString(iGrapplersGCheck)+")");
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d3(1),DAMAGE_TYPE_BLUDGEONING), OBJECT_SELF);
|
|
DeleteLocalInt(oTarget, "AoO_SUCCESS");
|
|
DeleteLocalInt(oTarget, "AoO_TO_RESIST_GRAPPLE");
|
|
DeleteLocalObject(OBJECT_SELF,"IS_GRAPPLING");
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FloatingTextStringOnCreature("Attack of Opportunity",oTarget,FALSE);
|
|
AssignCommand(oTarget,ActionAttack(OBJECT_SELF));
|
|
DeleteLocalInt(oTarget, "AoO_SUCCESS");
|
|
DeleteLocalInt(oTarget, "AoO_TO_RESIST_GRAPPLE");
|
|
DeleteLocalObject(OBJECT_SELF,"IS_GRAPPLING");
|
|
}
|
|
}
|
|
|
|
|
|
int iEventNum = GetUserDefinedEventNumber();
|
|
void main()
|
|
{
|
|
int DO_GRAPPLE_RAKE = TRUE; // Set to False and OBJECT_SELF will not do grapple and rake stuff
|
|
int GRAPPLE_CHANCE = 25; // Chance when bite is used OBJECT_SELF will grapple
|
|
int RAKE_CHANCE = 50; // Chance OBJECT_SELF will rake while grappling
|
|
int RAKE_DMG = d4(1)+3; // Rake damage
|
|
|
|
switch(iEventNum)
|
|
{
|
|
case 1001: // Called by OnHeartbeat
|
|
|
|
|
|
if(GetLocalObject(OBJECT_SELF, "IS_GRAPPLING") != OBJECT_INVALID &&
|
|
GetIsDead(GetLocalObject(OBJECT_SELF, "IS_GRAPPLING")) != TRUE)
|
|
{
|
|
object oPC = GetLocalObject(OBJECT_SELF, "IS_GRAPPLING");
|
|
ActionForceMoveToObject(oPC,TRUE,0.5,0.5);
|
|
SendMessageToPC(oPC,COLOR_RED+"The "+GetName(OBJECT_SELF)+" holds on to you.");
|
|
DeleteLocalInt(oPC,"AoO_SUCCESS");
|
|
DoGrapple(oPC, OBJECT_SELF, RAKE_CHANCE, RAKE_DMG);
|
|
}
|
|
else if(GetLocalObject(OBJECT_SELF, "IS_GRAPPLING") != OBJECT_INVALID &&
|
|
GetIsDead(GetLocalObject(OBJECT_SELF, "IS_GRAPPLING")) == TRUE)
|
|
{
|
|
DeleteLocalInt(GetLocalObject(OBJECT_SELF,"IS_GRAPPLING"), "AoO_SUCCESS");
|
|
DeleteLocalInt(GetLocalObject(OBJECT_SELF,"IS_GRAPPLING"), "AoO_TO_RESIST_GRAPPLE");
|
|
DeleteLocalInt(GetLocalObject(OBJECT_SELF, "LAST_ATTACKER"), "AoO_SUCCESS");
|
|
DeleteLocalInt(GetLocalObject(OBJECT_SELF, "LAST_ATTACKER"), "AoO_TO_RESIST_GRAPPLE");
|
|
DeleteLocalObject(OBJECT_SELF,"IS_GRAPPLING");
|
|
DeleteLocalObject(OBJECT_SELF,"IS_GRAPPLING");
|
|
DeleteLocalObject(OBJECT_SELF, "LAST_ATTACKER");
|
|
|
|
}
|
|
|
|
// Run script only if a PC is in the area
|
|
if (GetIsPCInArea(GetArea(OBJECT_SELF)) == TRUE)
|
|
{
|
|
DB("PC_IN_AREA"); // Debug Line
|
|
|
|
|
|
// Vars to find the numerical location of OBJECT_SELF
|
|
object oArea = GetArea(OBJECT_SELF);
|
|
vector vPos = GetPosition(OBJECT_SELF);
|
|
float fFace = GetFacing(OBJECT_SELF);
|
|
location lLoc = Location(oArea, vPos, fFace);
|
|
int iLight1 = GetTileSourceLight1Color(lLoc);
|
|
int iLight2 = GetTileSourceLight2Color(lLoc);
|
|
int iMLight1 = GetTileMainLight1Color(lLoc);
|
|
int iMLight2 = GetTileMainLight2Color(lLoc);
|
|
|
|
DB("iLight1 = "+IntToString(iLight1)); // Debug Line
|
|
DB("iLight2 = "+IntToString(iLight1)); // Debug Line
|
|
DB("iMLight1 = "+IntToString(iLight1)); // Debug Line
|
|
DB("iMLight2 = "+IntToString(iLight1)); // Debug Line
|
|
|
|
|
|
// Remove of Apply Invisibility if light is on OBJECT_SELF or not
|
|
if (iLight1 != TILE_SOURCE_LIGHT_COLOR_WHITE ||
|
|
iLight1 != TILE_SOURCE_LIGHT_COLOR_PALE_YELLOW ||
|
|
iLight2 != TILE_SOURCE_LIGHT_COLOR_WHITE ||
|
|
iLight2 != TILE_SOURCE_LIGHT_COLOR_PALE_YELLOW ||
|
|
iMLight1 != TILE_MAIN_LIGHT_COLOR_YELLOW ||
|
|
iMLight1 != TILE_MAIN_LIGHT_COLOR_PALE_YELLOW ||
|
|
iMLight1 != TILE_MAIN_LIGHT_COLOR_DIM_WHITE ||
|
|
iMLight1 != TILE_MAIN_LIGHT_COLOR_BRIGHT_WHITE ||
|
|
iMLight2 != TILE_MAIN_LIGHT_COLOR_YELLOW ||
|
|
iMLight2 != TILE_MAIN_LIGHT_COLOR_PALE_YELLOW ||
|
|
iMLight2 != TILE_MAIN_LIGHT_COLOR_DIM_WHITE ||
|
|
iMLight2 != TILE_MAIN_LIGHT_COLOR_BRIGHT_WHITE)
|
|
{
|
|
RemoveEffect(OBJECT_SELF, EffectVisualEffect(VFX_DUR_INVISIBILITY));
|
|
}
|
|
else if(GetHasEffect(OBJECT_SELF, EffectVisualEffect(VFX_DUR_INVISIBILITY)) == FALSE)
|
|
{
|
|
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_INVISIBILITY), OBJECT_SELF);
|
|
}
|
|
|
|
// Grapple and Rake Stuff
|
|
if (GetIsInCombat(OBJECT_SELF) == TRUE && DO_GRAPPLE_RAKE == TRUE)
|
|
{
|
|
object oLastAttacker = GetLocalObject(OBJECT_SELF, "LAST_ATTACKER");
|
|
|
|
DB(GetName(OBJECT_SELF)+" is in combat with "+GetName(oLastAttacker)); // Debug Line
|
|
|
|
if (GetDistanceBetween(oLastAttacker, OBJECT_SELF) <= 5.0)
|
|
{
|
|
int iMeleeTouch = TouchAttackMelee(oLastAttacker, TRUE);
|
|
|
|
DB(GetName(OBJECT_SELF)+"'s Melee Touch Attack = "+IntToString(iMeleeTouch)); // Debug Line
|
|
|
|
// Grapple
|
|
if (GRAPPLE_CHANCE > d100(1) && iMeleeTouch >= 1 && GetLocalInt(oLastAttacker, "IS_GRAPPLED") != 1)
|
|
{
|
|
ActionUseSkill(SKILL_TAUNT, oLastAttacker);
|
|
SetLocalInt(oLastAttacker, "AoO_TO_RESIST_GRAPPLE",1);
|
|
DoGrapple(oLastAttacker, OBJECT_SELF, RAKE_CHANCE, RAKE_DMG);
|
|
}
|
|
}
|
|
else DeleteLocalObject(OBJECT_SELF, "LAST_ATTACKER");
|
|
}
|
|
}
|
|
break;
|
|
//
|
|
|
|
|
|
case 1002: // Called by OnPerception
|
|
SetLocalObject(OBJECT_SELF, "LAST_ATTACKER", GetLastPerceived());
|
|
break;
|
|
case 1005: // Called by Attack
|
|
SetLocalObject(OBJECT_SELF, "LAST_ATTACKER", GetLastAttacker());
|
|
break;
|
|
case 1006:
|
|
if (GetLocalInt(GetLastDamager(OBJECT_SELF), "AoO_TO_RESIST_GRAPPLE") == 1) SetLocalInt(GetLastDamager(OBJECT_SELF), "AoO_SUCCESS", 1);
|
|
break;
|
|
case 1007:
|
|
DelayCommand(4.0,ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_UNDEAD),OBJECT_SELF));
|
|
break;
|
|
case 1010:
|
|
SetLocalObject(OBJECT_SELF, "LAST_ATTACKER", GetLastSpellCaster());
|
|
break;
|
|
}
|
|
}
|
|
|