Added henchman rental
Many areas, items, and creatures were adjusted for balance and aesthetics.
This commit is contained in:
702
_module/nss/hench_i0_melee.nss
Normal file
702
_module/nss/hench_i0_melee.nss
Normal file
@@ -0,0 +1,702 @@
|
||||
/*
|
||||
|
||||
Henchman Inventory And Battle AI
|
||||
|
||||
This file contains a modified form of the original TalentMeleeAttack.
|
||||
Major modification to not randomly pick feats to use.
|
||||
|
||||
*/
|
||||
|
||||
#include "hench_i0_equip"
|
||||
|
||||
// void main() { }
|
||||
|
||||
|
||||
int GetItemAttackBonus(object oTarget, object oItem)
|
||||
{
|
||||
int nReturnVal = 0;
|
||||
|
||||
itemproperty oProp = GetFirstItemProperty(oItem);
|
||||
while (GetIsItemPropertyValid(oProp))
|
||||
{
|
||||
int bGetSetting = FALSE;
|
||||
switch (GetItemPropertyType(oProp))
|
||||
{
|
||||
case ITEM_PROPERTY_ENHANCEMENT_BONUS:
|
||||
case ITEM_PROPERTY_ATTACK_BONUS:
|
||||
bGetSetting = TRUE;
|
||||
break;
|
||||
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP:
|
||||
case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
|
||||
switch (GetItemPropertySubType(oProp))
|
||||
{
|
||||
case IP_CONST_ALIGNMENTGROUP_NEUTRAL:
|
||||
bGetSetting = (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_NEUTRAL) ||
|
||||
(GetAlignmentLawChaos(oTarget) == ALIGNMENT_NEUTRAL);
|
||||
break;
|
||||
case IP_CONST_ALIGNMENTGROUP_LAWFUL:
|
||||
bGetSetting = GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL;
|
||||
break;
|
||||
case IP_CONST_ALIGNMENTGROUP_CHAOTIC:
|
||||
bGetSetting = GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC;
|
||||
break;
|
||||
case IP_CONST_ALIGNMENTGROUP_GOOD:
|
||||
bGetSetting = GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD;
|
||||
break;
|
||||
case IP_CONST_ALIGNMENTGROUP_EVIL:
|
||||
bGetSetting = GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP:
|
||||
case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP:
|
||||
bGetSetting = GetItemPropertySubType(oProp) == GetRacialType(oTarget);
|
||||
break;
|
||||
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT:
|
||||
case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT:
|
||||
{
|
||||
int iSpecificAlignment = GetItemPropertySubType(oProp);
|
||||
switch (iSpecificAlignment % 3)
|
||||
{
|
||||
case 0:
|
||||
bGetSetting = GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD;
|
||||
break;
|
||||
case 1:
|
||||
bGetSetting = GetAlignmentGoodEvil(oTarget) == ALIGNMENT_NEUTRAL;
|
||||
break;
|
||||
case 2:
|
||||
bGetSetting = GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL;
|
||||
break;
|
||||
}
|
||||
if (bGetSetting)
|
||||
{
|
||||
bGetSetting = FALSE;
|
||||
switch (iSpecificAlignment / 3)
|
||||
{
|
||||
case 0:
|
||||
bGetSetting = GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL;
|
||||
break;
|
||||
case 1:
|
||||
bGetSetting = GetAlignmentLawChaos(oTarget) == ALIGNMENT_NEUTRAL;
|
||||
break;
|
||||
case 2:
|
||||
bGetSetting = GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (bGetSetting)
|
||||
{
|
||||
int itemPropValue = GetItemPropertyCostTableValue(oProp);
|
||||
if (itemPropValue > nReturnVal)
|
||||
{
|
||||
nReturnVal = itemPropValue;
|
||||
}
|
||||
}
|
||||
oProp = GetNextItemProperty(oItem);
|
||||
}
|
||||
return nReturnVal;
|
||||
}
|
||||
|
||||
|
||||
int GetMeleeAttackBonus(object oCreature, object oWeaponRight, object oTarget)
|
||||
{
|
||||
int nReturn = 0;
|
||||
// Finesse only if we are using a proper weapon
|
||||
int nStrMod = GetAbilityModifier(ABILITY_STRENGTH, oCreature);
|
||||
int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY, oCreature);
|
||||
int bCanFinesse = GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) && (nDexMod > nStrMod);
|
||||
|
||||
if (GetIsObjectValid(oWeaponRight))
|
||||
{
|
||||
nReturn += GetItemAttackBonus(oTarget, oWeaponRight);
|
||||
if (bCanFinesse)
|
||||
{
|
||||
switch (GetBaseItemType(oWeaponRight))
|
||||
{
|
||||
// only these weapons can be finessed
|
||||
case BASE_ITEM_DAGGER:
|
||||
case BASE_ITEM_HANDAXE:
|
||||
case BASE_ITEM_KAMA:
|
||||
case BASE_ITEM_KUKRI:
|
||||
case BASE_ITEM_LIGHTHAMMER:
|
||||
case BASE_ITEM_LIGHTMACE:
|
||||
case BASE_ITEM_RAPIER:
|
||||
case BASE_ITEM_SHORTSWORD:
|
||||
case BASE_ITEM_SHURIKEN:
|
||||
case BASE_ITEM_SICKLE:
|
||||
case BASE_ITEM_THROWINGAXE:
|
||||
break;
|
||||
default:
|
||||
bCanFinesse = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: creature weapons can be finessed
|
||||
oWeaponRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature);
|
||||
if (GetIsObjectValid(oWeaponRight))
|
||||
{
|
||||
nReturn += GetItemAttackBonus(oTarget, oWeaponRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
oWeaponRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature);
|
||||
if (GetIsObjectValid(oWeaponRight))
|
||||
{
|
||||
nReturn += GetItemAttackBonus(oTarget, oWeaponRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
oWeaponRight = GetItemInSlot(INVENTORY_SLOT_ARMS, oCreature);
|
||||
if (GetIsObjectValid(oWeaponRight))
|
||||
{
|
||||
nReturn += GetItemAttackBonus(oTarget, oWeaponRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
object oWeaponLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
|
||||
int nOffHandWeaponSize = GetMeleeWeaponSize(oWeaponLeft);
|
||||
if (nOffHandWeaponSize > 0)
|
||||
{
|
||||
if (nOffHandWeaponSize == GetCreatureSize(oCreature))
|
||||
{
|
||||
nReturn -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO more could be done here
|
||||
nReturn -= 4;
|
||||
}
|
||||
}
|
||||
if(bCanFinesse)
|
||||
{
|
||||
nReturn += nDexMod;
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn += nStrMod;
|
||||
}
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
|
||||
int GetRangeAttackBonus(object oCreature, object oRangedWeapon, object oTarget)
|
||||
{
|
||||
int nReturn = GetItemAttackBonus(oTarget, oRangedWeapon);
|
||||
int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY, oCreature);
|
||||
int nWisMod = GetAbilityModifier(ABILITY_WISDOM, oCreature);
|
||||
if (GetHasFeat(FEAT_ZEN_ARCHERY, oCreature) && (nWisMod > nDexMod))
|
||||
{
|
||||
nReturn += nWisMod;
|
||||
}
|
||||
else
|
||||
{
|
||||
nReturn += nDexMod;
|
||||
}
|
||||
int itemType = GetBaseItemType(oRangedWeapon);
|
||||
if ((itemType == BASE_ITEM_LONGBOW) || (itemType == BASE_ITEM_SHORTBOW))
|
||||
{
|
||||
int nLevel = GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, oCreature);
|
||||
if (nLevel > 0)
|
||||
{
|
||||
nReturn += ((nLevel+1)/2);
|
||||
}
|
||||
}
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
|
||||
int GetAttackBonus(object oCreature, object oTarget)
|
||||
{
|
||||
object oRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature);
|
||||
if (GetWeaponRanged(oRightWeapon))
|
||||
{
|
||||
return GetRangeAttackBonus(oCreature, oRightWeapon, oTarget);
|
||||
}
|
||||
return GetMeleeAttackBonus(oCreature, oRightWeapon, oTarget);
|
||||
}
|
||||
|
||||
|
||||
void HenchDoTalentMeleeAttack(object oTarget, float fThresholdDistance, int iCreatureType)
|
||||
{
|
||||
int iIntCheck = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) - 2;
|
||||
if (iIntCheck < 6)
|
||||
{
|
||||
// have less smart creatures not use best combat feats all the time
|
||||
if (iIntCheck < 1)
|
||||
{
|
||||
iIntCheck = 1;
|
||||
}
|
||||
if (iIntCheck < d6())
|
||||
{
|
||||
UseCombatAttack(oTarget);
|
||||
return;
|
||||
}
|
||||
}
|
||||
object oRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
|
||||
int bRangedWeapon = GetWeaponRanged(oRightWeapon);
|
||||
|
||||
int iAC = GetAC(oTarget);
|
||||
int iNewBAB = GetBaseAttackBonus(OBJECT_SELF) + 5 + d4(2);
|
||||
|
||||
if(bRangedWeapon)
|
||||
{
|
||||
// At a -2 to hit, this can disarm the arms or legs...speed or attack bonus
|
||||
if(d8() == 1 && GetHasFeat(FEAT_CALLED_SHOT) && !GetHasFeatEffect(FEAT_CALLED_SHOT, oTarget)
|
||||
&& !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT, OBJECT_SELF) && !GetIsDisabled(oTarget))
|
||||
{
|
||||
iNewBAB += GetRangeAttackBonus(OBJECT_SELF, oRightWeapon, oTarget);
|
||||
if((iNewBAB - 2) >= iAC)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_CALLED_SHOT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Always use if present
|
||||
if(GetHasFeat(FEAT_RAPID_SHOT))
|
||||
{
|
||||
int iItemType = GetBaseItemType(oRightWeapon);
|
||||
if (iItemType == BASE_ITEM_SHORTBOW || iItemType == BASE_ITEM_LONGBOW)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_RAPID_SHOT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ActionAttack(oTarget);
|
||||
return;
|
||||
}
|
||||
iNewBAB += GetMeleeAttackBonus(OBJECT_SELF, oRightWeapon, oTarget);
|
||||
|
||||
float relativeChallenge;
|
||||
if (iCreatureType == 0)
|
||||
{
|
||||
// mosters always use best feat
|
||||
relativeChallenge = -10.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
relativeChallenge = iCreatureType == 1 ? IntToFloat(GetHitDice(OBJECT_SELF)) * HENCH_HITDICE_TO_CR : GetChallengeRating(OBJECT_SELF);
|
||||
relativeChallenge -= GetIsPC(oTarget) || GetAssociateType(oTarget) == ASSOCIATE_TYPE_HENCHMAN ?
|
||||
IntToFloat(GetHitDice(oTarget)) * HENCH_HITDICE_TO_CR : GetChallengeRating(oTarget);
|
||||
}
|
||||
|
||||
// For use against them evil pests! Top - one use only anyway.
|
||||
if(GetHasFeat(FEAT_SMITE_EVIL) && GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL &&
|
||||
relativeChallenge <= 2.0)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_SMITE_EVIL);
|
||||
return;
|
||||
}
|
||||
if(GetHasFeat(FEAT_SMITE_GOOD) && GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD &&
|
||||
relativeChallenge <= 2.0)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_SMITE_GOOD);
|
||||
return;
|
||||
}
|
||||
|
||||
// * only the playable races have whirlwind attack
|
||||
// * Attempt to Use Whirlwind Attack
|
||||
if (GetHasFeat(FEAT_WHIRLWIND_ATTACK) && GetOKToWhirl(OBJECT_SELF))
|
||||
{
|
||||
int iAttackThreshold;
|
||||
if (GetCurrentHitPoints(oTarget) <= (GetMeleeAttackBonus(OBJECT_SELF, oRightWeapon, oTarget) + 5))
|
||||
{
|
||||
// a single hit is likely to kill target, check if any other targets are available
|
||||
iAttackThreshold = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set number of whirlwind targets needed equal to the number of attacks per round
|
||||
iAttackThreshold = GetBaseAttackBonus(OBJECT_SELF);
|
||||
if (GetHitDice(OBJECT_SELF) > 20)
|
||||
{
|
||||
iAttackThreshold -= GetHitDice(OBJECT_SELF) / 2;
|
||||
}
|
||||
iAttackThreshold = (iAttackThreshold + 4) / 5;
|
||||
}
|
||||
float fThresholdDistance;
|
||||
int iSizeThreshold;
|
||||
if (GetHasFeat(FEAT_IMPROVED_WHIRLWIND))
|
||||
{
|
||||
fThresholdDistance = 10.0;
|
||||
iSizeThreshold = CREATURE_SIZE_HUGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fThresholdDistance = 3.0;
|
||||
iSizeThreshold = CREATURE_SIZE_MEDIUM;
|
||||
}
|
||||
int enemyIndex = 1;
|
||||
object oTestTarget = GetNearestEnemy(OBJECT_SELF, enemyIndex++);
|
||||
while (GetIsObjectValid(oTestTarget))
|
||||
{
|
||||
if ((GetDistanceToObject(oTestTarget) <= fThresholdDistance) &&
|
||||
(GetCreatureSize(oTestTarget) <= iSizeThreshold))
|
||||
{
|
||||
--iAttackThreshold;
|
||||
if (iAttackThreshold <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
oTestTarget = GetNearestEnemy(OBJECT_SELF, enemyIndex++);
|
||||
}
|
||||
// Jug_Debug(GetName(OBJECT_SELF) + " num attacks " + IntToString((GetBaseAttackBonus(OBJECT_SELF) + 1) / 5) + " count is " + IntToString(iAttackThreshold));
|
||||
if (iAttackThreshold <= 0)
|
||||
{
|
||||
UseCombatAttack(OBJECT_SELF, FEAT_WHIRLWIND_ATTACK);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO update for HotU, dwarven defender (is same as barb rage?)
|
||||
if (relativeChallenge <= 2.0 && TryKiDamage(oTarget))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (d6() == 1 && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT, OBJECT_SELF) && (iNewBAB >= iAC))
|
||||
{
|
||||
int bHasQuiveringPalm = GetHasFeat(FEAT_QUIVERING_PALM);
|
||||
int bHasStunningFist = GetHasFeat(FEAT_STUNNING_FIST);
|
||||
int bHasSAP = GetHasFeat(FEAT_SAP);
|
||||
int bHasCalledShot = GetHasFeat(FEAT_CALLED_SHOT) && d3() == 1;
|
||||
if ((bHasQuiveringPalm || bHasStunningFist || bHasSAP || bHasCalledShot) &&
|
||||
relativeChallenge <= 2.0 &&
|
||||
(GetCharacterLevel(OBJECT_SELF) / 2 + 10 + GetAbilityModifier(ABILITY_WISDOM) >=
|
||||
GetFortitudeSavingThrow(oTarget) + 5 + Random(15)))
|
||||
{
|
||||
if(!GetIsDisabled(oTarget))
|
||||
{
|
||||
if (bHasQuiveringPalm && !GetIsObjectValid(oRightWeapon))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_QUIVERING_PALM);
|
||||
return;
|
||||
}
|
||||
if (bHasStunningFist)
|
||||
{
|
||||
int iMod = iNewBAB;
|
||||
if (GetIsObjectValid(oRightWeapon) || (GetLevelByClass(CLASS_TYPE_MONK) == 0))
|
||||
{
|
||||
iMod -= 4;
|
||||
}
|
||||
if (iMod >= iAC)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_STUNNING_FIST);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// OK, not for PCs, but may be on an NPC. -4 Attack. Above the one below.
|
||||
if(bHasSAP)
|
||||
{
|
||||
if((iNewBAB - 4) >= iAC)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_SAP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (bHasCalledShot)
|
||||
{
|
||||
// At a -2 to hit, this can disarm the arms or legs...speed or attack bonus
|
||||
if(((iNewBAB - 2) >= iAC) && !GetHasFeatEffect(FEAT_CALLED_SHOT, oTarget))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_CALLED_SHOT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bHasImprovedKnockdown = GetHasFeat(FEAT_IMPROVED_KNOCKDOWN);
|
||||
if((bHasImprovedKnockdown || GetHasFeat(FEAT_KNOCKDOWN)) &&
|
||||
!GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN, OBJECT_SELF) &&
|
||||
!GetHasFeatEffect(FEAT_KNOCKDOWN, oTarget) &&
|
||||
!GetHasFeatEffect(FEAT_IMPROVED_KNOCKDOWN, oTarget))
|
||||
{
|
||||
// By far the BEST feat to use - knocking them down lets you freely attack them!
|
||||
// These return 1-5, based on size.
|
||||
int iOurSize = GetCreatureSize(OBJECT_SELF);
|
||||
int iTheirSize = GetCreatureSize(oTarget);
|
||||
if (bHasImprovedKnockdown)
|
||||
{
|
||||
iOurSize++;
|
||||
}
|
||||
int bUse = iOurSize > iTheirSize;
|
||||
if (!bUse && ((iOurSize + 1) >= iTheirSize))
|
||||
{
|
||||
int iMod = iNewBAB - 4;
|
||||
// check if one size larger
|
||||
if (iOurSize != iTheirSize)
|
||||
{
|
||||
iMod -= 4;
|
||||
}
|
||||
if(iMod >= iAC)
|
||||
{
|
||||
bUse = iMod > GetSkillRank(SKILL_DISCIPLINE, oTarget);
|
||||
}
|
||||
}
|
||||
if(bUse)
|
||||
{
|
||||
UseCombatAttack(oTarget, bHasImprovedKnockdown ? FEAT_IMPROVED_KNOCKDOWN : FEAT_KNOCKDOWN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// start using expertise if have under 50% hit points
|
||||
if (GetPercentageHPLoss(OBJECT_SELF) < 50 &&
|
||||
(GetHasFeat(FEAT_EXPERTISE) || GetHasFeat(FEAT_IMPROVED_EXPERTISE)))
|
||||
{
|
||||
// get estimation of opponent attack vs. my AC
|
||||
int iMyAC = GetAC(OBJECT_SELF);
|
||||
int iTargetsBAB = GetBaseAttackBonus(oTarget) + 5 + d4(2) + GetAttackBonus(oTarget, OBJECT_SELF);
|
||||
|
||||
if(GetHasFeat(FEAT_IMPROVED_EXPERTISE) && (iTargetsBAB - 5) >= iMyAC)
|
||||
{
|
||||
UseCombatAttack(oTarget, -1, ACTION_MODE_IMPROVED_EXPERTISE);
|
||||
return;
|
||||
}
|
||||
if(iTargetsBAB >= iMyAC)
|
||||
{
|
||||
UseCombatAttack(oTarget, -1, ACTION_MODE_EXPERTISE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Only use parry on an active melee attacker, and
|
||||
// only if our parry skill > our AC - 10
|
||||
// JE, Apr.14,2004: Bugfix to make this actually work. Thanks to the message board
|
||||
// members who investigated this.
|
||||
if (GetSkillRank(SKILL_PARRY) > (GetAC(OBJECT_SELF) - 10))
|
||||
{
|
||||
object oTargetRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
|
||||
if (GetAttackTarget(oTarget) == OBJECT_SELF &&
|
||||
GetIsObjectValid(oTargetRightWeapon) &&
|
||||
!GetWeaponRanged(oTargetRightWeapon))
|
||||
{
|
||||
int iAttackChance = GetBaseAttackBonus(oTarget) + GetAttackBonus(oTarget, OBJECT_SELF) - GetAC(OBJECT_SELF);
|
||||
if ((iAttackChance > -20) && (GetPercentageHPLoss(OBJECT_SELF) < 65))
|
||||
{
|
||||
object oNearestFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if (GetIsObjectValid(oNearestFriend) && GetDistanceToObject(oNearestFriend) <= 5.0)
|
||||
{
|
||||
UseCombatAttack(oTarget, -1, ACTION_MODE_PARRY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Auldar: Give 10% chance to Taunt if target is within 3.5 meters and is a challenge, if Skill points have been
|
||||
// spent in Taunt skill indicating intention to use, and a taunt isn't in effect
|
||||
//
|
||||
if ((d10 () == 1) && ((relativeChallenge <= 2.0) ||
|
||||
(GetCharacterLevel(oTarget) > (GetCharacterLevel(OBJECT_SELF) - 2)))
|
||||
&& (GetDistanceToObject(oTarget) <= 3.5))
|
||||
{
|
||||
// Auldar: Adding a check for the Taunt skill, and ensuring that noone with ONLY a CHA mod to
|
||||
// Taunt will use the skill.
|
||||
// This confirms that some points are spent in the skill indicating an intention for the NPC to use them.
|
||||
// Also using 69MEH69's idea to check for a negative modifier so we don't subtract a negative number (ie add)
|
||||
// to the skill check
|
||||
if ((GetSkillRank(SKILL_TAUNT, OBJECT_SELF, TRUE) > 0) && ((GetSkillRank(SKILL_TAUNT) + 5 + d4(2)) > GetSkillRank(SKILL_CONCENTRATION, oTarget)))
|
||||
{
|
||||
ActionUseSkill(SKILL_TAUNT, oTarget);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(d4() == 1 && (GetHasFeat(FEAT_IMPROVED_DISARM) || GetHasFeat(FEAT_DISARM)) &&
|
||||
GetIsCreatureDisarmable(oTarget) &&
|
||||
((GetIsObjectValid(oRightWeapon) && !GetWeaponRanged(oRightWeapon)) || !GetIsObjectValid(oRightWeapon)))
|
||||
{
|
||||
object oTargetRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
|
||||
if (GetIsObjectValid(oTargetRightWeapon) && !GetWeaponRanged(oTargetRightWeapon))
|
||||
{
|
||||
int iWeaponSize;
|
||||
if (GetIsObjectValid(oRightWeapon))
|
||||
{
|
||||
iWeaponSize = GetMeleeWeaponSize(oRightWeapon);
|
||||
}
|
||||
else
|
||||
{
|
||||
iWeaponSize = GetCreatureSize(OBJECT_SELF);
|
||||
}
|
||||
int iTargetWeaponSize = GetMeleeWeaponSize(oTargetRightWeapon);
|
||||
|
||||
// No AOO, and only a -4 penalty to hit.
|
||||
if(GetHasFeat(FEAT_IMPROVED_DISARM))
|
||||
{
|
||||
// Apply weapon size penalites/bonuses to check - Use right weapons.
|
||||
int iMod = iWeaponSize - iTargetWeaponSize;
|
||||
if(iMod != 0) iMod += (iMod * 4);
|
||||
if(((iNewBAB - 4 + iMod) >= iAC) && (iMod > GetSkillRank(SKILL_DISCIPLINE, oTarget)))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_IMPROVED_DISARM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Provokes an AOO. Improved does not, but this is -6, and bonuses depend on weapons used (sizes)
|
||||
else if(d2() == 1)
|
||||
{
|
||||
// Apply weapon size penalites/bonuses to check - Use right weapons.
|
||||
int iMod = iWeaponSize - iTargetWeaponSize;
|
||||
if(iMod != 0) iMod += (iMod * 4);
|
||||
if(((iNewBAB - 6 + iMod) >= iAC) && (iMod > GetSkillRank(SKILL_DISCIPLINE, oTarget)))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_DISARM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This activates an extra attack, at -2 to hit. Of course, only unarmed and kama
|
||||
if(GetHasFeat(FEAT_FLURRY_OF_BLOWS) && ((iNewBAB - 2) >= iAC) && (!GetIsObjectValid(oRightWeapon) ||
|
||||
(GetBaseItemType(oRightWeapon) == BASE_ITEM_KAMA)))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_FLURRY_OF_BLOWS);
|
||||
return;
|
||||
}
|
||||
// -10 to hit - make sure by extra 5
|
||||
if(GetHasFeat(FEAT_IMPROVED_POWER_ATTACK) && ((iNewBAB - 15) >= iAC))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_IMPROVED_POWER_ATTACK);
|
||||
return;
|
||||
}
|
||||
// is a -5 to hit - make sure by extra 5
|
||||
if(GetHasFeat(FEAT_POWER_ATTACK) && ((iNewBAB - 10) >= iAC))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_POWER_ATTACK);
|
||||
return;
|
||||
}
|
||||
// extra damage with only one attack
|
||||
if (GetHasFeat(FEAT_DIRTY_FIGHTING) && GetBaseAttackBonus(OBJECT_SELF) < 8)
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_DIRTY_FIGHTING);
|
||||
return;
|
||||
}
|
||||
|
||||
UseCombatAttack(oTarget);
|
||||
}
|
||||
|
||||
|
||||
void ActionContinueMeleeAttack(object oTarget, float fThresholdDistance, int iCreatureType, int iCallNumber)
|
||||
{
|
||||
if (GetLocalInt(OBJECT_SELF, "UseRangedWeapons"))
|
||||
{
|
||||
if (!EquipRangedWeapon(oTarget, iCreatureType == 1, iCallNumber))
|
||||
{
|
||||
ActionDoCommand(ActionContinueMeleeAttack(oTarget, fThresholdDistance, iCreatureType, iCallNumber + 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!EquipMeleeWeapons(oTarget, iCreatureType == 1, iCallNumber))
|
||||
{
|
||||
ActionDoCommand(ActionContinueMeleeAttack(oTarget, fThresholdDistance, iCreatureType, iCallNumber + 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
HenchDoTalentMeleeAttack(oTarget, fThresholdDistance, iCreatureType);
|
||||
}
|
||||
|
||||
|
||||
// MELEE ATTACK OTHERS
|
||||
/*
|
||||
ISSUE 1: Talent Melee Attack should set the Last Spell Used to 0 so that melee casters can use
|
||||
a single special ability.
|
||||
|
||||
Auldar: Made changes here to use Taunt when appropriate as well as more accurate calculations for
|
||||
To-Hit vs Target AC.
|
||||
|
||||
Tony: Made major changes in using attack feats. Heavily modified code from Jasperre.
|
||||
*/
|
||||
|
||||
int HenchTalentMeleeAttack(object oIntruder, float fThresholdDistance, int iMeleeAttackers, int iCreatureType, int bPolymorphed)
|
||||
{
|
||||
object oTarget = oIntruder;
|
||||
|
||||
if (iCreatureType == 0)
|
||||
{
|
||||
MonsterBattleCry();
|
||||
}
|
||||
else if (iCreatureType == 1)
|
||||
{
|
||||
HenchBattleCry();
|
||||
}
|
||||
|
||||
// allow sneak attack to use other feats
|
||||
if(GetHasFeat(FEAT_SNEAK_ATTACK))
|
||||
{
|
||||
//Sneak Attack Flanking attack
|
||||
float fRange = iMeleeAttackers ? 3.5 : /* bRangedWeapon*/ TRUE ? 50.0 : 5.0;
|
||||
int iEnemyAC, iAC = 100;
|
||||
object oRealMaster = GetRealMaster();
|
||||
int bEnemyMaster = FALSE;
|
||||
object oLastSneakTarget = GetLocalObject(OBJECT_SELF, "LastSneakTarget");
|
||||
object oAttackTarget;
|
||||
int nCnt = 1;
|
||||
object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
object oBest = OBJECT_INVALID;
|
||||
while(GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= fRange)
|
||||
{
|
||||
if(!GetPlotFlag(oEnemy) && !GetIsImmune(oEnemy, IMMUNITY_TYPE_SNEAK_ATTACK, OBJECT_SELF))
|
||||
{
|
||||
oAttackTarget = GetAttackTarget(oEnemy);
|
||||
if(oAttackTarget != OBJECT_SELF)
|
||||
{
|
||||
if (oEnemy == oLastSneakTarget)
|
||||
{
|
||||
oBest = oEnemy;
|
||||
break;
|
||||
}
|
||||
iEnemyAC = GetAC(oEnemy);
|
||||
if (oAttackTarget == oRealMaster)
|
||||
{
|
||||
if (!bEnemyMaster)
|
||||
{
|
||||
bEnemyMaster = TRUE;
|
||||
iAC = iEnemyAC;
|
||||
oBest = oEnemy;
|
||||
}
|
||||
else if(iAC > iEnemyAC)
|
||||
{
|
||||
iAC = iEnemyAC;
|
||||
oBest = oEnemy;
|
||||
}
|
||||
}
|
||||
else if(iAC > iEnemyAC)
|
||||
{
|
||||
iAC = iEnemyAC;
|
||||
oBest = oEnemy;
|
||||
}
|
||||
}
|
||||
}
|
||||
nCnt++;
|
||||
oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
}
|
||||
|
||||
if (GetIsObjectValid(oBest))
|
||||
{
|
||||
oTarget = oBest;
|
||||
SetLocalObject(OBJECT_SELF, "LastSneakTarget", oBest);
|
||||
}
|
||||
}
|
||||
|
||||
if (!HenchEquipAppropriateWeapons(oTarget, fThresholdDistance, iCreatureType == 1, bPolymorphed))
|
||||
{
|
||||
ActionDoCommand(ActionContinueMeleeAttack(oTarget, fThresholdDistance, iCreatureType, 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
HenchDoTalentMeleeAttack(oTarget, fThresholdDistance, iCreatureType);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
Reference in New Issue
Block a user