Here's our function set for List Ab. It includes a lot of custom hacks like Spell Immunity(TRUE_STRIKE), which is how we add stacking ab over 20, but it should still help illuminate the various checks you have to do. If memory serves it still doesn't calcluate monk glove ab accurately - that's been on the todo for a while now.
/*
* This method returns the size of a weaponBaseType
* nWeaponBaseType = the base type id of a weapon.
* returns WSIZE_TINY = 1 or WSIZE_SMALL = 2 or WSIZE_MEDIUM = 3 or WSIZE_LARGE = 4 or WSIZE_HUGE = 5
*/
int GetWeaponSize(int nWeapBaseType){
return StringToInt(Get2DAString("BASEITEMS","WeaponSize",nWeapBaseType));
}
/*
* This method checks if the weapon is considered "small" for the oPC
* If this is the case, the method returns 2 , otherwise 0 is returned.
* - oPC = The toon
* - oWeaponOffHand = The weapon
*/
int GetIsOffHandWeaponSmallModif(object oPC, object oWeaponOffHand){
int nCSize = GetCreatureSize(oPC);
int nWeaponBaseItem = GetBaseItemType(oWeaponOffHand);
int nWSize = GetWeaponSize(nWeaponBaseItem);
int nRetVal = 0;
switch (nWSize) {
case 1: if(nCSize > CREATURE_SIZE_TINY) nRetVal = 2; break;
case 2: if(nCSize > CREATURE_SIZE_SMALL) nRetVal = 2; break;
case 3: if(nCSize > CREATURE_SIZE_MEDIUM) nRetVal = 2; break;
case 4: if(nCSize > CREATURE_SIZE_LARGE) nRetVal = 2; break;
case 5: if(nCSize > CREATURE_SIZE_HUGE) nRetVal = 2; break;
}
return nRetVal;
}
/*
* This method returns the maximul weapon enhancement that is on a weapon (including the fixed weapon enhancement)
* - oPC = The toon
* - oWeapon = The weapon
*/
int getWeaponEnhancementBonus(object oPC,object oWeapon){
itemproperty ip = GetFirstItemProperty(oWeapon);
int nType, nFound, nReturn;
while (GetIsItemPropertyValid(ip)) {
nType = GetItemPropertyType(ip);
if (nType == ITEM_PROPERTY_ENHANCEMENT_BONUS ||
nType == ITEM_PROPERTY_ATTACK_BONUS) {
nFound = GetItemPropertyCostTableValue(ip);
if (nFound > nReturn)
nReturn = nFound;
}
ip = GetNextItemProperty(oWeapon);
}
return nReturn;
}
/*
* This method calculates the dual wielding modifier
* - oPC = The toon
* - nSlot = INVENTORY_SLOT_RIGHTHAND or INVENTORY_SLOT_LEFTHAND
* - nOffSmall =The amount that can be substracted from the dualing penalties (Currently only should be 0 or 2 for small weapons)
*/
int GetDualWieldingModifier(object oPC,int nSlot, int nOffSmall){
int nTotal;
int nTwoWeaponFight, nAmbidexTerity;
if(nSlot == INVENTORY_SLOT_RIGHTHAND){
nTotal = -6 + nOffSmall;
}
else if (nSlot == INVENTORY_SLOT_LEFTHAND){
nTotal = -10 + nOffSmall;
if(GetHasFeat(FEAT_AMBIDEXTERITY,oPC)){
nTotal = nTotal + 4;
}
}
if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING,oPC)){
nTotal = nTotal +2;
}
return nTotal;
}
// This method finds all the MAGICAL AB increases on a toon.
// oPC = The toon
// returns the amount
// Stores the "result-strings" (for the feedback in the combat log) in a Local string on the oPC with name = gol_tmp_ab
// DO NOT FORGET TO DELETE TEMPSTRING!
int GetMagicABIncrease(object oPC){
int nAmount = 0;
string sResultStrings;
string sName;
effect eEff;
for (eEff = GetFirstEffect(oPC); GetIsEffectValid(eEff); eEff = GetNextEffect(oPC)) {
if (GetEffectType(eEff) == EFFECT_TYPE_ATTACK_INCREASE) {
nAmount += GetEffectInteger(eEff, 0);
int nEffectId = GetEffectSpellId(eEff);
if(nEffectId == HGEFFECT_BARDSONG_AB_00 ||
nEffectId == HGEFFECT_BARDSONG_AB_01 ||
nEffectId == HGEFFECT_BARDSONG_AB_03 ||
nEffectId == HGEFFECT_BARDSONG_AB_04 ||
nEffectId == HGEFFECT_BARDSONG_AB_05 ||
nEffectId == HGEFFECT_BARDSONG_AB_06 ||
nEffectId == HGEFFECT_BARDSONG_AB_07){
sName = "Bard Song";
}
else{
sName = SFGetSpellName(GetEffectSpellId(eEff));
}
if(GetStringLength(sName) <= 0){
sName = "generic";
}
sResultStrings += (COLOR_GREEN +" "+ sName + " : +"+IntToString(GetEffectInteger(eEff, 0))+"\\n");
}
}
SetLocalString(oPC,"gol_tmp_ab",sResultStrings);
return nAmount;
}
/*
* This method Lists the attack bonus for a weapon
* - oPC = The actual toon
* - oWeapon = The weapon
* - nSlot = INVENTORY_SLOT_RIGHTHAND or INVENTORY_SLOT_LEFTHAND
* - nDualing = If the toon is dualing melee weapons, make this 1
* - nOffSmall = The amount that can be substracted from the dualing penalties (Currently only can be 0 or 2 for small weapons)
*/
string ListAttackBonusForWeapon (object oPC, object oWeapon, int nSlot, int nDualing, int nOffSmall) {
/* include +20 magical bonus always */
int nBAB = GetBaseAttackBonus(oPC), nHD = GetHitDice(oPC);
int nEBAB, nLBAB, nWF, nGWF, nEWF, nLWF, nPWF, nEP, nCW, nWM, nAA, nAbil, nDual, nSize, nMagicIncrease, nWeaponModifs ,nOther;
string sTempIncMagicAbStrings,sTempDecMagicAbStrings;
if(nDualing > 0){
nDual = GetDualWieldingModifier(oPC,nSlot,nOffSmall);
}
if (nHD == 40) {
nBAB -= 30;
nEBAB = 10;
nLBAB = GetLocalInt(oPC, "LegendaryBAB");
} else if (nHD == 64) {
nBAB -= 50;
nEBAB = 50;
} else if (nHD > 20) {
nEBAB = (nHD - 19) / 2;
nBAB -= nEBAB;
}
int nBaseItem = BASE_ITEM_GLOVES;
if (GetIsObjectValid(oWeapon))
nBaseItem = GetBaseItemType(oWeapon);
nEP = ListAttackBonusABFeat(oPC, FEAT_EPIC_PROWESS, 1);
nWF = ListAttackBonusABFeat(oPC, GetWeaponFocusFeat(nBaseItem), 1);
nGWF = ListAttackBonusABFeat(oPC, GetWeaponGreaterFocusFeat(nBaseItem), 1);
nEWF = ListAttackBonusABFeat(oPC, GetWeaponEpicFocusFeat(nBaseItem), 2);
nLWF = ListAttackBonusABFeat(oPC, GetWeaponLegendaryFocusFeat(nBaseItem), (nEP ? 3 : 2));
nPWF = 0;
nAbil = GetAttackBonusAdjustment(oPC, oWeapon, GetItemIsRangedWeapon(oWeapon)) - (nGWF + nLWF);
nSize = GetCreatureSizeACModifier(oPC);
if (nBaseItem != BASE_ITEM_GLOVES) {
nCW = GetSkillRank(SKILL_CRAFT_WEAPON, oPC) / 40;
nAbil -= nCW;
}
int nWMLevel = GetLevelByclass(class_TYPE_WEAPON_MASTER, oPC);
if (nWMLevel >= 5 && ListAttackBonusABFeat(oPC, GetWeaponOfChoiceFeat(nBaseItem), 1) > 0) {
nWM++;
if (nWMLevel >= 10) {
nWM += (nWMLevel - 10) / 3;
if (GetIsPC(oPC)) {
nWM++;
nAbil--;
if (nWMLevel == 29) {
nAbil--;
nWM++;
} else if (nWMLevel == 30) {
nWM += 3;
nAbil -= 3;
}
}
}
}
if (GetHasSpellImmunity(SPELL_TRUE_STRIKE, oPC)) {
int nTrue = 0;
effect eEff;
for (eEff = GetFirstEffect(oPC); GetIsEffectValid(eEff); eEff = GetNextEffect(oPC)) {
if (GetEffectType(eEff) == EFFECT_TYPE_SPELL_IMMUNITY &&
GetEffectInteger(eEff, 0) == SPELL_TRUE_STRIKE) {
int nTrueBuff = GetEffectInteger(eEff, 1);
if (nTrueBuff > nTrue)
nTrue = nTrueBuff;
}
}
nTrue -= nWM;
if (nTrue > 0) {
nOther += nTrue;
nAbil -= nTrue;
}
}
if (GetBaseItemType(oWeapon) == BASE_ITEM_SHORTBOW || GetBaseItemType(oWeapon) == BASE_ITEM_LONGBOW)
nAA = (GetLevelByclass(class_TYPE_ARCANE_ARCHER, oPC) + 1) / 2;
nMagicIncrease = GetMagicABIncrease(oPC);
if(nMagicIncrease >0){
sTempIncMagicAbStrings = GetLocalString(oPC,"gol_tmp_ab");
}
DeleteLocalString(oPC,"gol_tmp_ab");
nWeaponModifs = getWeaponEnhancementBonus(oPC,oWeapon);
int nMagicTotal = nMagicIncrease + nWeaponModifs;
int nMagicMax = 20;
if(nMagicTotal > nMagicMax)
nMagicTotal = nMagicMax;
if(nMagicTotal < -20)
nMagicTotal = -20;
int nAB = nBAB + nEBAB + nLBAB + nWF + nGWF + nEWF + nLWF + nPWF + nEP + nCW + nWM + nAA + nAbil + nDual + nSize + nOther + nMagicTotal;
string sMessage = COLOR_WHITE;
if(nAB>= 0){
sMessage += "(+";
}
else{
sMessage += "(";
}
sMessage += IntToString(nAB) + ")\\n";
if (nBAB > 0)
sMessage += COLOR_PURPLE + " BAB: " + COLOR_LT_PURPLE + IntToString(nBAB) + "\\n";
if (nEBAB > 0)
sMessage += COLOR_PURPLE + " EBAB: " + COLOR_LT_PURPLE + IntToString(nEBAB) + "\\n";
if (nLBAB > 0)
sMessage += COLOR_PURPLE + " LBAB: " + COLOR_LT_PURPLE + IntToString(nLBAB) + "\\n";
if (nAbil != 0)
sMessage += COLOR_PURPLE + " Ability: " + COLOR_LT_PURPLE + IntToString(nAbil) + "\\n";
if (nWF > 0)
sMessage += COLOR_PURPLE + " Weapon Focus: " + COLOR_LT_PURPLE + IntToString(nWF) + "\\n";
if (nGWF > 0)
sMessage += COLOR_PURPLE + " Greater Weapon Focus: " + COLOR_LT_PURPLE + IntToString(nGWF) + "\\n";
if (nEWF > 0)
sMessage += COLOR_PURPLE + " Epic Weapon Focus: " + COLOR_LT_PURPLE + IntToString(nEWF) + "\\n";
if (nLWF > 0)
sMessage += COLOR_PURPLE + " Legendary Weapon Focus: " + COLOR_LT_PURPLE + IntToString(nLWF) + "\\n";
if (nPWF > 0)
sMessage += COLOR_PURPLE + " Paragon Weapon Focus: " + COLOR_LT_PURPLE + IntToString(nPWF) + "\\n";
if (nEP > 0)
sMessage += COLOR_PURPLE + " Epic Prowess: " + COLOR_LT_PURPLE + IntToString(nEP) + "\\n";
if (nCW > 0)
sMessage += COLOR_PURPLE + " Craft Weapon: " + COLOR_LT_PURPLE + IntToString(nCW) + "\\n";
if (nWM > 0)
sMessage += COLOR_PURPLE + " Weapon Master: " + COLOR_LT_PURPLE + IntToString(nWM) + "\\n";
if (nAA > 0)
sMessage += COLOR_PURPLE + " Arcane Archer: " + COLOR_LT_PURPLE + IntToString(nAA) + "\\n";
if (nDual != 0)
sMessage += COLOR_PURPLE + " Dual Wielding: " + COLOR_LT_PURPLE + IntToString(nDual) + "\\n";
if (nSize != 0)
sMessage += COLOR_PURPLE + " Size: " + COLOR_LT_PURPLE + IntToString(nSize) + "\\n";
if (nOther != 0)
sMessage += COLOR_PURPLE + " Other: " + COLOR_LT_PURPLE + IntToString(nOther) + "\\n";
if(nMagicTotal != 0){
sMessage += COLOR_PURPLE + " Magic: " + COLOR_LT_PURPLE + IntToString(nMagicTotal) + COLOR_LT_PURPLE + " (Max = +"+IntToString(nMagicMax)+")\\n";
if(nMagicIncrease > 0){
sMessage += COLOR_BLUE + " -General inc : +" + COLOR_BLUE + IntToString(nMagicIncrease) + "\\n";
sMessage += sTempIncMagicAbStrings;
}
if(nWeaponModifs > 0){
sMessage += COLOR_BLUE + " -Weapon modifs : +" + COLOR_BLUE + IntToString(nWeaponModifs) + "\\n";
}
}
return (sMessage + "\\n");
}
/*
* This method lists the attack bonus (!List ab command) of a toon
* -oTarget = The target we want the attack bonus for
* -oPC = The player character
*
*/
void ListAttackBonus (object oTarget, object oPC) {
string sMessage;
object oWeapon;
int nSmall = 0;
int nDual = 0;
if (oTarget != oPC)
sMessage = COLOR_WHITE + "Attack bonus for " + GetName(oTarget) + ":\\n";
else
sMessage = COLOR_WHITE + "Attack bonus:\\n";
object oWeaponR = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
object oWeaponL = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
if( GetIsObjectValid(oWeaponR) && GetItemIsMeleeWeapon(oWeaponR) && GetIsObjectValid(oWeaponL) && GetItemIsMeleeWeapon(oWeaponL)){
// DUAL WIELDING
nSmall = GetIsOffHandWeaponSmallModif(oPC,oWeaponL);
nDual = 1;
}
if (GetIsObjectValid(oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget)))
sMessage += COLOR_GOLD + "Right Hand: " + COLOR_LT_YELLOW + GetName(oWeapon) + " ";
else
sMessage += COLOR_GOLD + "Right Hand: " + COLOR_LT_YELLOW + "(unarmed) ";
sMessage += COLOR_ORANGE + "(" + IntToString(GetCriticalHitRange(oTarget, FALSE)) + "-20/x" +
IntToString(GetCriticalHitMultiplier(oTarget, FALSE)) + ") ";
sMessage += ListAttackBonusForWeapon(oTarget, oWeapon, INVENTORY_SLOT_RIGHTHAND,nDual,nSmall);
if (GetIsObjectValid(oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget)) &&
GetItemIsMeleeWeapon(oWeapon)) {
sMessage += COLOR_GOLD + "Left Hand: " + COLOR_LT_YELLOW + GetName(oWeapon) + " ";
sMessage += COLOR_ORANGE + "(" + IntToString(GetCriticalHitRange(oTarget, TRUE)) + "-20/x" +
IntToString(GetCriticalHitMultiplier(oTarget, TRUE)) + ") ";
sMessage += ListAttackBonusForWeapon(oTarget, oWeapon, INVENTORY_SLOT_LEFTHAND,nDual,nSmall);
}
SendChatLogMessage(oPC, sMessage + COLOR_END, oPC, 5);
}
Funky