//:://///////////////////////////////////////////// //:: Combat Maneuver include: //:: prc_inc_combmove //:://///////////////////////////////////////////// /** @file Defines various functions and other stuff that do something related to the combat maneuvers Things: Grapple Trip Bullrush Charge Overrun Disarm @author Stratovarius @date Created - 2008.4.20 */ //::////////////////////////////////////////////// //::////////////////////////////////////////////// ////////////////////////////////////////////////// /* Constants */ ////////////////////////////////////////////////// const int GRAPPLE_ATTACK = 1; const int GRAPPLE_OPPONENT_WEAPON = 2; const int GRAPPLE_ESCAPE = 3; const int GRAPPLE_TOB_CRUSHING = 4; const int GRAPPLE_DAMAGE = 5; const int GRAPPLE_PIN = 6; const int DEBUG_COMBAT_MOVE = FALSE; const int COMBAT_MOVE_GRAPPLE = 1; const int COMBAT_MOVE_BULLRUSH = 2; const int COMBAT_MOVE_OVERRUN = 3; const int COMBAT_MOVE_TRIP = 4; const int COMBAT_MOVE_DISARM = 5; const int COMBAT_MOVE_SHIELD_BASH = 6; ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// /** * Returns the total bonus to checks for chosen combat move * * @param oPC The PC * @param CombatMove The combat move to check * @param nDefender Do the benefits apply when defending only? * @param nAttacker Do the benefits apply when attacking only? * @return Total bonus */ int GetCombatMoveCheckBonus(object oPC, int nCombatMove, int nDefender = FALSE, int nAttacker = FALSE); /** * Marks a PC is charging for a round * * @param oPC The PC */ void SetIsCharging(object oPC); /** * Get whether a PC is charging for a round * * @param oPC The PC * @return TRUE or FALSE */ int GetIsCharging(object oPC); /** * This will do a complete PnP charge attack * Only call EITHER Attack OR Bull Rush * * @param oPC The PC * @param oTarget The Target * @param nDoAttack Do an attack at the end of a charge or not * @param nGenerateAoO Does the movement generate an AoO * @param nDamage A damage bonus on the charge * @param nDamageType Damage type of the bonus. * @param nBullRush Do a Bull Rush at the end of a charge * @param nExtraBonus An extra bonus to grant the PC on the Bull rush * @param nBullAoO Does the bull rush attempt generate an AoO * @param nMustFollow Does the Bull rush require the pushing PC to follow the target * @param nAttack Bonus to the attack roll // I forgot to add it before, I'm an idiot ok? * @param nPounce FALSE for normal behaviour, TRUE to do a full attack at the end of a charge // Same comment as above * * @return TRUE if the attack or Bull rush hits, else FALSE */ void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO = TRUE, int nDamage = 0, int nDamageType = -1, int nBullRush = FALSE, int nExtraBonus = 0, int nBullAoO = TRUE, int nMustFollow = TRUE, int nAttack = 0, int nPounce = FALSE); /** * This will do a complete PnP Bull rush * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nGenerateAoO Does the Bull rush attempt generate an AoO * @param nMustFollow Does the Bull rush require the pushing PC to follow the target * @param nNoMove PC does not need to move to the target, used for spells * @param nAbility Override the PC's Strength score with something else * * @return TRUE if the Bull rush succeeds, else FALSE */ void DoBullRush(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nMustFollow = TRUE, int nNoMove = FALSE, int nAbility = 0); /** * This will do a complete PnP Trip * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nGenerateAoO Does the Trip attempt generate an AoO * @param nCounterTrip Can the target attempt a counter trip if you fail * @param nSkipTouch Skip the melee touch attack or not * @param nAbi This overrides the PC's ability modifier with the input value * * @return TRUE if the Trip succeeds, else FALSE * It sets a local int known as TripDifference that is the amount you succeeded or failed by. */ int DoTrip(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nCounterTrip = TRUE, int nSkipTouch = FALSE, int nAbi = 0); /** * Will take an int and transform it into one of the DAMAGE_BONUS constants (From 1 to 20). * * @param nCheck Int to convert * @return DAMAGE_BONUS_1 to DAMAGE_BONUS_20 */ int GetIntToDamage(int nCheck); /** * This will do a complete PnP Grapple * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nGenerateAoO Does the Grapple attempt generate an AoO * @param nSkipTouch Skip the melee touch attack or not * * @return TRUE if the Grapple succeeds, else FALSE */ int DoGrapple(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nSkipTouch = FALSE); /** * Marks a target as grappled. * * @param oTarget The Target */ void SetGrapple(object oTarget); /** * Returns true or false if the creature is grappled. * * @param oTarget Person to check * * @return TRUE or FALSE */ int GetGrapple(object oTarget); /** * Saves the grapple target for the PC * * @param oPC The PC * @param oTarget The Target */ void SetGrappleTarget(object oPC, object oTarget); /** * Returns the grapple target for the PC * * @param oPC The PC */ object GetGrappleTarget(object oPC); /** * Marks a target as pinned. * * @param oTarget The Target */ void SetIsPinned(object oTarget); /** * Returns true or false if the creature is pinned. * * @param oTarget Person to check * * @return TRUE or FALSE */ int GetIsPinned(object oTarget); /** * Removes the Pinned condition * * @param oTarget The Target */ void BreakPin(object oTarget); /** * Ends a grapple between the two creatures * * @param oPC The PC * @param oTarget The Target */ void EndGrapple(object oPC, object oTarget); /** * The options that can be performed during a grapple. Returns success or fail of the grapple check. * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nSwitch The options to use. One of: GRAPPLE_ATTACK, GRAPPLE_OPPONENT_WEAPON, GRAPPLE_ESCAPE, GRAPPLE_TOB_CRUSHING * * To-Do - Add Grapple to Move, add Pin Target, add Pin options */ int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = -1); /** * Returns true or false if the creature's right hand weapon is light * * @param oPC Person to check * * @return TRUE or FALSE */ int GetIsLightWeapon(object oPC); /** * This will do a complete PnP Overrun. See tob_stdr_bldrrll for an example of how to use. * Overrun is part of a move action. * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nGenerateAoO Does the Overrun attempt generate an AoO * @param nAvoid Can the target avoid you * @param nCounterTrip Can the target attempt a counter if you fail * * @return TRUE if the Overrun succeeds, else FALSE * It sets a local int known as OverrunDifference that is the amount you succeeded or failed by. */ void DoOverrun(object oPC, object oTarget, location lTarget, int nGenerateAoO = TRUE, int nExtraBonus = 0, int nAvoid = TRUE, int nCounter = TRUE); /** * This will do a complete PnP Disarm * * @param oPC The PC * @param oTarget The Target * @param nExtraBonus An extra bonus to grant the PC * @param nGenerateAoO Does the attempt generate an AoO * @param nCounter Can the target attempt a counter disarm if you fail * * @return TRUE if the Disarm succeeds, else FALSE */ int DoDisarm(object oPC, object oTarget, int nExtraBonus = 0, int nGenerateAoO = TRUE, int nCounter = TRUE); // * returns the size modifier for grappling int PRCGetSizeModifier(object oCreature); /** * Does the knockback for the Tiger Blooded Tome of Battle feat. * Is here because it uses Bull Rush code. * * @param oInitiator Hitter * @param oTarget Guess what */ void TigerBlooded(object oInitiator, object oTarget); ////////////////////////////////////////////////// /* Includes */ ////////////////////////////////////////////////// #include "prc_inc_combat" #include "prc_inc_sp_tch" ////////////////////////////////////////////////// /* Internal functions */ ////////////////////////////////////////////////// void _DoBullRushKnockBack(object oTarget, object oPC, float fFeet) { // Calculate how far the creature gets pushed float fDistance = FeetToMeters(fFeet); // Determine if they hit a wall on the way location lPC = GetLocation(oPC); location lTargetOrigin = GetLocation(oTarget); vector vAngle = AngleToVector(GetRelativeAngleBetweenLocations(lPC, lTargetOrigin)); vector vTargetOrigin = GetPosition(oTarget); vector vTarget = vTargetOrigin + (vAngle * fDistance); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("Initialized _DoBullRushKnockBack", oPC, FALSE); if(!LineOfSightVector(vTargetOrigin, vTarget)) { // Hit a wall, binary search for the wall float fEpsilon = 1.0f; // Search precision float fLowerBound = 0.0f; // The lower search bound, initialise to 0 float fUpperBound = fDistance; // The upper search bound, initialise to the initial distance fDistance = fDistance / 2; // The search position, set to middle of the range if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoBullRushKnockBack: If Statement", oPC, FALSE); do{ // Create test vector for this iteration vTarget = vTargetOrigin + (vAngle * fDistance); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoBullRushKnockBack: DO Loop", oPC, FALSE); // Determine which bound to move. if(LineOfSightVector(vTargetOrigin, vTarget)) fLowerBound = fDistance; else fUpperBound = fDistance; // Get the new middle point fDistance = (fUpperBound + fLowerBound) / 2; }while(fabs(fUpperBound - fLowerBound) > fEpsilon); } // Create the final target vector vTarget = vTargetOrigin + (vAngle * fDistance); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoBullRushKnockBack: Final Vector", oPC, FALSE); // Move the target location lTargetDestination = Location(GetArea(oTarget), vTarget, GetFacing(oTarget)); AssignCommand(oTarget, ClearAllActions(TRUE)); AssignCommand(oTarget, JumpToLocation(lTargetDestination)); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoBullRushKnockBack: Jumped", oPC, FALSE); } int _DoGrappleCheck(object oPC, object oTarget, int nExtraBonus, int nSwitch = -1) { // The basic modifiers int nPCBAB = GetBaseAttackBonus(oPC); int nTargetBAB = GetBaseAttackBonus(oTarget); int nPCStr = GetAbilityModifier(ABILITY_STRENGTH, oPC); int nTargetStr = GetAbilityModifier(ABILITY_STRENGTH, oTarget); int nPCBonus = PRCGetSizeModifier(oPC); int nTargetBonus = PRCGetSizeModifier(oTarget); // Other ability bonuses nPCBonus += GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_GRAPPLE, FALSE, TRUE); nTargetBonus += GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_GRAPPLE, TRUE); // Extra bonus nPCBonus += nExtraBonus; if (GetHasFeat(FEAT_IMPROVED_GRAPPLE, oPC)) nPCBonus += 4; if (GetHasFeat(FEAT_IMPROVED_GRAPPLE, oTarget)) nTargetBonus += 4; nTargetBonus += GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oTarget); //Only applies on defense if (nSwitch == GRAPPLE_ESCAPE) nPCBonus += GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oPC); // And when escaping //cant grapple incorporeal or ethereal things if((GetIsEthereal(oTarget) && !GetIsEthereal(oPC)) || GetIsIncorporeal(oTarget)) { FloatingTextStringOnCreature("You cannot grapple an Ethereal or Incorporeal creature",oPC, FALSE); return FALSE; } int nPCCheck = nPCBAB + nPCStr + nPCBonus + d20(); int nTargetCheck = nTargetBAB + nTargetStr + nTargetBonus + d20(); // Now roll the ability check SendMessageToPC(oPC, "PC Grapple Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (GetIsPC(oTarget)) SendMessageToPC(oTarget, "Enemy Grapple Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (nPCCheck >= nTargetCheck) { return TRUE; } // Didn't grapple successfully return FALSE; } void _DoCurlingWaveStrike(object oPC, object oTarget) { if (GetLocalInt(oPC, "CurlingWaveStrike")) return; // Escape if this has already happened location lTarget = GetLocation(oPC); int nContinue = TRUE; // Use the function to get the closest creature as a target object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); while(GetIsObjectValid(oAreaTarget) && nContinue) { // All enemies in range get a free AoO shot if(oAreaTarget != oPC && // Don't hit yourself GetIsInMeleeRange(oPC, oAreaTarget) && // They must be in melee range GetIsEnemy(oAreaTarget, oPC) && // Only enemies are valid targets oAreaTarget != oTarget) // Can't hit the same guy twice { // Once we're here, perform the second trip DoTrip(oPC, oAreaTarget, 0); nContinue = FALSE; // Break the loop } //Select the next target within the spell shape. oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); } // Stop this being an eternal loop SetLocalInt(oPC, "CurlingWaveStrikeLoop", TRUE); DelayCommand(0.5, DeleteLocalInt(oPC, "CurlingWaveStrikeLoop")); // Once a round SetLocalInt(oPC, "CurlingWaveStrikeRound", TRUE); DelayCommand(6.0, DeleteLocalInt(oPC, "CurlingWaveStrikeRound")); } // Returns 0 on a fail // Returns 1 on a successful overrun // Returns 2 on an avoid void _DoOverrunCheck(object oPC, object oTarget, location lTarget, int nGenerateAoO = TRUE, int nExtraBonus = 0, int nAvoid = TRUE, int nCounter = TRUE) { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoOverrunCheck: Initialized", oPC, FALSE); // Stops loops if (GetLocalInt(oPC, "Overrun") != 2 && !GetLocalInt(oPC, "BoulderRoll")) return; if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoOverrunCheck: Loop Protect", oPC, FALSE); if(!nGenerateAoO) { // Huge bonus to tumble to prevent AoOs from movement ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSkillIncrease(SKILL_TUMBLE, 50), oPC, 6.0); } // The basic modifiers int nSucceed = FALSE; int nPCStat, nTargetStat; // Use the higher of the two mods if (GetAbilityModifier(ABILITY_STRENGTH, oPC) > GetAbilityModifier(ABILITY_DEXTERITY, oPC)) nPCStat = GetAbilityModifier(ABILITY_STRENGTH, oPC) + GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_OVERRUN, FALSE, TRUE); else nPCStat = GetAbilityModifier(ABILITY_DEXTERITY, oPC) + GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_OVERRUN, FALSE, TRUE); // Use the higher of the two mods if (GetAbilityModifier(ABILITY_STRENGTH, oTarget) > GetAbilityModifier(ABILITY_DEXTERITY, oTarget)) nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_OVERRUN, TRUE); else nTargetStat = GetAbilityModifier(ABILITY_DEXTERITY, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_OVERRUN, TRUE); // Get mods for size int nPCBonus = PRCGetSizeModifier(oPC); int nTargetBonus = PRCGetSizeModifier(oTarget); //Warblade Battle Skill bonus if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC) >= 11) { nPCBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Overrun bonus (attacker)"); } if (GetLevelByClass(CLASS_TYPE_WARBLADE, oTarget) >= 11) { nTargetBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oTarget); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Overrun bonus (defender)"); } if (GetHasFeat(FEAT_IMPROVED_OVERRUN, oPC)) //Can't avoid an overrun now { nPCBonus += 4; nAvoid = FALSE; } if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoOverrunCheck: Modifiers Complete", oPC, FALSE); // Do the AoO for an overrun attempt if (nGenerateAoO) { // Perform the Attack effect eNone; DelayCommand(0.0, PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Attack of Opportunity Hit", "Attack of Opportunity Miss")); FloatingTextStringOnCreature(GetName(oTarget)+" Overrun Attack of Opportunity", oPC, FALSE); } int nPCCheck = nPCStat + nPCBonus + nExtraBonus + d20(); int nTargetCheck = nTargetStat + nTargetBonus + d20(); // The target has the option to avoid. Smaller targets will avoid if allowed. if (nPCBonus > nTargetBonus && nAvoid) { FloatingTextStringOnCreature(GetName(oTarget) + " has successfully avoided you", oPC, FALSE); // You didn't knock down the target, but neither did it stop you. Keep on chugging. SetLocalInt(oPC, "Overrun", 2); AssignCommand(oPC, ActionForceMoveToLocation(lTarget, TRUE)); return; } // Now roll the ability check SendMessageToPC(oPC, "Overrun Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (nPCCheck >= nTargetCheck) { FloatingTextStringOnCreature("You have succeeded on your Overrun attempt",oPC, FALSE); // Knock em down ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oTarget, 6.0); nSucceed = TRUE; SetLocalInt(oPC, "OverrunDifference", nPCCheck - nTargetCheck); DeleteLocalInt(oPC, "OverrunDifference"); effect eNone; if (GetHasFeat(FEAT_CENTAUR_TRAMPLE, oPC)) PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Centaur Trample Hit", "Centaur Trample Miss", FALSE, GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC)); AssignCommand(oPC, ActionForceMoveToLocation(lTarget, TRUE)); DelayCommand(7.05, AssignCommand(oTarget, ClearAllActions(TRUE))); DelayCommand(7.05, AssignCommand(oTarget, ActionAttack(oPC))); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoOverrunCheck: oTarget Assign Command "+GetName(oTarget), oPC, FALSE); } else // If you fail, enemy gets a counter Overrun attempt, using Strength { nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_OVERRUN, FALSE, TRUE); FloatingTextStringOnCreature("You have failed on your Overrun attempt",oPC, FALSE); AssignCommand(oPC, ClearAllActions(TRUE)); AssignCommand(oPC, JumpToLocation(GetLocation(oTarget))); // Roll counter Overrun attempt nTargetCheck = nTargetStat + nTargetBonus + d20(); nPCCheck = nPCStat + nPCBonus + d20(); // If counters aren't allowed, don't knock em down // Its down here to allow the text message to go through SendMessageToPC(oPC, "Enemy Overrun Counter Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (nTargetCheck >= nPCCheck && nCounter) { // Knock em down ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oPC, 6.0); } SetLocalInt(oPC, "OverrunDifference", nTargetCheck - nPCCheck); DelayCommand(2.0, DeleteLocalInt(oPC, "OverrunDifference")); } if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("_DoOverrunCheck: Ending, nSucceed "+IntToString(nSucceed), oPC, FALSE); SetLocalInt(oPC, "Overrun", nSucceed); } int _ChargeDamage(object oPC) { int nDam; int nSize = PRCGetSizeModifier(oPC); if (GetHasFeat(FEAT_GREATER_POWERFUL_CHARGE, oPC)) nSize += 4; if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 0) nDam += d8(); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 4) nDam += d6(2); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 8) nDam += d6(3); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 12) nDam += d6(4); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 16) nDam += d6(6); if (GetHasFeat(FEAT_RHINO_TRIBE_CHARGE, oPC)) nDam += d6(2); // Using a natural attack only if (GetHasSpellEffect(VESTIGE_AMON, oPC) && GetLocalInt(oPC, "AmonRam") && !GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC))) nDam += d8(); nDam += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_CHARGE); // Doesn't appear to be added to charging normally, so brute forcing it here nDam += GetEssentiaInvested(oPC, MELD_INCANDESCENT_STRIKE); return nDam; } int _ChargeAttack(object oPC, object oTarget, int nAtk) { nAtk += 2; // Add to whatever the bonus was before int nAC = 2; if(GetHasFeat(FEAT_FURIOUS_CHARGE, oPC)) nAtk += 2; if(GetHasFeat(FEAT_RECKLESS_CHARGE, oPC)) { nAtk += 2; nAC += 2; } if(GetHasFeat(FEAT_GREAT_STAG_BERSERKER, oPC)) // Yes, it's the same feat as Reckless Charge { nAtk += 2; nAC += 2; } if(GetHasFeat(FEAT_SIDESTEP_CHARGE, oTarget)) nAtk -= 4; if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) >= 2) nAtk += 1; if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) >= 4) nAtk += 1; effect eCharge = EffectLinkEffects(EffectACDecrease(nAC), EffectMovementSpeedIncrease(99)); eCharge = ExtraordinaryEffect(eCharge); SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCharge, oPC, 6.0); nAtk += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_CHARGE); // Done this way because otherwise the attack bonus isn't used properly return nAtk; } void _SuperiorBullRush(object oPC, object oTarget) { int nDam = d6(); if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) >= 4) nDam = d8(); nDam += GetAbilityModifier(ABILITY_STRENGTH, oPC); if (GetIsCharging(oPC)) { int nSize = PRCGetSizeModifier(oPC); if (GetHasFeat(FEAT_GREATER_POWERFUL_CHARGE, oPC)) nSize += 4; if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 0) nDam += d8(); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 4) nDam += d6(2); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 8) nDam += d6(3); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 12) nDam += d6(4); else if(GetHasFeat(FEAT_POWERFUL_CHARGE, oPC) && nSize == 16) nDam += d6(6); } effect eDeath = EffectDamage(nDam, DAMAGE_TYPE_PIERCING); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget); FloatingTextStringOnCreature("Superior Bull Rush Hit", oPC, FALSE); } void _DoBullrushCheck(object oPC, object oTarget, int nExtraBonus, int nMustFollow = TRUE, int nAbility = 0) { // The basic modifiers int nPCStr = GetAbilityModifier(ABILITY_STRENGTH, oPC); int nTargetStr = GetAbilityModifier(ABILITY_STRENGTH, oTarget); if (nAbility > 0) nPCStr = nAbility; // Use the override if it exists int nPCBonus = PRCGetSizeModifier(oPC); int nTargetBonus = PRCGetSizeModifier(oTarget); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: Initialized", oPC, FALSE); //Warblade Battle Skill bonus if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC) >= 11) { nPCBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Bull Rush bonus (attacker)"); } if (GetLevelByClass(CLASS_TYPE_WARBLADE, oTarget) >= 11) { nTargetBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oTarget); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Bull Rush bonus (defender)"); } if (GetHasFeat(FEAT_IMPROVED_BULLRUSH, oPC)) nPCBonus += 4; effect eNone; // Get a +2 bonus for charging during a bullrush if (GetIsCharging(oPC)) nPCBonus += 2; // Other ability bonuses nPCBonus += GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_BULLRUSH, FALSE, TRUE); nTargetBonus += GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_BULLRUSH, TRUE); // Extra bonus nPCBonus += nExtraBonus; if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: End of Bonuses", oPC, FALSE); if (GetLocalInt(oPC, "SlingDireWind_BullRush")) //Special roll { nPCStr = 15; nPCBonus = 0; nMustFollow = FALSE; } else if (GetLocalInt(oPC, "RonoveBullRush")) //Special roll { nPCStr = GetLocalInt(oPC, "RonoveBullRush"); nPCBonus = 0; nMustFollow = FALSE; } // Ability check int nPCCheck = nPCStr + nPCBonus + d20(); int nTargetCheck = nTargetStr + nTargetBonus + d20(); SendMessageToPC(oPC, "Bull Rush Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); // Now roll the ability check if (nPCCheck >= nTargetCheck) { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: Successful Hit", oPC, FALSE); // Knock them back 5 feet float fFeet = 5.0; // For every 5 points greater, knock back an additional 5 feet. fFeet += 5.0 * ((nPCCheck - nTargetCheck) / 5); // This weapon of legacy adds 5 feet to a successful bull rush if(GetLocalInt(oPC, "Caladbolg_Bullrush")) fFeet += 5.0; // Max pushback from this one is 5.0 if (GetLocalInt(oPC, "SlingDireWind_BullRush")) fFeet = 5.0; SetLocalInt(oPC, "Bullrush", TRUE); DelayCommand(3.0, DeleteLocalInt(oPC, "Bullrush")); // Shedu Crown negates the knockback if (GetHasSpellEffect(18767, oTarget)) fFeet = 0.0; _DoBullRushKnockBack(oTarget, oPC, fFeet); if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC)) _SuperiorBullRush(oPC, oTarget); // If the PC has to keep pushing to knock back, move the PC along if (nMustFollow) { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: Following", oPC, FALSE); AssignCommand(oPC, ClearAllActions(TRUE)); AssignCommand(oPC, JumpToLocation(GetLocation(oTarget))); } if(GetHasFeat(FEAT_RAMPAGING_BULL_RUSH, oPC) && GetHasSpellEffect(SPELLABILITY_BARBARIAN_RAGE, oPC)) DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, RoundsToSeconds(1))); } else FloatingTextStringOnCreature("You have failed your Bull Rush Attempt",oPC, FALSE); // Let people know if we made the hit or not if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: Exit", oPC, FALSE); } int _CountPinRounds(object oTarget) { int nPin = GetLocalInt(oTarget, "PinnedRounds"); SetLocalInt(oTarget, "PinnedRounds", nPin+1); return nPin+1; } void _DoReapingMauler(object oPC, object oTarget, int nRounds) { int nClass = GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC); if (3 > nClass) return; if (!GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) { if (nRounds >= 3 && nClass >= 5) // Devastating Grapple { int nDC = 15 + GetAbilityModifier(ABILITY_WISDOM, oPC); if(!FortitudeSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oPC)) { FloatingTextStringOnCreature("Devastating Grapple Success", oPC, FALSE); effect eDeath = EffectDamage(9999, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget); } } else { int nDC = 10 + nClass + GetAbilityModifier(ABILITY_WISDOM, oPC); if(!FortitudeSave(oTarget, nDC, SAVING_THROW_TYPE_NONE, oPC)) { SetLocalInt(oTarget, "UnconsciousGrapple", TRUE); // Unconscious effects effect eUncon = EffectLinkEffects(EffectStunned(), EffectVisualEffect(VFX_DUR_MIND_AFFECTING_DISABLED)); eUncon = EffectLinkEffects(eUncon, EffectKnockdown()); float fDur = d3() * 6.0; ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eUncon), oTarget, fDur); FloatingTextStringOnCreature("Sleeper Lock Success", oPC, FALSE); DelayCommand(fDur, DeleteLocalInt(oTarget, "UnconsciousGrapple")); } } } } void _PostCharge(object oPC, object oTarget) { int nSpellId = PRCGetSpellId(); if (DEBUG) DoDebug("_PostCharge nSpellId: "+IntToString(nSpellId)); effect eNone; int nSucceed = GetLocalInt(oTarget, "PRCCombat_StruckByAttack"); if(GetHasFeat(FEAT_SIDESTEP_CHARGE, oTarget) && nSucceed == FALSE) DelayCommand(0.0, PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, -1, "Sidestep Charge Hit", "Sidestep Charge Miss")); //Gorebrute Elite Knockdown if(GetLocalInt(oPC, "ShifterGore") && GetHasFeat(FEAT_GOREBRUTE_ELITE, oPC) && nSucceed) { //Knockdown check int nEnemyStr = d20() + GetAbilityModifier(ABILITY_STRENGTH, oTarget); int nYourStr = d20() + GetAbilityModifier(ABILITY_STRENGTH, oPC); SendMessageToPC(oPC, "Opposed Knockdown Check: Rolled " + IntToString(nYourStr) + " vs " + IntToString(nEnemyStr)); SendMessageToPC(oTarget, "Opposed Knockdown Check: Rolled " + IntToString(nEnemyStr) + " vs " + IntToString(nYourStr)); if(nYourStr > nEnemyStr) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0); } if (nSpellId == MOVE_DS_DOOM_CHARGE && nSucceed) { effect eLink = EffectVisualEffect(VFX_DUR_ROOTED_TO_SPOT); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_BLUDGEONING, 10)); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_PIERCING, 10)); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_SLASHING, 10)); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 6.0); } else if (nSpellId == MOVE_DS_LAW_BEARER && nSucceed) { effect eLink = EffectVisualEffect(VFX_DUR_ROOTED_TO_SPOT); eLink = EffectLinkEffects(eLink, EffectACIncrease(5)); eLink = EffectLinkEffects(eLink, EffectSavingThrowIncrease(SAVING_THROW_ALL, 5)); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 6.0); } else if (nSpellId == MOVE_DS_RADIANT_CHARGE && nSucceed) { effect eLink = EffectVisualEffect(VFX_DUR_ROOTED_TO_SPOT); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_BLUDGEONING, 10)); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_PIERCING, 10)); eLink = EffectLinkEffects(eLink, EffectDamageResistance(DAMAGE_TYPE_SLASHING, 10)); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 6.0); } else if (nSpellId == MOVE_DS_TIDE_CHAOS && nSucceed) { effect eLink = EffectLinkEffects(EffectVisualEffect(VFX_DUR_BLUR), EffectConcealment(50)); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 6.0); } else if (nSpellId == MOVE_WR_WAR_MASTERS_CHARGE && nSucceed) { ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectStunned()), oTarget, 6.0); } // Applies to all charges, Thunderstep Boots meld if (GetHasSpellEffect(MELD_THUNDERSTEP_BOOTS, oPC) && nSucceed) { int nDice = GetEssentiaInvested(oPC, MELD_STRONGHEART_VEST) + 1; ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(d4(nDice), DAMAGE_TYPE_SONIC)), oTarget); if (GetIsMeldBound(oTarget, MELD_THUNDERSTEP_BOOTS) == CHAKRA_FEET) { int nDC = GetMeldshaperDC(oPC, CLASS_TYPE_SOULBORN, MELD_STRONGHEART_VEST); if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(), oTarget, 6.0); } } // Applies to all charges, Urskan Greaves meld if (GetHasSpellEffect(MELD_URSKAN_GREAVES, oPC) && nSucceed) { int nDice = GetEssentiaInvested(oPC, MELD_URSKAN_GREAVES); if (GetIsMeldBound(oTarget, MELD_URSKAN_GREAVES) == CHAKRA_FEET) ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(d4(nDice), DAMAGE_TYPE_BLUDGEONING)), oTarget); } } void _DoTrampleDamage(object oPC, object oTarget) { int nPCSize = PRCGetSizeModifier(oPC); int nTargetSize = PRCGetSizeModifier(oTarget); // Have to be equal to your size or smaller if (nPCSize >= nTargetSize) { int nDamage = d8(); if (nPCSize == 4) nDamage = d6(2); // Large else if (nPCSize == -4) nDamage = d6(); // Small int nDC = GetMeldshaperDC(oPC, CLASS_TYPE_SOULBORN, PRCGetSpellId()); nDamage += FloatToInt(GetAbilityModifier(ABILITY_STRENGTH, oPC) * 1.5); nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, SAVING_THROW_TYPE_NONE); if (nDamage > 0) ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING), oTarget); } } void _HeartOfFireGrapple(object oPC, object oTarget) { if (GetIsMeldBound(oTarget, MELD_HEART_OF_FIRE) == CHAKRA_WAIST) { int nEssentia = GetEssentiaInvested(oPC, MELD_HEART_OF_FIRE); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(nEssentia), DAMAGE_TYPE_FIRE), oTarget); } } int _TotemAvatar(object oPC, int nCombatMove) { int nReturn; if (GetIsMeldBound(oPC, MELD_HEART_OF_FIRE) == CHAKRA_FEET && nCombatMove != COMBAT_MOVE_GRAPPLE) nReturn = 4; if (nCombatMove == COMBAT_MOVE_GRAPPLE || nCombatMove == COMBAT_MOVE_BULLRUSH || nCombatMove == COMBAT_MOVE_OVERRUN || nCombatMove == COMBAT_MOVE_TRIP) nReturn += 4; return nReturn; } int _UrskanGreaves(object oPC) { int nReturn; if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM) nReturn = 2 + GetEssentiaInvested(oPC, MELD_URSKAN_GREAVES); return nReturn; } void _ShieldBashDamage(object oPC, object oTarget, int nRoll, int nHand, int nDamage, int nDamageType, int nType) { int nDam = d3(); if (nType == BASE_ITEM_LARGESHIELD) nDam = d4(); int nStr = GetAbilityModifier(ABILITY_STRENGTH, oPC)/2; // Default to offhand if (nHand) nStr = GetAbilityModifier(ABILITY_STRENGTH, oPC); // Onhand attack int nBash = GetLocalInt(oPC, "BashingEnchant"); if (nBash && nType == BASE_ITEM_LARGESHIELD) nDam = d8(); else if (nBash && nType == BASE_ITEM_SMALLSHIELD) nDam = d6(); nDam += nStr; nDam += nBash; // Critical hit if (nRoll == 2) { if (nType == BASE_ITEM_LARGESHIELD) nDam += d4(); else nDam += d3(); nDam += nStr; nDam += nBash; nDamage *= 2; } effect eLink = EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING); if (nDamage) eLink = EffectLinkEffects(eLink, EffectDamage(nDamage, nDamageType)); ApplyEffectToObject(DURATION_TYPE_INSTANT, ExtraordinaryEffect(eLink), oTarget); //Extra damage from Energized Shield and Lesser Energized Shield int nType = GetLocalInt(oPC, "EnShieldType"); int nD6 = GetLocalInt(oPC, "EnShieldD6"); SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nType, d6(nD6)), oTarget); } void _BariaurChargeDamage(object oPC, object oTarget, int nRoll, int nDamBonus) { int nDam = d6(2) + GetAbilityModifier(ABILITY_STRENGTH, oPC) + nDamBonus; // Onhand attack if (nRoll == 2) nDam += d6(2) + GetAbilityModifier(ABILITY_STRENGTH, oPC) + nDamBonus; ApplyEffectToObject(DURATION_TYPE_INSTANT, ExtraordinaryEffect(EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING)), oTarget); } ////////////////////////////////////////////////// /* Function definitions */ ////////////////////////////////////////////////// int GetCombatMoveCheckBonus(object oPC, int nCombatMove, int nDefender = FALSE, int nAttacker = FALSE) { int nBonus = 0; if(nCombatMove == COMBAT_MOVE_GRAPPLE) { if(GetHasSpellEffect(MOVE_SD_STONEFOOT_STANCE, oPC)) nBonus += 2; if(GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC) >= 2) nBonus += 1; if(GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC) >= 4) nBonus += 1; if(GetHasFeat(FEAT_LEGENDARY_WRESTLER, oPC)) nBonus += 10; if(GetRacialType(oPC) == RACIAL_TYPE_CHITINE) nBonus += 4; if(GetHasSpellEffect(MELD_GIRALLON_ARMS, oPC)) nBonus += (2 + GetEssentiaInvested(oPC, MELD_GIRALLON_ARMS)); // MELD_GIRALLON_ARMS if(GetLocalInt(oPC, "BullybashersGrapple")) nBonus += 4; if(GetLocalInt(oPC, "BullybashersGiant")) nBonus += 4; if(GetHasFeat(FEAT_OPEN_LESSER_CHAKRA_ARMS, oPC)) nBonus += 2; if(GetHasFeat(FEAT_ABERRANT_DEEPSPAWN, oPC)) nBonus += 2; if(GetHasFeat(FEAT_ABERRANT_LIMBS, oPC)) nBonus += 2; if(GetHasSpellEffect(POWER_GRIP_IRON, oPC)) nBonus += GetLocalInt(oPC, "Psi_GripOfIron"); } else if(nCombatMove == COMBAT_MOVE_BULLRUSH) { if(GetHasSpellEffect(MOVE_SD_STONEFOOT_STANCE, oPC)) nBonus += 2; if(GetHasSpellEffect(MOVE_SS_STEP_WIND, oPC)) nBonus += 4; if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC)) nBonus += GetAbilityModifier(ABILITY_STRENGTH, oPC); if(GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC) >= 3) nBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if(GetLocalInt(oPC, "LuckyDiceAbility")) nBonus += 1; if(GetHasSpellEffect(MELD_MAULING_GAUNTLETS, oPC)) nBonus += (2 + (2 * GetEssentiaInvested(oPC, MELD_MAULING_GAUNTLETS))); // MELD_MAULING_GAUNTLETS if(GetHasSpellEffect(MELD_SPHINX_CLAWS, oPC)) nBonus += (1 + GetEssentiaInvested(oPC, MELD_SPHINX_CLAWS)); // MELD_SPHINX_CLAWS if(GetLocalInt(oPC, "EventideCrux")) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_OVERRUN) { if(GetHasSpellEffect(MOVE_SD_STONEFOOT_STANCE, oPC)) nBonus += 2; if(GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC) >= 3) nBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if(GetLocalInt(oPC, "LuckyDiceAbility")) nBonus += 1; if(GetHasSpellEffect(MELD_MAULING_GAUNTLETS, oPC)) nBonus += (2 + (2 * GetEssentiaInvested(oPC, MELD_MAULING_GAUNTLETS))); // MELD_MAULING_GAUNTLETS if(GetHasSpellEffect(MELD_SPHINX_CLAWS, oPC)) nBonus += (1 + GetEssentiaInvested(oPC, MELD_SPHINX_CLAWS)); // MELD_SPHINX_CLAWS if(GetLocalInt(oPC, "EventideCrux")) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_TRIP) { if(GetHasSpellEffect(MOVE_SD_STONEFOOT_STANCE, oPC)) nBonus += 2; if(GetHasSpellEffect(MOVE_SS_STEP_WIND, oPC)) nBonus += 4; if(GetHasFeat(FEAT_WOLF_BERSERKER, oPC)) nBonus += 4; if(GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC) >= 3) nBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if(GetLocalInt(oPC, "LuckyDiceAbility")) nBonus += 1; if(GetHasSpellEffect(MELD_MAULING_GAUNTLETS, oPC)) nBonus += (2 + (2 * GetEssentiaInvested(oPC, MELD_MAULING_GAUNTLETS))); // MELD_MAULING_GAUNTLETS if(GetHasSpellEffect(MELD_SPHINX_CLAWS, oPC)) nBonus += (1 + GetEssentiaInvested(oPC, MELD_SPHINX_CLAWS)); // MELD_SPHINX_CLAWS if(GetLocalInt(oPC, "EventideCrux")) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_DISARM) { if(GetHasSpellEffect(MELD_BLADEMELD_CROWN, oPC)) nBonus += 4; } if (nAttacker) { if(nCombatMove == COMBAT_MOVE_GRAPPLE) { if(GetLocalInt(oPC, "Flay_Grapple")) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_BULLRUSH) { if(GetLocalInt(oPC, "Caladbolg_Bullrush")) nBonus += 4; if (GetLocalInt(oPC, "Marshal_ArtWar")) nBonus += GetLocalInt(oPC, "Marshal_ArtWar"); if (GetEssentiaInvestedFeat(oPC, FEAT_COBALT_POWER)) nBonus += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_POWER); if(GetHasFeat(FEAT_RAMPAGING_BULL_RUSH, oPC) && GetHasSpellEffect(SPELLABILITY_BARBARIAN_RAGE, oPC)) nBonus -= 4; // Yes, minus is correct } else if(nCombatMove == COMBAT_MOVE_OVERRUN) { nBonus += _UrskanGreaves(oPC); if (GetEssentiaInvestedFeat(oPC, FEAT_COBALT_POWER)) nBonus += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_POWER); } else if(nCombatMove == COMBAT_MOVE_TRIP) { if (GetEssentiaInvestedFeat(oPC, FEAT_COBALT_EXPERTISE)) nBonus += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_EXPERTISE); if (GetLocalInt(oPC, "Marshal_ArtWar")) nBonus += GetLocalInt(oPC, "Marshal_ArtWar"); } else if(nCombatMove == COMBAT_MOVE_DISARM) { if(GetLocalInt(oPC, "Caladbolg_Disarm")) nBonus += 4; if (GetLocalInt(oPC, "Marshal_ArtWar")) nBonus += GetLocalInt(oPC, "Marshal_ArtWar"); if (GetEssentiaInvestedFeat(oPC, FEAT_COBALT_EXPERTISE)) nBonus += GetEssentiaInvestedFeat(oPC, FEAT_COBALT_EXPERTISE); int IsDisarmWeap = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)); if (IsDisarmWeap == BASE_ITEM_HEAVYFLAIL || IsDisarmWeap == BASE_ITEM_LIGHTFLAIL || IsDisarmWeap == BASE_ITEM_DIREMACE || IsDisarmWeap == BASE_ITEM_WHIP || IsDisarmWeap == BASE_ITEM_NUNCHAKU) nBonus += 2; if (GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)) == BASE_ITEM_SAI) nBonus += 4; } } else if (nDefender) { if(GetHasFeat(FEAT_MOUNTAIN_STANCE, oPC)) nBonus += 2; if(GetHasSpellEffect(SPELL_UNMOVABLE, oPC)) nBonus += 20; if(GetHasFeat(FEAT_SHIELD_WARD, oPC)) { int nBase = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC)); if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD) nBonus += GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC)); } if(nCombatMove == COMBAT_MOVE_GRAPPLE) { if(GetHasSpellEffect(MOVE_SD_ROOT_MOUNTAIN, oPC)) nBonus += 10; nBonus += _TotemAvatar(oPC, nCombatMove); if(GetHasSpellEffect(MELD_BLADEMELD_WAIST, oPC)) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_BULLRUSH) { if(GetLocalInt(oPC, "Steadfast_Rooted")) nBonus += 4; if(GetHasSpellEffect(MOVE_SD_ROOT_MOUNTAIN, oPC)) nBonus += 10; if(GetHasSpellEffect(MELD_BEHIR_GORGET, oPC)) nBonus += 4; // MELD_BEHIR_GORGET if(GetHasSpellEffect(MELD_GORGON_MASK, oPC)) nBonus += (2 + GetEssentiaInvested(oPC, MELD_GORGON_MASK)); // MELD_GORGON_MASK nBonus += _TotemAvatar(oPC, nCombatMove); if(GetHasSpellEffect(MELD_BLADEMELD_WAIST, oPC)) nBonus += 4; if(GetRacialType(oPC) == RACIAL_TYPE_BARIAUR) nBonus += 4; if(GetRacialType(oPC) == RACIAL_TYPE_WILDREN) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_OVERRUN) { if(GetHasSpellEffect(MOVE_SD_ROOT_MOUNTAIN, oPC)) nBonus += 10; if(GetHasSpellEffect(MELD_GORGON_MASK, oPC)) nBonus += (2 + GetEssentiaInvested(oPC, MELD_GORGON_MASK)); // MELD_GORGON_MASK nBonus += _TotemAvatar(oPC, nCombatMove); if(GetHasSpellEffect(MELD_BLADEMELD_WAIST, oPC)) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_TRIP) { if(GetLocalInt(oPC, "Steadfast_Rooted")) nBonus += 4; if(GetHasSpellEffect(MOVE_SD_ROOT_MOUNTAIN, oPC)) nBonus += 10; if(GetHasSpellEffect(MELD_BEHIR_GORGET, oPC)) nBonus += 4; // MELD_BEHIR_GORGET if(GetHasSpellEffect(MELD_GORGON_MASK, oPC)) nBonus += (2 + GetEssentiaInvested(oPC, MELD_GORGON_MASK)); // MELD_GORGON_MASK nBonus += _TotemAvatar(oPC, nCombatMove); if(GetHasSpellEffect(MELD_BLADEMELD_WAIST, oPC)) nBonus += 4; if(GetRacialType(oPC) == RACIAL_TYPE_BARIAUR) nBonus += 4; if(GetRacialType(oPC) == RACIAL_TYPE_WILDREN) nBonus += 4; } else if(nCombatMove == COMBAT_MOVE_DISARM) { if(GetRacialType(oPC) == RACIAL_TYPE_CHITINE) nBonus += 4; } } if(DEBUG) DoDebug("GetCombatMoveCheckBonus: nBonus " + IntToString(nBonus)); return nBonus; } void SetIsCharging(object oPC) { SetLocalInt(oPC, "PCIsCharging", TRUE); // You count as having charged for the entire round DelayCommand(6.0, DeleteLocalInt(oPC, "PCIsCharging")); } int GetIsCharging(object oPC) { return GetLocalInt(oPC, "PCIsCharging"); } void DoCharge(object oPC, object oTarget, int nDoAttack = TRUE, int nGenerateAoO = TRUE, int nDamage = 0, int nDamageType = -1, int nBullRush = FALSE, int nExtraBonus = 0, int nBullAoO = TRUE, int nMustFollow = TRUE, int nAttack = 0, int nPounce = FALSE) { if(!nGenerateAoO) { // Huge bonus to tumble to prevent AoOs from movement ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSkillIncrease(SKILL_TUMBLE, 50), oPC, 6.0); } // Return value int nSucceed = FALSE; // PnP rules use feet, might as well convert it now. float fDistance = MetersToFeet(GetDistanceBetweenLocations(GetLocation(oPC), GetLocation(oTarget))); if(fDistance >= 10.0) { // Mark the PC as charging SetIsCharging(oPC); nDamage += _ChargeDamage(oPC); nAttack = _ChargeAttack(oPC, oTarget, nAttack); // This now takes into account charge feats effect eNone; // Move to the target AssignCommand(oPC, ClearAllActions()); AssignCommand(oPC, ActionMoveToObject(oTarget, TRUE)); if(nDoAttack) // Perform the Attack { // Dread Carapace Totem Bind if(GetIsIncarnumUser(oPC)) { if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM) // CHAKRA_TOTEM { location lTargetLocation = GetLocation(oPC); int nSaveDC = GetMeldshaperDC(oPC, CLASS_TYPE_TOTEMIST, MELD_DREAD_CARAPACE); // MELD_DREAD_CARAPACE object oDreadTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTargetLocation, FALSE, OBJECT_TYPE_CREATURE); while(GetIsObjectValid(oDreadTarget)) { if(GetIsEnemy(oPC, oDreadTarget)) { if(!PRCMySavingThrow(SAVING_THROW_WILL, oDreadTarget, nSaveDC, SAVING_THROW_TYPE_FEAR)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectShaken(), oDreadTarget, 6.0); } //Select the next target within the spell shape. oDreadTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTargetLocation, FALSE, OBJECT_TYPE_CREATURE); } } if (GetIsMeldBound(oPC, MELD_SPHINX_CLAWS) == CHAKRA_HANDS && !GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC))) // CHAKRA_HANDS, empty hand nPounce = TRUE; } // Flying Kick feat if(GetHasFeat(FEAT_FLYING_KICK, oPC) && (GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) == OBJECT_INVALID)) nDamage += d12(); if(GetHasFeat(FEAT_LION_TRIBE_WARRIOR, oPC) && GetIsLightWeapon(oPC) && !IPGetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC))) // No melee weapon in your off hand nPounce = TRUE; if(GetHasFeat(FEAT_SNOW_TIGER_BERSERKER, oPC) && GetIsLightWeapon(oPC)) nPounce = TRUE; if(GetHasFeat(FEAT_CATFOLK_POUNCE, oPC) && GetIsDeniedDexBonusToAC(oTarget, oPC, TRUE)) nPounce = TRUE; if(GetItemPossessedBy(oPC, "WOL_Shishio") == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) && GetLocalInt(oPC, "Shishio_Pounce")) nPounce = TRUE; if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5) nPounce = TRUE; if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT) nPounce = TRUE; if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_CHUPOCLOPS_POUNCE) nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level if(GetLocalInt(oPC, "LeadingTheCharge")) nDamage += GetLocalInt(oPC, "LeadingTheCharge"); if(nDamageType == -1) // If the damage type isn't set { object oWeap = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); nDamageType = GetWeaponDamageType(oWeap); } float fDelay = FeetToMeters(fDistance)/10; if(nPounce) // Uses instant attack in order to make sure they all go off in the alloted period of time. DelayCommand(fDelay, PerformAttackRound(oTarget, oPC, eNone, 0.0, nAttack, nDamage, nDamageType, FALSE, "Charge Hit", "Charge Miss", FALSE, FALSE, TRUE)); else if(GetLocalInt(oPC, "BariaurCharge")) // Bariaur Charge { int nRoll = GetAttackRoll(oTarget, oPC, OBJECT_INVALID, 0, 0, nAttack); _BariaurChargeDamage(oPC, oTarget, nRoll, nDamage); DeleteLocalInt(oPC, "BariaurCharge"); } else if(GetLocalInt(oPC, "ShifterGore")) //Gorebrute shifter option { string sResRef = "prc_shftr_gore_"; int nSize = PRCGetCreatureSize(oPC); if(GetHasFeat(FEAT_SHIFTER_SAVAGERY) && GetHasFeatEffect(FEAT_FRENZY, oTarget)) nSize += 2; if(nSize > CREATURE_SIZE_COLOSSAL) nSize = CREATURE_SIZE_COLOSSAL; sResRef += GetAffixForSize(nSize); object oHorns = CreateItemOnObject(sResRef, oPC); DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage + (GetHitDice(oPC) / 4), DAMAGE_TYPE_PIERCING, "Horns Hit", "Horns Miss", FALSE, oHorns)); DestroyObject(oHorns); } else if(GetLocalInt(oPC, "ShifterClaw")) //Razorclaw Elite shifted option { object oWeaponL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC); object oWeaponR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage, DAMAGE_TYPE_SLASHING, "Claw Hit", "Claw Miss", FALSE, oWeaponR, oWeaponL)); DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage, DAMAGE_TYPE_SLASHING, "Claw Hit", "Claw Miss", FALSE, oWeaponR, oWeaponL, 1)); } else { if(GetHasFeat(FEAT_TWO_WEAPON_POUNCE, oPC) && IPGetIsMeleeWeapon(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC))) { nAttack -= 2; DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage, nDamageType, "Two Weapon Pounce Hit", "Two Weapon Pounce Miss", FALSE, OBJECT_INVALID, OBJECT_INVALID, TRUE)); } else if (GetLocalInt(oPC, "TigerFangCharge")) // Grants one extra attack at the end of a charge DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage, nDamageType, "Frenzied Charge Hit", "Frenzied Charge Miss", FALSE, OBJECT_INVALID, OBJECT_INVALID, TRUE)); DelayCommand(fDelay, PerformAttack(oTarget, oPC, eNone, 0.0, nAttack, nDamage, nDamageType, "Charge Hit", "Charge Miss")); } DelayCommand(fDelay, _PostCharge(oPC, oTarget)); } if(nBullRush) { DoBullRush(oPC, oTarget, nExtraBonus, nBullAoO, nMustFollow); FloatingTextStringOnCreature("You are bull rushing " + GetName(oTarget), oPC); } } else { FloatingTextStringOnCreature("You are too close to charge " + GetName(oTarget), oPC); } } void DoBullRush(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nMustFollow = TRUE, int nNoMove = FALSE, int nAbility = 0) { if (!nNoMove) { // Move to the target AssignCommand(oPC, ClearAllActions()); AssignCommand(oPC, ActionMoveToObject(oTarget, TRUE)); } effect eNone; // Do the AoO for moving into the enemy square if (nGenerateAoO) { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: AoO Start", oPC, FALSE); location lTarget = GetLocation(oPC); // Use the function to get the closest creature as a target object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); while(GetIsObjectValid(oAreaTarget)) { // All enemies in range get a free AoO shot if(oAreaTarget != oPC && // Don't hit yourself GetIsInMeleeRange(oPC, oAreaTarget) && // They must be in melee range GetIsEnemy(oAreaTarget, oPC)) // Only enemies are going to take AoOs { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: AoO Part 1", oPC, FALSE); if (!GetHasFeat(FEAT_IMPROVED_BULLRUSH, oPC) || oAreaTarget != oTarget) //Improved Bullrush means the defender can't take the AoO { // Perform the Attack DelayCommand(0.0, PerformAttack(oPC, oAreaTarget, eNone, 0.0, 0, 0, 0, "Attack of Opportunity Hit", "Attack of Opportunity Miss")); FloatingTextStringOnCreature(GetName(oAreaTarget)+" Bull Rush Attack of Opportunity", oPC, FALSE); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullRush: AoO Part 2", oPC, FALSE); } } //Select the next target within the spell shape. oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget, TRUE, OBJECT_TYPE_CREATURE); } } float fDelay = PRCGetSpellEffectDelay(GetLocation(oPC), oTarget) * 2.5; if (nNoMove) fDelay = 0.1; // No need for a delay if it's a spell if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoBullrush: Delay: "+FloatToString(fDelay), oPC, FALSE); DelayCommand(fDelay,_DoBullrushCheck(oPC, oTarget, nExtraBonus, nMustFollow, nAbility)); } int DoTrip(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nCounterTrip = TRUE, int nSkipTouch = FALSE, int nAbi = 0) { // The basic modifiers int nSucceed = FALSE; effect eNone; int nPCStat, nTargetStat; // Use the higher of the two mods if (GetAbilityModifier(ABILITY_STRENGTH, oPC) > GetAbilityModifier(ABILITY_DEXTERITY, oPC)) nPCStat = GetAbilityModifier(ABILITY_STRENGTH, oPC); else nPCStat = GetAbilityModifier(ABILITY_DEXTERITY, oPC); // Use the higher of the two mods if (GetAbilityModifier(ABILITY_STRENGTH, oTarget) > GetAbilityModifier(ABILITY_DEXTERITY, oTarget)) nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget); else nTargetStat = GetAbilityModifier(ABILITY_DEXTERITY, oTarget); // Override if (nAbi > 0) nPCStat = nAbi; // Get mods for size int nPCBonus = PRCGetSizeModifier(oPC) + GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_TRIP, FALSE, TRUE); int nTargetBonus = PRCGetSizeModifier(oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_TRIP, TRUE); //Warblade Battle Skill bonus if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC) >= 11) { nPCBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Trip bonus (attacker)"); } if (GetLevelByClass(CLASS_TYPE_WARBLADE, oTarget) >= 11) { nTargetBonus += GetAbilityModifier(ABILITY_INTELLIGENCE, oTarget); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Trip bonus (defender)"); } if (GetHasFeat(FEAT_IMPROVED_TRIP, oPC)) nPCBonus += 4; // Do the AoO for a trip attempt if (nGenerateAoO && !GetHasFeat(FEAT_IMPROVED_TRIP, oPC)) { // Perform the Attack effect eNone; DelayCommand(0.0, PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Attack of Opportunity Hit", "Attack of Opportunity Miss")); } int nPCCheck = nPCStat + nPCBonus + nExtraBonus + d20(); int nTargetCheck = nTargetStat + nTargetBonus + d20(); int nTouch; if (nSkipTouch == TRUE) nTouch = TRUE; else nTouch = PRCDoMeleeTouchAttack(oTarget, TRUE, oPC); // Gotta touch them if (nTouch) { SendMessageToPC(oPC, "Trip Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); // Now roll the ability check if (nPCCheck >= nTargetCheck) { // Knock em down ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oTarget, 6.0); nSucceed = TRUE; SetLocalInt(oPC, "TripDifference", nPCCheck - nTargetCheck); DelayCommand(2.0, DeleteLocalInt(oPC, "TripDifference")); if (!GetLocalInt(oPC, "CurlingWaveStrikeLoop")) // Neither of these trigger when Curling Wave Strike Loop protection is active { if (GetHasFeat(FEAT_CURLING_WAVE_STRIKE, oPC) && !GetLocalInt(oPC, "CurlingWaveStrikeRound")) // Once a round _DoCurlingWaveStrike(oPC, oTarget); else if (GetHasFeat(FEAT_IMPROVED_TRIP, oPC)) // Do the free Improved Trip attack DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, 0, 0, 0, "Improved Trip Free Attack Hit", "Improved Trip Free Attack Miss")); } } else // If you fail, enemy gets a counter trip attempt, using Strength { nTargetStat = GetAbilityModifier(ABILITY_STRENGTH, oTarget) + GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_TRIP, FALSE, TRUE); FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); // Roll counter trip attempt nTargetCheck = nTargetStat + nTargetBonus + d20(); nPCCheck = nPCStat + nPCBonus + d20(); // If counters aren't allowed, don't knock em down // Its down here to allow the text message to go through SendMessageToPC(oPC, "Enemy Counter Trip Check: "+IntToString(nPCCheck)+" vs "+IntToString(nTargetCheck)); if (nTargetCheck >= nPCCheck && nCounterTrip) { // Knock em down ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectKnockdown()), oPC, 6.0); } SetLocalInt(oPC, "TripDifference", nTargetCheck - nPCCheck); DelayCommand(2.0, DeleteLocalInt(oPC, "TripDifference")); } } else FloatingTextStringOnCreature("You have failed on your Trip attempt",oPC, FALSE); // Now we do the rest of the attacks in the round, regardless, remembering to bump down the iteratives SetLocalInt(oPC, "CombatMoveAttack", TRUE); DelayCommand(5.5, DeleteLocalInt(oPC, "CombatMoveAttack")); if (GetBaseAttackBonus(oPC) >= 6) PerformAttackRound(oTarget, oPC, eNone, 0.0, -5); DelayCommand(0.25, AssignCommand(oPC, ActionAttack(oTarget))); // Let people know if we made the hit or not return nSucceed; } int GetIntToDamage(int nCheck) { switch(nCheck) { case 1: return DAMAGE_BONUS_1; case 2: return DAMAGE_BONUS_2; case 3: return DAMAGE_BONUS_3; case 4: return DAMAGE_BONUS_4; case 5: return DAMAGE_BONUS_5; case 6: return DAMAGE_BONUS_6; case 7: return DAMAGE_BONUS_7; case 8: return DAMAGE_BONUS_8; case 9: return DAMAGE_BONUS_9; case 10: return DAMAGE_BONUS_10; case 11: return DAMAGE_BONUS_11; case 12: return DAMAGE_BONUS_12; case 13: return DAMAGE_BONUS_13; case 14: return DAMAGE_BONUS_14; case 15: return DAMAGE_BONUS_15; case 16: return DAMAGE_BONUS_16; case 17: return DAMAGE_BONUS_17; case 18: return DAMAGE_BONUS_18; case 19: return DAMAGE_BONUS_19; case 20: return DAMAGE_BONUS_20; } return -1; } int DoGrapple(object oPC, object oTarget, int nExtraBonus, int nGenerateAoO = TRUE, int nSkipTouch = FALSE) { if (GetGrapple(oTarget)) { FloatingTextStringOnCreature("You cannot grapple a creature that is already grappled.", oPC, FALSE); return FALSE; } if(GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oTarget)) { FloatingTextStringOnCreature("You cannot grapple a creature under the effect of Freedom of Movement", oPC, FALSE); return FALSE; } if (IPGetHasItemPropertyOnCharacter(oTarget, ITEM_PROPERTY_FREEDOM_OF_MOVEMENT)) { FloatingTextStringOnCreature("You cannot grapple a creature under the effect of Freedom of Movement.", oPC, FALSE); return FALSE; } if (GetIsImmune(oTarget, IMMUNITY_TYPE_ENTANGLE)) { FloatingTextStringOnCreature("This creature is immune to grappling.", oPC, FALSE); return FALSE; } object oGlaive = GetItemPossessedBy(oPC, "prc_eldrtch_glv"); if(GetIsObjectValid(oGlaive)) DestroyObject(oGlaive); int nSucceed = FALSE; effect eNone; // Do the AoO for trying a grapple if (nGenerateAoO && !GetHasFeat(FEAT_IMPROVED_GRAPPLE, oPC)) { // Perform the Attack DelayCommand(0.0, PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Attack of Opportunity Hit", "Attack of Opportunity Miss")); if (GetLocalInt(oPC, "PRCCombat_StruckByAttack")) { FloatingTextStringOnCreature("You have failed at your Grapple Attempt.", oPC, FALSE); return FALSE; } } int nTouch; if (nSkipTouch == TRUE) nTouch = TRUE; else nTouch = PRCDoMeleeTouchAttack(oTarget, TRUE, oPC); // Gotta touch them if (nTouch) { // Now roll the ability check if (_DoGrappleCheck(oPC, oTarget, nExtraBonus)) { FloatingTextStringOnCreature("You have successfully grappled " + GetName(oTarget), oPC, FALSE); int nBearFang = GetLocalInt(oPC, "BearFangGrapple"); SetGrapple(oPC); SetGrapple(oTarget); SetLocalInt(oPC, "GrappleOriginator", TRUE); effect eHold = EffectCutsceneParalyze(); effect eEntangle = EffectVisualEffect(VFX_DUR_SPELLTURNING_R); effect eLink = EffectLinkEffects(eHold, eEntangle); //apply the effect if (!GetLocalInt(oPC, "Flay_Grapple")) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oPC, 9999.0); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oTarget, 9999.0); nSucceed = TRUE; if (nBearFang) // Grants a bonus attack on hit { // Attack with a -4 penalty DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, -4, 0, 0, "Bear Fang Attack Hit", "Bear Fang Attack Miss")); DeleteLocalInt(oPC, "BearFangGrapple"); } else { // Now hit them with an unarmed strike object oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); } _HeartOfFireGrapple(oPC, oTarget); // If you kill them with this, best to clean up right away if (GetIsDead(oTarget) || !GetIsObjectValid(oTarget)) { EndGrapple(oPC, oTarget); // Remove the hooks if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); FloatingTextStringOnCreature("Your target is dead, ending grapple", oPC, FALSE); } else { // Hook in the events and save the target for an ongoing grapple if(DEBUG) DoDebug("prc_grapple: Adding eventhooks"); SetGrappleTarget(oPC, oTarget); AddEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); } } else FloatingTextStringOnCreature("You have failed your Grapple Attempt", oPC, FALSE); } // Let people know if we made the hit or not return nSucceed; } void SetGrapple(object oTarget) { SetLocalInt(oTarget, "IsGrappled", TRUE); } int GetGrapple(object oTarget) { return GetLocalInt(oTarget, "IsGrappled"); } void SetGrappleTarget(object oPC, object oTarget) { SetLocalObject(oPC, "GrappleTarget", oTarget); } object GetGrappleTarget(object oPC) { return GetLocalObject(oPC, "GrappleTarget"); } void SetIsPinned(object oTarget) { SetLocalInt(oTarget, "IsPinned", TRUE); } int GetIsPinned(object oTarget) { return GetLocalInt(oTarget, "IsPinned"); } void BreakPin(object oTarget) { DeleteLocalInt(oTarget, "IsPinned"); DeleteLocalInt(oTarget, "PinnedRounds"); } void EndGrapple(object oPC, object oTarget) { DeleteLocalInt(oPC, "IsGrappled"); DeleteLocalInt(oTarget, "IsGrappled"); DeleteLocalInt(oTarget, "PinnedRounds"); DeleteLocalObject(oPC, "GrappleTarget"); DeleteLocalInt(oTarget, "UnconsciousGrapple"); DeleteLocalInt(oPC, "GrappleOriginator"); DeleteLocalInt(oPC, "ScorpionLight"); DeleteLocalInt(oPC, "Flay_Grapple"); RemoveEventScript(oPC, EVENT_ITEM_ONHIT, "wol_m_flay", TRUE, FALSE); BreakPin(oTarget); effect eBad = GetFirstEffect(oTarget); //Search for negative effects while(GetIsEffectValid(eBad)) { int nInt = GetEffectSpellId(eBad); if (GetEffectType(eBad) == EFFECT_TYPE_CUTSCENE_PARALYZE) { RemoveEffect(oTarget, eBad); } eBad = GetNextEffect(oTarget); } eBad = GetFirstEffect(oPC); //Search for negative effects while(GetIsEffectValid(eBad)) { int nInt = GetEffectSpellId(eBad); if (GetEffectType(eBad) == EFFECT_TYPE_CUTSCENE_PARALYZE) { RemoveEffect(oPC, eBad); } eBad = GetNextEffect(oPC); } } int DoGrappleOptions(object oPC, object oTarget, int nExtraBonus, int nSwitch = -1) { effect eNone; int nSuccess = _DoGrappleCheck(oPC, oTarget, nExtraBonus, nSwitch); // This applies on all grapples regardless of success or failure _HeartOfFireGrapple(oPC, oTarget); if(GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oTarget)) { nSuccess = TRUE; nSwitch = GRAPPLE_ESCAPE; } if (nSwitch == GRAPPLE_ATTACK) { // Must be a light weapon, and succeed at the grapple check if (nSuccess && (GetIsLightWeapon(oPC) || GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) || GetHasFeat(FEAT_SPIKED_BODY, oPC)||GetHasFeat(FEAT_NATURAL_SPIKES))) { if (GetIsMeldBound(oTarget, MELD_RAGECLAWS) == CHAKRA_TOTEM && !GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC))) // CHAKRA_TOTEM { DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, 0, 0, 0, "Rageclaws Hit", "Rageclas Miss")); DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, 0, 0, 0, "Rageclaws Hit", "Rageclas Miss")); } else if (GetHasSpellEffect(MOVE_TC_WOLVERINE_STANCE, oPC)) { int nDam = 0; if (PRCGetCreatureSize(oTarget) > PRCGetCreatureSize(oPC)) nDam = 4; DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, 0, nDam, 0, "Wolverine Stance Hit", "Wolverine Stance Miss")); } else if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC)) { int nDam = d6(); if(GetLevelByClass(CLASS_TYPE_WARFORGED_JUGGERNAUT, oPC) >= 4) nDam = d8(); effect eDeath = EffectDamage(nDam, DAMAGE_TYPE_PIERCING); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDeath, oTarget); FloatingTextStringOnCreature("Warforged Juggernaut Armor Spikes Hit", oPC, FALSE); } else if(GetHasFeat(FEAT_SPIKED_BODY, oPC)) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(), DAMAGE_TYPE_PIERCING), oTarget); FloatingTextStringOnCreature("Spiked Body Hit", oPC, FALSE); } else if(GetHasFeat(FEAT_NATURAL_SPIKES, oPC)) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(), DAMAGE_TYPE_PIERCING), oTarget); FloatingTextStringOnCreature("Natural Spikes Hit", oPC, FALSE); } else { // Attack with a -4 penalty int nPen = -4; if (GetLocalInt(oPC, "ScorpionLight")) nPen = 0; DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, nPen, 0, 0, "Grapple Light Weapon Attack Hit", "Grapple Light Weapon Attack Miss")); } } else FloatingTextStringOnCreature("You have failed your Grapple Light Weapon Attack Attempt",oPC, FALSE); } else if (nSwitch == GRAPPLE_OPPONENT_WEAPON) { // Must be a light weapon, and succeed at the grapple check if (nSuccess && GetIsLightWeapon(oTarget)) { // Attack with a -4 penalty object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); DelayCommand(0.0, PerformAttack(oTarget, oPC, eNone, 0.0, -4, 0, 0, "Grapple Opponent's Weapon Hit", "Grapple Opponent's Weapon Miss", FALSE, oWeapon)); } else FloatingTextStringOnCreature("You have failed your Grapple Opponent's Weapon Attempt",oPC, FALSE); } else if (nSwitch == GRAPPLE_DAMAGE) { // Must be a light weapon, and succeed at the grapple check if (GetLocalInt(oPC, "Flay_Grapple")) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d3()+5), oTarget); FloatingTextStringOnCreature("Flay Constrict", oPC, FALSE); } else if (GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oPC) >= 8) { // Now hit them with a lot of unarmed strikes object oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oPC); eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oPC); eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); // Rend damage is double claw damage ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d8(2) + (2 * GetAbilityModifier(ABILITY_STRENGTH, oPC)), DAMAGE_TYPE_SLASHING), oTarget); FloatingTextStringOnCreature("Savage Grapple Hit",oPC, FALSE); } else if (GetHasFeat(FEAT_OWLBEAR_BERSERKER, oPC)) { ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6()), oTarget); FloatingTextStringOnCreature("Owlbear Berserker Hit",oPC, FALSE); } else if (nSuccess) { // Now hit them with an unarmed strike object oWeap = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oPC); effect eDam = GetAttackDamage(oTarget, oPC, oWeap, GetWeaponBonusDamage(oWeap, oTarget), GetMagicalBonusDamage(oPC, oTarget)); ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget); FloatingTextStringOnCreature("Grapple Unarmed Damage Hit",oPC, FALSE); } else FloatingTextStringOnCreature("You have failed your Grapple Unarmed Damage Attempt",oPC, FALSE); // This is bonus damage that applies to successful grappling of any of the above if (GetHasSpellEffect(VESTIGE_ZAGAN, oPC) && GetLocalInt(oPC, "ExploitVestige") != VESTIGE_ZAGAN_CONSTRICT && nSuccess) { int nDam = d8() + GetAbilityModifier(ABILITY_STRENGTH, oPC) + GetAbilityModifier(ABILITY_STRENGTH, oPC)/2; ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam), oTarget); FloatingTextStringOnCreature("Zagan Constrict Hit",oPC, FALSE); } } else if (nSwitch == GRAPPLE_ESCAPE) { // Must be a light weapon, and succeed at the grapple check if (nSuccess) { if (GetIsPinned(oPC)) { BreakPin(oPC); if (GetIsPC(oPC)) FloatingTextStringOnCreature("You have escaped the pin", oPC, FALSE); else FloatingTextStringOnCreature("Your target has escaped your pin", oTarget, FALSE); } else { EndGrapple(oPC, oTarget); if (GetIsPC(oPC)) { // Remove the hooks if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); RemoveEventScript(oPC, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); FloatingTextStringOnCreature("You have escaped the grapple", oPC, FALSE); } else { // Remove the hooks if(DEBUG) DoDebug("prc_grapple: Removing eventhooks"); RemoveEventScript(oTarget, EVENT_ONHEARTBEAT, "prc_grapple", TRUE, FALSE); FloatingTextStringOnCreature("Your target has escaped your grapple", oTarget, FALSE); // Target is valid and we know it's an enemy and we're in combat DelayCommand(0.25, AssignCommand(oTarget, ActionAttack(oPC))); } } } else FloatingTextStringOnCreature("You have failed your Grapple Escape Attempt",oPC, FALSE); } else if (nSwitch == GRAPPLE_TOB_CRUSHING && GetHasSpellEffect(MOVE_SD_CRUSHING_WEIGHT, oPC)) { // Constrict for 2d6 + 1.5 Strength if (nSuccess) { int nDam = FloatToInt(d6(2) + (GetAbilityModifier(ABILITY_STRENGTH, oPC) * 1.5)); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam), oTarget); FloatingTextStringOnCreature("Crushing Weight Success",oPC, FALSE); } else FloatingTextStringOnCreature("You have failed your Crushing Weight Attempt",oPC, FALSE); } else if (nSwitch == GRAPPLE_PIN) { // Pins the target if (nSuccess) { FloatingTextStringOnCreature("You have pinned your target", oPC, FALSE); SetIsPinned(oTarget); int nClass = GetLevelByClass(CLASS_TYPE_REAPING_MAULER, oPC); if (nClass) { int nRounds = _CountPinRounds(oTarget); _DoReapingMauler(oPC, oTarget, nRounds); } if (GetHasFeat(FEAT_EARTHS_EMBRACE, oPC)) { // Add in unarmed damage int nDamageSize = FindUnarmedDamage(oPC); int nDie = StringToInt(Get2DACache("iprp_monstcost", "Die", nDamageSize)); int nNum = StringToInt(Get2DACache("iprp_monstcost", "NumDice", nDamageSize)); int nRoll; //Potential die options if(nDie == 4) nRoll = d4(nNum); else if(nDie == 6) nRoll = d6(nNum); else if(nDie == 8) nRoll = d8(nNum); else if(nDie == 10) nRoll = d10(nNum); else if(nDie == 12) nRoll = d12(nNum); else if(nDie == 20) nRoll = d20(nNum); FloatingTextStringOnCreature("Earth's Embrace chokes the life from your foe", oPC, FALSE); int nDam = d12() + nRoll; ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, DAMAGE_TYPE_BLUDGEONING), oTarget); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACDecrease(4)), oPC, 6.0); } } else FloatingTextStringOnCreature("You have failed your Grapple Pin Attempt",oPC, FALSE); } else { FloatingTextStringOnCreature("DoGrappleOptions: Error, invalid option "+IntToString(nSwitch)+" passed to function by "+GetName(oPC),oPC, FALSE); FloatingTextStringOnCreature("DoGrappleOptions: Error, GetGrapple(oPC) "+IntToString(GetGrapple(oPC))+" GetGrapple(oTarget) "+IntToString(GetGrapple(oTarget)),oPC, FALSE); return FALSE; } return nSuccess; } int GetIsLightWeapon(object oPC) { // You may use any weapon in a grapple with this stance. if (GetHasSpellEffect(MOVE_TC_WOLVERINE_STANCE, oPC)) return TRUE; int nSize = PRCGetCreatureSize(oPC); object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); int nWeaponSize = GetWeaponSize(oItem); // is the size appropriate for a light weapon? return (nWeaponSize < nSize); } void DoOverrun(object oPC, object oTarget, location lTarget, int nGenerateAoO = TRUE, int nExtraBonus = 0, int nAvoid = TRUE, int nCounter = TRUE) { effect eCharge = SupernaturalEffect(EffectMovementSpeedIncrease(99)); // Just to speed things up a bit SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCharge, oPC, 5.0); SetLocalInt(oPC, "Overrun", 2); // This tells _DoOverrunCheck it's a valid call float fLength = GetDistanceBetweenLocations(GetLocation(oPC), lTarget); vector vOrigin = GetPosition(oPC); if (GetIsMeldBound(oPC, MELD_URSKAN_GREAVES) == CHAKRA_TOTEM) nAvoid = FALSE; if (GetHasFeat(FEAT_CENTAUR_TRAMPLE, oPC)) nAvoid = FALSE; // Step one is check to see if we're using oTarget or not if (GetIsObjectValid(oTarget)) { lTarget = GetLocation(oTarget); fLength = GetDistanceBetweenLocations(GetLocation(oPC), lTarget); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoOverrun: Valid Target", oPC, FALSE); } else oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE, vOrigin); // Only change targets if invalid // Move the PC to the location AssignCommand(oPC, ClearAllActions(TRUE)); AssignCommand(oPC, ActionForceMoveToLocation(lTarget, TRUE)); if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoOverrun: Distance: "+FloatToString(fLength), oPC, FALSE); // Loop over targets in the line shape if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoOverrun: First Target: "+GetName(oTarget), oPC, FALSE); while(GetIsObjectValid(oTarget)) // Find the targets { if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoOverrun: Loop 1, Target: "+GetName(oTarget), oPC, FALSE); if(oTarget != oPC && GetIsEnemy(oTarget, oPC)) // Don't overrun friends or yourself { float fDelay = PRCGetSpellEffectDelay(GetLocation(oPC), oTarget) * 2.5; if (DEBUG_COMBAT_MOVE) FloatingTextStringOnCreature("DoOverrun: Loop 2, Delay: "+FloatToString(fDelay), oPC, FALSE); DelayCommand(fDelay,_DoOverrunCheck(oPC, oTarget, lTarget, nGenerateAoO, nExtraBonus, nAvoid, nCounter)); }// end if - Target validity check // Get next target oTarget = MyNextObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE, vOrigin); }// end while - Target loop // Clean up DelayCommand(3.0,DeleteLocalInt(oPC, "Overrun")); } int PRCGetSizeModifier(object oCreature) { int nSize = PRCGetCreatureSize(oCreature); //Powerful Build bonus if(GetHasFeat(FEAT_RACE_POWERFUL_BUILD, oCreature)) nSize++; //Make sure it doesn't overflow if(nSize > CREATURE_SIZE_COLOSSAL) nSize = CREATURE_SIZE_COLOSSAL; int nModifier = 0; // Jotunbrud if(GetHasFeat(FEAT_JOTUNBRUD, oCreature) && nSize == CREATURE_SIZE_MEDIUM) nSize++; // Oddly, this overrides everything else and just sets your size as large if (GetHasSpellEffect(VESTIGE_ZAGAN, oCreature) && GetLocalInt(oCreature, "ExploitVestige") != VESTIGE_ZAGAN_GRAPPLE) nSize = CREATURE_SIZE_LARGE; switch (nSize) { case CREATURE_SIZE_TINY: nModifier = -8; break; case CREATURE_SIZE_SMALL: nModifier = -4; break; case CREATURE_SIZE_MEDIUM: nModifier = 0; break; case CREATURE_SIZE_LARGE: nModifier = 4; break; case CREATURE_SIZE_HUGE: nModifier = 8; break; case CREATURE_SIZE_GARGANTUAN: nModifier = 12; break; case CREATURE_SIZE_COLOSSAL: nModifier = 16; break; } return nModifier; } void TigerBlooded(object oInitiator, object oTarget) { // Got to have the feat first and hit the opponent if (!GetHasFeat(FEAT_TIGER_BLOODED, oInitiator)) return; if (!GetLocalInt(oTarget, "PRCCombat_StruckByAttack")) return; if(GetHasSpellEffect(SPELLABILITY_BARBARIAN_RAGE, oInitiator) || GetIsPolyMorphedOrShifted(oInitiator) || GetHasSpellEffect(SPELL_SPELL_RAGE, oInitiator) || GetHasSpellEffect(SPELL_BLOOD_FRENZY, oInitiator) || GetHasSpellEffect(SPELL_FRENZY, oInitiator) || GetHasSpellEffect(SPELL_INSPIRE_FRENZY, oInitiator) || GetHasSpellEffect(SPELL_TRIBAL_FRENZY , oInitiator) || GetHasSpellEffect(INVOKE_WILD_FRENZY, oInitiator)) { int nHD = GetHitDice(oInitiator)/2; int nStr = GetAbilityModifier(ABILITY_STRENGTH, oInitiator); int nDC = 10 + nHD + nStr; if (PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC) && PRCGetSizeModifier(oInitiator) >= PRCGetSizeModifier(oTarget)) { _DoBullRushKnockBack(oTarget, oInitiator, 5.0); FloatingTextStringOnCreature("Tiger Blooded Knockback", oInitiator, FALSE); } } } int DoDisarm(object oPC, object oTarget, int nExtraBonus = 0, int nGenerateAoO = TRUE, int nCounter = TRUE) { object oTargetWep = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget); if (!GetIsObjectValid(oTargetWep) || GetPlotFlag(oTargetWep) || (!GetIsCreatureDisarmable(oTarget) && !GetPRCSwitch(PRC_PNP_DISARM)) || GetLocalInt(oTarget, "TigerFangDisarm")) { FloatingTextStringOnCreature("Target is not a legal target", oPC, FALSE); AssignCommand(oPC, ActionAttack(oTarget)); return FALSE; } // The basic modifiers int nSucceed = FALSE; object oPCWep = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); effect eNone; GetAttackRoll(oTarget, oPC, oPCWep, 0, 0, 0, FALSE); GetAttackRoll(oPC, oTarget, oTargetWep, 0, 0, 0, FALSE); int nPCAttack = GetLocalInt(oPC, "PRCAttackBonus"); int nTargetAttack = GetLocalInt(oTarget, "PRCAttackBonus"); nPCAttack += GetCombatMoveCheckBonus(oPC, COMBAT_MOVE_DISARM, FALSE, TRUE); nTargetAttack += GetCombatMoveCheckBonus(oTarget, COMBAT_MOVE_DISARM, TRUE); int nPCSize = PRCGetCreatureSize(oPC); int nPCWeaponSize = GetWeaponSize(oPCWep); int nTGSize = PRCGetCreatureSize(oTarget); int nTGWeaponSize = GetWeaponSize(oTargetWep); // Two-handed weapon if (nPCWeaponSize >= nPCSize + 1) nPCAttack += 4; if (nTGWeaponSize >= nTGSize + 1) nTargetAttack += 4; // Light weapon or unarmed if ((nPCSize > nPCWeaponSize) || !GetIsObjectValid(oPCWep)) nPCAttack -= 4; if (nTGSize > nTGWeaponSize) nTargetAttack -= 4; //Larger combatant gets a +4 bonus per size difference, applied as a bonus or penalty to the PCAttack nPCAttack += (nPCSize - nTGSize) * 4; //Warblade Battle Skill bonus if (GetLevelByClass(CLASS_TYPE_WARBLADE, oPC) >= 11) { nPCAttack += GetAbilityModifier(ABILITY_INTELLIGENCE, oPC); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Disarm bonus (attacker)"); } if (GetLevelByClass(CLASS_TYPE_WARBLADE, oTarget) >= 11) { nTargetAttack += GetAbilityModifier(ABILITY_INTELLIGENCE, oTarget); if (DEBUG_COMBAT_MOVE) DoDebug("Warblade Battle Skill Disarm bonus (defender)"); } if (GetHasFeat(FEAT_PRC_IMP_DISARM, oPC)) // Check if oPC is the same as oTarget and return immediately if (oPC == oTarget) { FloatingTextStringOnCreature("You can't Disarm yourself.", oPC, FALSE); return FALSE; } if (GetHasFeat(FEAT_PRC_IMP_DISARM, oPC)) { nPCAttack += 4; nGenerateAoO = FALSE; nCounter = FALSE; } // Do the AoO for a trip attempt if (nGenerateAoO) { // Perform the Attack effect eNone; DelayCommand(0.0, PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Attack of Opportunity Hit", "Attack of Opportunity Miss")); if (GetLocalInt(oPC, "PRCCombat_StruckByAttack")) { FloatingTextStringOnCreature("You have failed at your Disarm Attempt.", oPC, FALSE); return FALSE; } } SendMessageToPC(oPC, "Disarm Check: "+IntToString(nPCAttack)+" vs "+IntToString(nTargetAttack)); // Now the outcome if (nPCAttack >= nTargetAttack) { // Disarm em nSucceed = TRUE; // Unarmed if (!GetIsObjectValid(oPCWep)) { object oCopy = CopyObject(oTargetWep, GetLocation(oPC), oPC); DestroyObject(oTargetWep); SetDroppableFlag(oCopy, TRUE); SetStolenFlag(oCopy, FALSE); } else { AssignCommand(oTarget, ClearAllActions(TRUE)); SetDroppableFlag(oTargetWep, TRUE); SetStolenFlag(oTargetWep, FALSE); //AssignCommand(oTarget, ActionPutDownItem(oTargetWep)); ForcePutDown(oTarget, oTargetWep, INVENTORY_SLOT_RIGHTHAND); } if (GetHasFeat(FEAT_STEAL_AND_STRIKE, oPC)) { int nRight = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)); int nLeft = GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC)); if (nLeft == BASE_ITEM_KUKRI && nRight == BASE_ITEM_RAPIER) PerformAttack(oPC, oTarget, eNone, 0.0, 0, 0, 0, "Steal and Strike Hit", "Steal and Strike Miss", FALSE, OBJECT_INVALID, GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC), TRUE); } } else if (nCounter) // If you fail, enemy gets a counter attempt { FloatingTextStringOnCreature("You have failed on your disarm attempt",oPC, FALSE); DoDisarm(oTarget, oPC, 0, FALSE, FALSE); } else FloatingTextStringOnCreature("You have failed on your disarm attempt",oPC, FALSE); // Keep Attacking //AssignCommand(oPC, ActionAttack(oTarget)); // Now we do the rest of the attacks in the round, regardless, remembering to bump down the iteratives SetLocalInt(oPC, "CombatMoveAttack", TRUE); DelayCommand(5.5, DeleteLocalInt(oPC, "CombatMoveAttack")); if (GetBaseAttackBonus(oPC) >= 6) PerformAttackRound(oTarget, oPC, eNone, 0.0, -5); DelayCommand(0.25, AssignCommand(oPC, ActionAttack(oTarget))); // Let people know if we made the hit or not return nSucceed; } void DoTrample(object oPC, object oTarget, location lTarget) { effect eCharge = SupernaturalEffect(EffectMovementSpeedIncrease(99)); // Just to speed things up a bit ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCharge, oPC, 5.5); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSkillIncrease(SKILL_TUMBLE, 50), oPC, 5.5); float fLength = GetDistanceBetweenLocations(GetLocation(oPC), lTarget); vector vOrigin = GetPosition(oPC); // Step one is check to see if we're using oTarget or not if (GetIsObjectValid(oTarget)) { lTarget = GetLocation(oTarget); fLength = GetDistanceBetweenLocations(GetLocation(oPC), lTarget); } else oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE, vOrigin); // Only change targets if invalid // Move the PC to the location AssignCommand(oPC, ClearAllActions(TRUE)); AssignCommand(oPC, ActionForceMoveToLocation(lTarget, TRUE)); // Loop over targets in the line shape while(GetIsObjectValid(oTarget)) // Find the targets { if(oTarget != oPC && GetIsEnemy(oTarget, oPC)) // Don't overrun friends or yourself { float fDelay = PRCGetSpellEffectDelay(GetLocation(oPC), oTarget) * 2.5; DelayCommand(fDelay, _DoTrampleDamage(oPC, oTarget)); }// end if - Target validity check // Get next target oTarget = MyNextObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE, vOrigin); }// end while - Target loop } void DoShieldBash(object oPC, object oTarget, int nAtk = 0, int nDamage = 0, int nDamageType = 0, int nCharge = FALSE, int nPounce = FALSE, int nSlam = FALSE, int nInstant = FALSE) { object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC); int nType = GetBaseItemType(oShield); effect eNone; // Can only bash with small or large shields, not tower if (nType != BASE_ITEM_LARGESHIELD && nType != BASE_ITEM_SMALLSHIELD) { FloatingTextStringOnCreature("You do not have a legal shield equipped!", oPC, FALSE); PerformAttackRound(oTarget, oPC, eNone); return; } int nTWFeat, nPenOn, nPenOff; // Check for TWF feats that matter for this if(GetHasFeat(FEAT_SUPREME_TWO_WEAPON_FIGHTING, oPC)) nTWFeat = 4; else if(GetHasFeat(FEAT_GREATER_TWO_WEAPON_FIGHTING, oPC)) nTWFeat = 3; else if(GetHasFeat(FEAT_IMPROVED_TWO_WEAPON_FIGHTING, oPC)) nTWFeat = 2; else if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oPC)) nTWFeat = 1; // Number of attacks with the shield. You always get at least one. int nAttacks = 1; if (nTWFeat == 4) nAttacks = 4; else if (nTWFeat == 3) nAttacks = 3; else if (nTWFeat == 2) nAttacks = 2; // Attack penalty for two weapon fighting. Small shields count as light weapons. Large shields as one-handed weapons. if(GetHasFeat(FEAT_AGILE_SHIELD_FIGHTER, oPC)) { nPenOn = -2; nPenOff = -2; } else if (nTWFeat && (nType == BASE_ITEM_SMALLSHIELD || (nType == BASE_ITEM_LARGESHIELD && GetHasFeat(FEAT_OTWF, oPC)))) { nPenOn = -2; nPenOff = -2; } else if (nTWFeat && nType == BASE_ITEM_LARGESHIELD) // TWF with a One-handed weapon { nPenOn = -4; nPenOff = -4; } else if (nType == BASE_ITEM_SMALLSHIELD) // Light weapon, no TWF { nPenOn = -4; nPenOff = -8; } else // One-handed weapon, no TWF { nPenOn = -6; nPenOff = -10; } // Add bashing to attack rolls. _ShieldBashDamage gets it for damage nAtk += GetLocalInt(oPC, "BashingEnchant"); // Add in any passed along bonuses nPenOn += nAtk; nPenOff += nAtk; // Do the attacks, including main hand //Pouncing Charge if (nCharge && nPounce) { PerformAttackRound(oTarget, oPC, eNone, 0.0, nPenOn, nDamage, nDamageType, FALSE, "Pouncing Charge Hit", "Pouncing Charge Miss", FALSE, FALSE, TRUE); int i; for(i = 1; i <= nAttacks; i++) { // Account for iteratives on TWF int nIter = 5-(5*i); int nRoll = GetAttackRoll(oTarget, oPC, oShield, 1, 0, nPenOff-nIter); if (nRoll) { _ShieldBashDamage(oPC, oTarget, nRoll, FALSE, nDamage, nDamageType, nType); // The only way to get here is Shield Charge, so we know they have this effect DoTrip(oPC, oTarget, 0, FALSE, FALSE); } } } else if (nCharge && !nPounce) // Charging without pounce, so only one attack { PerformAttack(oTarget, oPC, eNone, 0.0, nPenOn, nDamage, nDamageType, "Charge Hit", "Charge Miss"); int nRoll = GetAttackRoll(oTarget, oPC, oShield, 1, 0, nPenOff); if (nRoll) { _ShieldBashDamage(oPC, oTarget, nRoll, FALSE, nDamage, nDamageType, nType); // The only way to get here is Shield Charge, so we know they have this effect DoTrip(oPC, oTarget, 0, FALSE, FALSE); } } else if (nSlam) // Shield Slam only { int nRoll = GetAttackRoll(oTarget, oPC, oShield, 1, 0, nPenOff); if (nRoll) { // GetAttackRoll doesn't set this, so we set it manually SetLocalInt(oTarget, "PRCCombat_StruckByAttack", TRUE); DelayCommand(1.0, DeleteLocalInt(oTarget, "PRCCombat_StruckByAttack")); _ShieldBashDamage(oPC, oTarget, nRoll, TRUE, nDamage, nDamageType, nType); // Shield slam stun int nDC = 10 + GetHitDice(oPC)/2 + GetAbilityModifier(ABILITY_STRENGTH, oPC); if (!GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT)) { if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE)) { ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDazed(), oTarget, 6.0); } } FloatingTextStringOnCreature("Shield Slam Hit!", oPC, FALSE); // If it's a charge and we're here, we've hit with the attack if (nCharge) DoTrip(oPC, oTarget, 0, FALSE, FALSE); } else FloatingTextStringOnCreature("Shield Slam Missed!", oPC, FALSE); } else if (nInstant) // Shield Counter only, currently { int nRoll = GetAttackRoll(oTarget, oPC, oShield, 1, 0, nPenOff); if (nRoll) { // GetAttackRoll doesn't set this, so we set it manually SetLocalInt(oTarget, "PRCCombat_StruckByAttack", TRUE); DelayCommand(1.0, DeleteLocalInt(oTarget, "PRCCombat_StruckByAttack")); _ShieldBashDamage(oPC, oTarget, nRoll, TRUE, nDamage, nDamageType, nType); // Enemy misses their next attack ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(PSI_IMP_CONCUSSION_BLAST), oTarget); ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectAttackDecrease(20)), oTarget, 3.0); FloatingTextStringOnCreature("Shield Counter Hit!", oPC, FALSE); } else FloatingTextStringOnCreature("Shield Counter Missed!", oPC, FALSE); } else // No charge, no pounce, so regular combat { PerformAttackRound(oTarget, oPC, eNone, 0.0, nPenOn, nDamage, nDamageType); int i; for(i = 1; i <= nAttacks; i++) { // Account for iteratives on TWF int nIter = 5-(5*i); int nRoll = GetAttackRoll(oTarget, oPC, oShield, 1, 0, nPenOff-nIter); if (nRoll) { _ShieldBashDamage(oPC, oTarget, nRoll, FALSE, nDamage, nDamageType, nType); } } } // No shield benefit for the next round, unless you have Improved Shield Bash if(!GetHasFeat(FEAT_IMPROVED_SHIELD_BASH, oPC)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectACDecrease(GetItemACValue(oShield)), oPC, 6.0); // Target is valid and we know it's an enemy and we're in combat DelayCommand(0.25, AssignCommand(oPC, ActionAttack(oTarget))); } void DoShieldCharge(object oPC, object oTarget, int nSlam = FALSE) { // PnP rules use feet, might as well convert it now. float fDistance = MetersToFeet(GetDistanceBetweenLocations(GetLocation(oPC), GetLocation(oTarget))); if(fDistance >= 10.0) { // Mark the PC as charging SetIsCharging(oPC); int nPounce = FALSE; int nDamageType = DAMAGE_TYPE_BASE_WEAPON; int nDamage = _ChargeDamage(oPC); int nAttack = _ChargeAttack(oPC, oTarget, nAttack); // This now takes into account charge feats effect eNone; // Move to the target AssignCommand(oPC, ClearAllActions()); AssignCommand(oPC, ActionMoveToObject(oTarget, TRUE)); // Dread Carapace Totem Bind if(GetIsIncarnumUser(oPC)) { if (GetIsMeldBound(oPC, MELD_DREAD_CARAPACE) == CHAKRA_TOTEM) // CHAKRA_TOTEM { location lTargetLocation = GetLocation(oPC); int nSaveDC = GetMeldshaperDC(oPC, CLASS_TYPE_TOTEMIST, MELD_DREAD_CARAPACE); // MELD_DREAD_CARAPACE object oDreadTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTargetLocation, FALSE, OBJECT_TYPE_CREATURE); while(GetIsObjectValid(oDreadTarget)) { if(GetIsEnemy(oPC, oDreadTarget)) { if(!PRCMySavingThrow(SAVING_THROW_WILL, oDreadTarget, nSaveDC, SAVING_THROW_TYPE_FEAR)) ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectShaken(), oDreadTarget, 6.0); } //Select the next target within the spell shape. oDreadTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(60.0), lTargetLocation, FALSE, OBJECT_TYPE_CREATURE); } } } // Flying Kick feat if(GetHasFeat(FEAT_FLYING_KICK, oPC) && (GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) == OBJECT_INVALID)) nDamage += d12(); if(GetHasFeat(FEAT_SNOW_TIGER_BERSERKER, oPC) && GetIsLightWeapon(oPC)) nPounce = TRUE; if(GetHasFeat(FEAT_CATFOLK_POUNCE, oPC) && GetIsDeniedDexBonusToAC(oTarget, oPC, TRUE)) nPounce = TRUE; if(GetItemPossessedBy(oPC, "WOL_Shishio") == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) && GetLocalInt(oPC, "Shishio_Pounce")) nPounce = TRUE; if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) >= 5) nPounce = TRUE; if(GetRacialType(oPC) == RACIAL_TYPE_MARRUSAULT) nPounce = TRUE; // Checks for a White Raven Stance // If it exists, +1 damage/initiator level if(GetLocalInt(oPC, "LeadingTheCharge")) nDamage += GetLocalInt(oPC, "LeadingTheCharge"); if(nDamageType == -1) // If the damage type isn't set { object oWeap = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC); nDamageType = GetWeaponDamageType(oWeap); } float fDelay = FeetToMeters(fDistance)/10; DelayCommand(fDelay, DoShieldBash(oPC, oTarget, nAttack, nDamage, nDamageType, TRUE, nPounce, nSlam)); DelayCommand(fDelay, _PostCharge(oPC, oTarget)); } else { FloatingTextStringOnCreature("You are too close to charge " + GetName(oTarget), oPC); } } //:: Test void //:: void main (){}