int PRCDoRangedTouchAttack(object oTarget, int nDisplayFeedback = TRUE, object oCaster = OBJECT_SELF, int nAttackBonus = 0); int PRCDoMeleeTouchAttack(object oTarget, int nDisplayFeedback = TRUE, object oCaster = OBJECT_SELF, int nAttackBonus = 0); //#include "prc_inc_sneak" #include "prc_inc_combat" //#include "prc_inc_template" int PRCDoRangedTouchAttack(object oTarget, int nDisplayFeedback = TRUE, object oCaster = OBJECT_SELF, int nAttackBonus = 0) { if(GetLocalInt(oTarget, "Dymond_Deflect")) { DeleteLocalInt(oTarget, "Dymond_Deflect"); return FALSE; } if(GetLocalInt(oCaster, "AttackHasHit")) return GetLocalInt(oCaster, "AttackHasHit"); string sCacheName = "AttackHasHit_"+ObjectToString(oTarget); if(GetLocalInt(oCaster, sCacheName)) return GetLocalInt(oCaster, sCacheName); if(GetPersistantLocalInt(oCaster, "template_102")) // TEMPLATE_DEMILICH nAttackBonus += GetHitDice(oCaster); if(GetHasFeat(FEAT_SHIELD_WARD, oTarget)) { int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) nAttackBonus -= GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); } else if(GetHasFeat(FEAT_PARRYING_SHIELD, oTarget)) // Yes, these two are mostly identical { int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) nAttackBonus -= GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); } int nResult = GetAttackRoll(oTarget,oCaster,OBJECT_INVALID,0,nAttackBonus,0,nDisplayFeedback,0.0,TOUCH_ATTACK_RANGED_SPELL); //Ranged Recall only applies on misses, need a swift action if (GetHasFeat(FEAT_RANGED_RECALL, oCaster) && nResult == 0) { int nRecall = GetLocalInt(oCaster, "RangedRecall"); // Only get three uses a day if (3 > nRecall) { if (TakeSwiftAction(oCaster)) { SetLocalInt(oCaster, "RangedRecall", nRecall+1); // Reroll with a -5 penalty nResult = GetAttackRoll(oTarget,oCaster,OBJECT_INVALID,0,nAttackBonus-5,0,nDisplayFeedback,0.0,TOUCH_ATTACK_MELEE_SPELL); } } } SetLocalInt(oCaster, sCacheName, nResult); DelayCommand(1.0, DeleteLocalInt(oCaster, sCacheName)); return nResult; } int PRCDoMeleeTouchAttack(object oTarget, int nDisplayFeedback = TRUE, object oCaster = OBJECT_SELF, int nAttackBonus = 0) { if(GetLocalInt(oCaster, "AttackHasHit")) return GetLocalInt(oCaster, "AttackHasHit"); string sCacheName = "AttackHasHit_"+ObjectToString(oTarget); if(GetLocalInt(oCaster, sCacheName)) return GetLocalInt(oCaster, sCacheName); if(GetPersistantLocalInt(oCaster, "template_102")) // TEMPLATE_DEMILICH nAttackBonus += GetHitDice(oCaster); if(GetHasFeat(FEAT_SHIELD_WARD, oTarget)) { int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) nAttackBonus -= GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); } else if(GetHasFeat(FEAT_PARRYING_SHIELD, oTarget)) // Yes, these two are mostly identical { int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) nAttackBonus -= GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)); } int nResult = GetAttackRoll(oTarget,oCaster,OBJECT_INVALID,0,nAttackBonus,0,nDisplayFeedback,0.0,TOUCH_ATTACK_MELEE_SPELL); SetLocalInt(oCaster, sCacheName, nResult); DelayCommand(1.0, DeleteLocalInt(oCaster, sCacheName)); return nResult; } // return sneak attack damage for a spell // requires caster, target, and spell damage type int SpellSneakAttackDamage(object oCaster, object oTarget) { if (GetLocalInt(oCaster, "NoSpellSneak")) return 0; int numDice = GetTotalSneakAttackDice(oCaster); if(numDice != 0 && GetCanSneakAttack(oTarget, oCaster) ) { FloatingTextStringOnCreature("*Sneak Attack Spell*", oCaster, TRUE); return GetSneakAttackDamage(numDice); } else { return 0; } } //Applies damage from touch attacks, // returns result of attack roll // // object oCaster, the attacker // object oTarget, the victim // int iAttackRoll, the result of a touch // attack roll, 1 for hit, 2 for // critical hit // int iDamage, the normal amount of damage done // int iDamageType, the damage type // int iDamageType2, the 2nd damage type // if 2 types of damage are applied int ApplyTouchAttackDamage(object oCaster, object oTarget, int iAttackRoll, int iDamage, int iDamageType, int iDamageType2 = -1) { iDamage *= iAttackRoll; if(iDamage) { if(!GetPRCSwitch(PRC_SPELL_SNEAK_DISABLE)) iDamage += SpellSneakAttackDamage(oCaster, oTarget); effect eDamage; if(iDamageType2 == -1) eDamage = PRCEffectDamage(oTarget, iDamage, iDamageType); else { //for touch attacks with 2 damage types, 1st damage type has priority eDamage = PRCEffectDamage(oTarget, iDamage / 2, iDamageType); eDamage = EffectLinkEffects(eDamage, EffectDamage(iDamage - (iDamage / 2), iDamageType2)); } ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget); } return iAttackRoll; } //routes to DoRacialSLA, but checks that the ray hits first //not sure how this will work if the spell does multiple touch attack, hopefully that shouldnt apply //this is Base DC, not total DC. SLAs are still spells, so spell focus should still apply. void DoSpellRay(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0) { int nAttack = PRCDoRangedTouchAttack(PRCGetSpellTargetObject()); if(nAttack) { ActionDoCommand(SetLocalInt(OBJECT_SELF, "AttackHasHit", nAttack)); //preserve crits if(DEBUG) DoDebug("Spell DC passed to DoSpellRay: " + IntToString(nTotalDC)); DoRacialSLA(nSpellID, nCasterlevel, nTotalDC, TRUE); ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "AttackHasHit")); } } //routes to DoRacialSLA, but checks that the rouch hits first //not sure how this will work if the spell does multiple touch attack, hopefully that shouldnt apply //this is Base DC, not total DC. SLAs are still spells, so spell focus should still apply. void DoSpellMeleeTouch(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0) { int nAttack = PRCDoMeleeTouchAttack(PRCGetSpellTargetObject()); if(nAttack) { ActionDoCommand(SetLocalInt(OBJECT_SELF, "AttackHasHit", nAttack)); //preserve crits DoRacialSLA(nSpellID, nCasterlevel, nTotalDC); ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "AttackHasHit")); } }