Agreed (with Shadow) on the no-auto failure rationale - we don't have auto-fail for monsters, only players (mostly party PvM server setting with rare PvP, though it doesn't matter since monster saves are balanced). We answered the immunities things by making many, but not all attacks, ignore immunity from gear. You can do this by stripping and reapplying gear immunities without players ever noticing (though you don't need to for death effects) - which is of course far more granular. Here's our hg_attack_inc:
#include "ac_level_inc"
#include "hg_antiex_inc"
void AttackEffectCallback (int nCallback, object oSelf, object oTarget);
void AttackResistCallback (int nCallback, object oSelf, object oTarget);
int GetCombatActive (object oCreature, object oArea) {
if (!GetIsInCombat(oCreature) || GetLocalInt(oCreature, "Friendly"))
return FALSE;
if (GetLocalInt(oArea, "TimeStop") && GetLocalObject(oArea, "TimeStopper") != oCreature)
return FALSE;
if (GetHasEffectOfType(EFFECT_TYPE_PETRIFY, oCreature))
return FALSE;
return TRUE;
}
int GetArmorACBase (object oTarget) {
return GetItemACBase(GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget));
}
int GetIsKnockedDown (object oTarget) {
return GetHasEffectOfTrueType(EFFECT_TRUETYPE_KNOCKDOWN, oTarget);
}
int GetPCGrappleModifier (object oPC) {
int nBaseItem = BASE_ITEM_GLOVES, nMod = GetTrueBaseAttackBonus(oPC);
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
if (GetHasFeat(FEAT_EPIC_PROWESS, oPC))
nMod += 1;
/* add weapon feats */
if (GetIsObjectValid(oWeapon))
nBaseItem = GetBaseItemType(oWeapon);
if (GetHasFeat(GetWeaponFocusFeat(nBaseItem), oPC))
nMod += 1;
if (GetHasFeat(GetWeaponGreaterFocusFeat(nBaseItem), oPC))
nMod += 1;
if (GetHasFeat(GetWeaponEpicFocusFeat(nBaseItem), oPC))
nMod += 2;
if (GetHasFeat(GetWeaponLegendaryFocusFeat(nBaseItem), oPC))
nMod += 3;
/* add WM bonus AB */
if (GetHasFeat(GetWeaponOfChoiceFeat(nBaseItem), oPC)) {
int nWM = GetLevelByclass(class_TYPE_WEAPON_MASTER, oPC);
if (nWM < 13)
nMod++;
else
nMod += 1 + ((nWM - 10) / 3);
} else {
/* unarmed feats count double if no WM */
if (GetHasFeat(FEAT_WEAPON_FOCUS_UNARMED_STRIKE, oPC))
nMod += 1;
if (GetHasFeat(HGFEAT_GREATER_WEAPON_FOCUS_UNARMED_STRIKE, oPC))
nMod += 1;
if (GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_UNARMED, oPC))
nMod += 2;
if (GetHasFeat(HGFEAT_LEG_WEAPON_FOCUS_UNARMED_STRIKE, oPC))
nMod += 3;
}
return nMod;
}
int GetAttackCheckResult (object oTarget, int nCheckType, int nCheckParam, object oSelf, float fDelay) {
int nBonus = 0, nResult = 0, nCheckSubType = (nCheckType & 0xFFFFFF);
if (nCheckType & 0x40000000) {
if (GetHasSpellEffect(HGSPELL_EPIC_UNBOWED_UNBENT_UNBROKEN, oTarget))
nBonus = 8;
if (nCheckType & 0x3F000000 == CHECK_TYPE_SKILL)
nBonus *= 2;
}
switch (nCheckType & 0x3F000000) {
case CHECK_TYPE_SAVE:
if (nCheckSubType == 4)
nResult = MindSave(oTarget, nCheckParam, oSelf);
else
nResult = GetSaveCheckResult(nCheckSubType & 0xF, oTarget, nCheckParam, (nCheckSubType >> 4), TRUE, TRUE, oSelf, fDelay);
break;
case CHECK_TYPE_SKILL:
nResult = GetSkillCheckResult(nCheckSubType, oTarget, nCheckParam, TRUE, (nBonus ? 2 : 0), oSelf, fDelay, 0, nBonus);
break;
case CHECK_TYPE_ABILITY:
nResult = GetAbilityCheckResult(nCheckSubType, oTarget, nCheckParam, TRUE, (nBonus ? 2 : 0), oSelf, fDelay, nBonus);
break;
default: return 1;
}
return nResult;
}
object FindCasterTarget (object oSelf=OBJECT_SELF) {
int i, nclass;
object oPC;
for (i = 1; i < 11; i++) {
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, oSelf, i,
CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
nclass = GetHighestCasterclass(oPC);
if (GetLevelByclass(nclass, oPC) > 10 &&
!GetHasEffectOfType(EFFECT_TYPE_SILENCE, oPC) &&
!GetHasSpellEffect(SPELL_ETHEREALNESS, oPC))
return oPC;
}
return OBJECT_INVALID;
}
object FindDistancedTarget (object oSelf, int nNearest, int nFurthest, float fMaxDistance=100.0, float fMinDistance=0.0) {
float fDist;
int i = nNearest + Random(nFurthest - nNearest);
object oPC = OBJECT_INVALID;
while (i >= nNearest && !GetIsObjectValid(oPC)) {
oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, oSelf, i--,
CREATURE_TYPE_IS_ALIVE, TRUE, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if (GetHasSpellEffect(SPELL_ETHEREALNESS, oPC))
oPC = OBJECT_INVALID;
else if ((fDist = GetDistanceBetween(oPC, oSelf)) > fMaxDistance)
oPC = OBJECT_INVALID;
else if (fDist < fMinDistance)
oPC = OBJECT_INVALID;
}
if (i < nNearest - 1)
return OBJECT_INVALID;
return oPC;
}
void ApplyBlindness (object oTarget, int nRounds, string sMessage, int bNoStack=TRUE, int bEx=TRUE, int nSpellId=-1, int bSpells=FALSE) {
if ((bNoStack && GetHasEffectOfType(EFFECT_TYPE_BLINDNESS, oTarget)) || GetPlotFlag(oTarget))
return;
effect eLink = EffectLinkEffects(EffectBlindness(), EffectSkillDecrease(SKILL_SPOT, 30));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_BLINDVISION));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
if (bSpells)
RemoveEffectsFromSpell(SPELL_UNDEATHS_ETERNAL_FOE, oTarget);
ApplyVisualToObject(VFX_IMP_BLIND_DEAF_M, oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyConfuse (object oTarget, int nRounds=10, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (!GetIsPC(oTarget) || GetPlotFlag(oTarget))
return;
effect eLink = EffectConfused();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DOMINATED));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_CONFUSION_S, oTarget);
if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyDaze (object oTarget, int nRounds=4, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectDazed();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_DAZED_S, oTarget);
if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyDeafness (object oTarget, int nRounds, string sMessage, int bSilenceBlocks=TRUE, int bNoStack=TRUE, int bEx=TRUE, int nSpellId=-1) {
if ((bNoStack && GetHasEffectOfType(EFFECT_TYPE_DEAF, oTarget)) || GetPlotFlag(oTarget))
return;
if (bSilenceBlocks &&!GetHasEffectOfType(EFFECT_TYPE_SILENCE, oTarget))
return;
effect eLink = EffectLinkEffects(EffectDeaf(), EffectSkillDecrease(SKILL_LISTEN, 30));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_BLIND_DEAF_M, oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyDisarm (object oTarget, string sMessage, int bIgnore=FALSE) {
if (GetPlotFlag(oTarget) || (bIgnore < 2 && GetHasSpellImmunity(HGSPELL_IRON_GRASP, oTarget)))
return;
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if (!GetIsObjectValid(oWeapon) || GetLocalInt(oWeapon, "REPLACED"))
return;
if (GetLocalInt(oWeapon, "NoDisarm") > bIgnore)
return;
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
if (GetIsPC(oTarget)) {
object oReplace = DestroyLostItem(oTarget, oWeapon, "DISEQUIP", "Disarmed Weapon");
if (GetResRef(oReplace) == "moltenslag") {
SetDescription(oReplace, "This is a disarmed weapon.\\\\\\\\n-----\\\\\\\\nUse the Unique Power on this item to restore it.\\\\\\\\n");
SetItemAppearance(oReplace, -3, 83);
}
} else {
effect eEff = EffectDisarm(0);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
}
}
void ApplyFear (object oTarget, int nRounds=10, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectFrightened();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_FEAR));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_FEAR_S, oTarget);
if (bIgnore > 1)
ApplyEffectIgnoringImmunities(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds), IGNORE_IMM_MIND|IGNORE_IMM_FEAR);
else if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds), FALSE);
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyKnockdown (object oTarget, int nRounds=3, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1, int nTumbleDC=120) {
if (GetPlotFlag(oTarget) || GetIsKnockedDown(oTarget))
return;
effect eLink = EffectLinkEffects(EffectKnockdown(), EffectIcon(EFFECT_ICON_KNOCKDOWN));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
float fDur = RoundsToSeconds(nRounds);
if (nTumbleDC > 0 && GetSkillCheckResult(SKILL_TUMBLE, oTarget, nTumbleDC) > 0)
fDur -= 6.0;
/* the Orb of Dragonkind halves knockdown duration */
if (GetLocalInt(oTarget, "StatArtifactUsed") == HGARTIFACT_ORB_OF_DRAGONKIND)
fDur /= 2.0;
if (fDur < 6.0)
fDur = 6.0;
if (bIgnore) {
ApplyEffectIgnoringKnockdownImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
RemoveEffectsFromSpell(HGEFFECT_UNTOUCHABLE_CURSE, oTarget);
} else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyLevelDrain (object oTarget, int nLevels=8, string sMessage="", int bIgnore=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectNegativeLevel(nLevels);
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = SupernaturalEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_REDUCE_ABILITY_SCORE, oTarget);
if (bIgnore)
ApplyEffectIgnoringDrainImmunity(DURATION_TYPE_PERMANENT, eLink, oTarget);
else
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
}
void ApplyParalyze (object oTarget, int nRounds=4, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectParalyze();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_PARALYZE_HOLD));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplySleep (object oTarget, int nRounds=4, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectSleep();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_SLEEP, oTarget);
if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
void ApplyStun (object oTarget, int nRounds=4, string sMessage="", int bIgnore=TRUE, int bEx=TRUE, int nSpellId=-1) {
if (GetPlotFlag(oTarget))
return;
effect eLink = EffectStunned();
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE));
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED));
if (bEx)
eLink = ExtraordinaryEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
ApplyVisualToObject(VFX_IMP_STUN, oTarget);
if (bIgnore)
ApplyEffectIgnoringMindImmunity(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
else
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(nRounds));
}
int DoBardSong (object oSelf, int nSongLevel, int nCurseLevel, int bCurseFirst=FALSE) {
int nSongCount = 0, nCurseCount = 0;
location lSelf = GetLocation(oSelf);
object oTarget;
if (GetHasDisablingEffect(oSelf) ||
GetHasEffectOfType(EFFECT_TYPE_SILENCE, oSelf))
return -1;
for (oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lSelf);
GetIsObjectValid(oTarget);
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lSelf)) {
if (GetIsDead(oTarget) || GetPlotFlag(oTarget))
continue;
if (nSongLevel > 0 && GetFactionEqual(oTarget, oSelf) && !GetHasSpellEffect(SPELLABILITY_BARD_SONG, oTarget))
nSongCount++;
else if (nCurseLevel > 0 && GetIsPC(oTarget) && !GetHasSpellEffect(SPELLABILITY_EPIC_CURSE_SONG, oTarget))
nCurseCount++;
}
if (nSongCount > 0 && !(bCurseFirst && nCurseCount > 0)) {
SetLocalInt(oSelf, "TempSongLevel", nSongLevel);
AssignCommand(oSelf, ClearAllActions(TRUE));
AssignCommand(oSelf, ActionCastSpellAtLocation(SPELLABILITY_BARD_SONG, lSelf, METAMAGIC_NONE, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
return 1;
} else if (nCurseCount > 0) {
SetLocalInt(oSelf, "TempSongLevel", nCurseLevel);
AssignCommand(oSelf, ClearAllActions(TRUE));
AssignCommand(oSelf, ActionCastSpellAtLocation(SPELLABILITY_EPIC_CURSE_SONG, lSelf, METAMAGIC_NONE, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
return 2;
}
return 0;
}
object DoGrapple (object oSelf, object oTarget, string sMessage, int nDC) {
int nTargetMod, nSelfRoll, nTargetRoll;
float fDelay = 0.0;
string sSign = " + ";
object oGrapple = GetLocalObject(oSelf, "GrappleTarget");
if (!GetIsObjectValid(oGrapple) || !GetHasEffectOfType(EFFECT_TYPE_CUTSCENE_PARALYZE, oGrapple)) {
DeleteLocalObject(oSelf, "GrappleTarget");
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENEIMMOBILIZE, oSelf, oSelf);
oGrapple = OBJECT_INVALID;
}
if (GetIsObjectValid(oGrapple)) {
if (GetPlotFlag(oGrapple) || GetDistanceBetween(oGrapple, oSelf) > 5.0 || GetHasSpellImmunity(SPELL_FREEDOM_OF_MOVEMENT, oGrapple)) {
DeleteLocalObject(oSelf, "GrappleTarget");
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENEIMMOBILIZE, oSelf, oSelf);
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENE_PARALYZE, oGrapple, oSelf);
return OBJECT_INVALID;
}
if ((nTargetMod = GetPCGrappleModifier(oGrapple)) < 0)
sSign = " - ";
nSelfRoll = 5; /* currently static */
nTargetRoll = d20();
if (nDC + nSelfRoll > nTargetMod + nTargetRoll) {
string sCheck = C_PALE_BLUE_PURPLE + GetName(oGrapple) + C_BLUE_PURPLE +
" : " + "Grapple vs. " + GetName(oSelf) + " : *grappled* : (" + IntToString(nTargetRoll) +
sSign + IntToString(abs(nTargetMod)) + " = " + IntToString(nTargetRoll + nTargetMod) +
" vs. DC: " + IntToString(nSelfRoll + nDC) + ")" + C_END;
switch (GetPCFilter(oGrapple, PCFILTER_CHECK)) {
case 0: DelayCommand(fDelay, SendMessageToPC(oGrapple, sCheck)); break;
case 1: DelayCommand(fDelay, SendSystemMessage(oGrapple, sCheck)); break;
case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(sCheck, oGrapple, FALSE)); break;
}
effect eGrap = EffectLinkEffects(EffectCutsceneParalyze(), EffectIcon(EFFECT_ICON_DOMINATED));
eGrap = ExtraordinaryEffect(eGrap);
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENE_PARALYZE, oGrapple, oSelf);
DelayCommand(0.01, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eGrap, oGrapple, 30.0));
return oGrapple;
} else {
string sCheck = C_PALE_BLUE_PURPLE + GetName(oGrapple) + C_BLUE_PURPLE +
" : " + "Grapple vs. " + GetName(oSelf) + " : *escaped* : (" + IntToString(nTargetRoll) +
sSign + IntToString(abs(nTargetMod)) + " = " + IntToString(nTargetRoll + nTargetMod) +
" vs. DC: " + IntToString(nSelfRoll + nDC) + ")" + C_END;
switch (GetPCFilter(oGrapple, PCFILTER_CHECK)) {
case 0: DelayCommand(fDelay, SendMessageToPC(oGrapple, sCheck)); break;
case 1: DelayCommand(fDelay, SendSystemMessage(oGrapple, sCheck)); break;
case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(sCheck, oGrapple, FALSE)); break;
}
DeleteLocalObject(oSelf, "GrappleTarget");
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENEIMMOBILIZE, oSelf, oSelf);
RemoveEffectsOfType(EFFECT_TYPE_CUTSCENE_PARALYZE, oGrapple, oSelf);
}
} else if (GetIsPC(oTarget) && !GetPlotFlag(oTarget)) {
if (GetDistanceBetween(oTarget, oSelf) > 2.5 || GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oTarget))
return OBJECT_INVALID;
if ((nTargetMod = GetPCGrappleModifier(oTarget)) < 0)
sSign = " - ";
nSelfRoll = d20();
nTargetRoll = d20();
if (nDC + nSelfRoll > nTargetMod + nTargetRoll) {
string sCheck = C_PALE_BLUE_PURPLE + GetName(oTarget) + C_BLUE_PURPLE +
" : " + "Grapple vs. " + GetName(oSelf) + " : *grappled* : (" + IntToString(nTargetRoll) +
sSign + IntToString(abs(nTargetMod)) + " = " + IntToString(nTargetRoll + nTargetMod) +
" vs. DC: " + IntToString(nSelfRoll + nDC) + ")" + C_END;
switch (GetPCFilter(oTarget, PCFILTER_CHECK)) {
case 0: DelayCommand(fDelay, SendMessageToPC(oTarget, sCheck)); break;
case 1: DelayCommand(fDelay, SendSystemMessage(oTarget, sCheck)); break;
case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(sCheck, oTarget, FALSE)); break;
}
effect eSelf = ExtraordinaryEffect(EffectCutsceneImmobilize());
effect eGrap = EffectLinkEffects(EffectCutsceneParalyze(), EffectIcon(EFFECT_ICON_DOMINATED));
eGrap = ExtraordinaryEffect(eGrap);
SetLocalObject(oSelf, "GrappleTarget", oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eGrap, oTarget, 30.0);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSelf, oSelf);
if (sMessage != "")
DelayCommand(0.2, FloatingTextStringOnCreature(sMessage, oTarget, FALSE));
} else {
string sCheck = C_PALE_BLUE_PURPLE + GetName(oTarget) + C_BLUE_PURPLE +
" : " + "Grapple vs. " + GetName(oSelf) + " : *evaded* : (" + IntToString(nTargetRoll) +
sSign + IntToString(abs(nTargetMod)) + " = " + IntToString(nTargetRoll + nTargetMod) +
" vs. DC: " + IntToString(nSelfRoll + nDC) + ")" + C_END;
switch (GetPCFilter(oTarget, PCFILTER_CHECK)) {
case 0: DelayCommand(fDelay, SendMessageToPC(oTarget, sCheck)); break;
case 1: DelayCommand(fDelay, SendSystemMessage(oTarget, sCheck)); break;
case 2: DelayCommand(fDelay, FloatingTextStringOnCreature(sCheck, oTarget, FALSE)); break;
}
}
}
return OBJECT_INVALID;
}
void DoLeechHit (object oSelf, object oTarget, int nDice=35) {
if (GetObjectType(oTarget) != OBJECT_TYPE_CREATURE ||
GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD ||
GetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT ||
GetLevelByclass(class_TYPE_PALEMASTER, oTarget) >= 20)
return;
int nMax = GetCurrentHitPoints(oTarget) + 10;
int nImm = GetDamageImmunity(oTarget, DAMAGE_TYPE_NEGATIVE);
if (nImm >= 100 || GetPlotFlag(oTarget))
return;
int nHeal, nDamage = d6(nDice);
if ((nHeal = (nDamage * (100 - nImm)) / 100) > nMax)
nHeal = nMax;
effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_NEGATIVE);
ApplyVisualToObject(VFX_IMP_NEGATIVE_ENERGY, oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
if (nHeal > 0 && GetCurrentHitPoints(oSelf) < 9999) {
ApplyVisualToObject(CEPVFX_IMP_HEALING_M_RED, oSelf);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ExtraordinaryEffect(EffectTemporaryHitpoints(nHeal)), OBJECT_SELF);
}
}
void DoMaul (object oTarget, int nDiscDC, int nStrDC, string sMessage, int nDamDice=6,
int nDamType=DAMAGE_TYPE_SLASHING, int nDamPower=DAMAGE_POWER_NORMAL, int nDamVuln=0) {
float fDelay = 0.1;
effect eDam, eVuln = ExtraordinaryEffect(EffectDamageImmunityDecrease(nDamType, nDamVuln));
if (TouchAttackMelee(oTarget, FALSE) > 0) {
do {
if (nDamVuln > 0)
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eVuln, oTarget);
eDam = EffectDamage(d20(nDamDice), nDamType, nDamPower);
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
fDelay += 0.01;
nDiscDC -= 10;
} while (nDiscDC > 50 && GetSkillCheckResult(SKILL_DISCIPLINE, oTarget, nDiscDC) <= 0);
if (nStrDC > 0 && GetAbilityCheckResult(ABILITY_STRENGTH, oTarget, nStrDC) <= 0)
ApplyKnockdown(oTarget, 4, sMessage);
}
}
void DoSlag (object oSelf, object oTarget, string sMessage, string sDesc="", int nACLimit=0) {
if (!GetIsObjectValid(oTarget) || !GetIsPC(oTarget))
return;
if (nACLimit)
SetLocalInt(oSelf, "RuinACLimit", nACLimit);
SetLocalInt(oSelf, "RuinSlag", -1);
SetLocalObject(oSelf, "RuinTarget", oTarget);
SetLocalString(oSelf, "RuinMessage", sMessage);
SetLocalString(oSelf, "RuinDesc", sDesc);
ExecuteScript("x2_s3_ruinarmor", oSelf);
DeleteLocalObject(oSelf, "RuinTarget");
}
int DoRadiusKnockdown (object oSelf, float fRadius, int nCheckType, int nCheckParam,
int nRounds=3, string sMessage="", int bIgnore=TRUE, int bEx=TRUE,
int nSpellId=-1, int nTumbleDC=120, int nEffectCallback=0,
float fBaseDelay=0.0, int nTargetMask=OBJECT_TYPE_CREATURE,
int nArmorModifier=0, int nTouchAttack=FALSE) {
int nCheckDC, nTouch, nTargets = 0;
float fDelay;
object oTarget;
location lSelf = GetLocation(oSelf);
nCheckType |= 0x40000000;
for (oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lSelf, TRUE, nTargetMask);
GetIsObjectValid(oTarget);
oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lSelf, TRUE, nTargetMask)) {
if (GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT) {
if (!GetLocalInt(oTarget, "NoAoEDispel"))
DestroyObject(oTarget);
continue;
}
if (nTouchAttack && (nTouch = TouchAttackMelee(oTarget, FALSE)) < 1)
continue;
if (fDelay < 0.0)
fDelay = -fBaseDelay + (IntToFloat(Random(11) - 5) * 0.1);
else
fDelay = fBaseDelay + (GetDistanceBetween(oSelf, oTarget) / 20.0);
if (nArmorModifier != 0)
nCheckDC = nCheckParam + ((GetArmorACBase(oTarget) * nArmorModifier) / 10);
else
nCheckDC = nCheckParam;
if (nTouch == 2)
nCheckDC += nTouchAttack;
if (GetIsTarget(oTarget, TARGET_TYPE_DEFAULT, oSelf) &&
!GetPlotFlag(oTarget) &&
!GetAttackCheckResult(oTarget, nCheckType, nCheckDC, oSelf, fDelay)) {
DelayCommand(fDelay, ApplyKnockdown(oTarget, nRounds, sMessage, bIgnore, bEx, nSpellId, nTumbleDC));
if (nEffectCallback > 0)
DelayCommand(fDelay + 0.01, AttackEffectCallback(nEffectCallback, oSelf, oTarget));
}
nTargets++;
}
return nTargets;
}
void DoSingleKnockdown (object oSelf, object oTarget, int nCheckType, int nCheckParam,
int nRounds=3, string sMessage="", int bIgnore=TRUE, int bEx=TRUE,
int nSpellId=-1, int nTumbleDC=120, int nEffectCallback=0) {
location lSelf = GetLocation(oSelf);
nCheckType |= 0x40000000;
if (GetIsTarget(oTarget, TARGET_TYPE_DEFAULT, oSelf) &&
!GetAttackCheckResult(oTarget, nCheckType, nCheckParam, oSelf, 0.0)) {
ApplyKnockdown(oTarget, nRounds, sMessage, bIgnore, bEx, nSpellId, nTumbleDC);
if (nEffectCallback > 0)
AttackEffectCallback(nEffectCallback, oSelf, oTarget);
}
}
void AttackNearest (object oSelf=OBJECT_SELF, float fDelay=1.0) {
object oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSelf, 1,
CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
if (GetIsObjectValid(oNearest)) {
DelayCommand(fDelay, ActionAttack(oNearest));
} else {
oNearest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oSelf, 1,
CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, CREATURE_TYPE_IS_ALIVE, TRUE);
if (GetIsObjectValid(oNearest))
DelayCommand(fDelay, ActionAttack(oNearest));
}
}
void DestroyBlades (location lTarget, float fRadius=RADIUS_SIZE_LARGE) {
effect eVis = EffectVisualEffect(VFX_IMP_DISPEL);
object oTarget;
for (oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget);
GetIsObjectValid(oTarget);
oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lTarget)) {
if (GetResRef(oTarget) == "x2_s_bblade") {
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DISPEL), GetLocation(oTarget));
DelayCommand(0.0, SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_MORDENKAINENS_DISJUNCTION)));
}
}
}
Modifié par FunkySwerve, 08 novembre 2010 - 10:38 .