Ok, from the answers I see, that there is no easy way. So I created a prototype. It’s some 300 lines of ugly scripting, but it seams to work well. I post it her, just in case, somebody is interrested.
/* Script: zz_ab
Estimate the final attack bonus of a creature.
(right hand, 1st attack)
Any racial- or alignmentbased bonus is neglected.
(i.e. a “+5 vs. giants” which comes from a weapon-property
[sling] doesnt find it’s way into the calculation)
Needs an item which could be activated on a target and
launches the script via tagbased scripting. */
int GetPropertyValue (itemproperty p, string s)
{
string resref;
string label = “99”;
int t = GetItemPropertyType(p);
int ct = GetItemPropertyCostTable(p);
int ctv = GetItemPropertyCostTableValue (p);
if (ct != 0)
{
resref = Get2DAString(“iprp_Costtable”, “Name”, ct);
label = Get2DAString(resref, “Value”, ctv);
}
return StringToInt (label);
}
int GetIs1HWeapon(object oItem)
{
if (!GetIsObjectValid(oItem)) return FALSE;
int nItem = GetBaseItemType(oItem);
if((nItem == BASE_ITEM_BASTARDSWORD) ||
(nItem == BASE_ITEM_BATTLEAXE) ||
(nItem == BASE_ITEM_HANDAXE) ||
(nItem == BASE_ITEM_KAMA) ||
(nItem == BASE_ITEM_KATANA) ||
(nItem == BASE_ITEM_KUKRI) ||
(nItem == BASE_ITEM_LONGSWORD) ||
(nItem == BASE_ITEM_SCIMITAR) ||
(nItem == BASE_ITEM_SICKLE) ||
(nItem == BASE_ITEM_CLUB) ||
(nItem == BASE_ITEM_DAGGER) ||
(nItem == BASE_ITEM_LIGHTFLAIL) ||
(nItem == BASE_ITEM_LIGHTHAMMER) ||
(nItem == BASE_ITEM_LIGHTMACE) ||
(nItem == BASE_ITEM_MORNINGSTAR) ||
(nItem == BASE_ITEM_RAPIER) ||
(nItem == BASE_ITEM_WHIP) ||
(nItem == BASE_ITEM_SHORTSWORD) ||
(nItem == BASE_ITEM_WARHAMMER) ||
(nItem == BASE_ITEM_DWARVENWARAXE)) return TRUE;
return FALSE;
}
int GetIsFinesseWeapon(int iwt)
{
if((iwt == BASE_ITEM_DAGGER) ||
(iwt == BASE_ITEM_HANDAXE) ||
(iwt == BASE_ITEM_KAMA) ||
(iwt == BASE_ITEM_KUKRI) ||
(iwt == BASE_ITEM_LIGHTHAMMER) ||
(iwt == BASE_ITEM_LIGHTMACE) ||
(iwt == BASE_ITEM_RAPIER) ||
(iwt == BASE_ITEM_SHORTSWORD) ||
(iwt == BASE_ITEM_SICKLE) ||
(iwt == BASE_ITEM_WHIP) ||
(iwt == BASE_ITEM_GLOVES) ||
(iwt == BASE_ITEM_INVALID)) return TRUE;
return FALSE;
}
int GetIsRangedWeapon(int iwt)
{
if((iwt == BASE_ITEM_DART) ||
(iwt == BASE_ITEM_HEAVYCROSSBOW) ||
(iwt == BASE_ITEM_LIGHTCROSSBOW) ||
(iwt == BASE_ITEM_LONGBOW) ||
(iwt == BASE_ITEM_SHORTBOW) ||
(iwt == BASE_ITEM_SHURIKEN) ||
(iwt == BASE_ITEM_SLING) ||
(iwt == BASE_ITEM_THROWINGAXE)) return TRUE;
return FALSE;
}
int GetIsSmallMeleeWeapon(object oItem)
{
if (!GetIsObjectValid(oItem)) return FALSE;
int nItem = GetBaseItemType(oItem);
if((nItem == BASE_ITEM_HANDAXE) ||
(nItem == BASE_ITEM_KUKRI) ||
(nItem == BASE_ITEM_DAGGER) ||
(nItem == BASE_ITEM_LIGHTHAMMER) ||
(nItem == BASE_ITEM_LIGHTMACE) ||
(nItem == BASE_ITEM_SHORTSWORD)) return TRUE;
return FALSE;
}
struct feats {int hf; int ef; int wc; int aa;};
struct feats Bonus (object t, int hf, int ef, int wc = FALSE, int aa = FALSE)
{
struct feats f;
f.hf = GetHasFeat (hf, t);
f.ef = GetHasFeat (ef, t);
if (wc != FALSE) f.wc = GetHasFeat (wc, t);
if (aa != FALSE) f.aa = GetLevelByClass (aa, t);
return f;
}
int GetFeatBonus (object t, int i)
{
struct feats f;
int hf, ef, wc;
int b = 0;
if (i == BASE_ITEM_GLOVES || i == BASE_ITEM_INVALID)
f = Bonus (t, FEAT_WEAPON_FOCUS_UNARMED_STRIKE, FEAT_EPIC_WEAPON_FOCUS_UNARMED);
if (i == BASE_ITEM_DAGGER) f = Bonus (t, FEAT_WEAPON_FOCUS_DAGGER, FEAT_EPIC_WEAPON_FOCUS_DAGGER, FEAT_WEAPON_OF_CHOICE_DAGGER);
if (i == BASE_ITEM_HEAVYCROSSBOW) f = Bonus (t, FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW, FEAT_EPIC_WEAPON_FOCUS_HEAVYCROSSBOW);
if (i == BASE_ITEM_LIGHTCROSSBOW) f = Bonus (t, FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW, FEAT_EPIC_WEAPON_FOCUS_LIGHTCROSSBOW);
if (i == BASE_ITEM_LIGHTMACE) f = Bonus (t, FEAT_WEAPON_FOCUS_LIGHT_MACE, FEAT_EPIC_WEAPON_FOCUS_LIGHTMACE, FEAT_WEAPON_OF_CHOICE_LIGHTMACE);
if (i == BASE_ITEM_MORNINGSTAR) f = Bonus (t, FEAT_WEAPON_FOCUS_MORNING_STAR, FEAT_EPIC_WEAPON_FOCUS_MORNINGSTAR, FEAT_WEAPON_OF_CHOICE_MORNINGSTAR);
if (i == BASE_ITEM_QUARTERSTAFF) f = Bonus (t, FEAT_WEAPON_FOCUS_STAFF, FEAT_EPIC_WEAPON_FOCUS_QUARTERSTAFF, FEAT_WEAPON_OF_CHOICE_QUARTERSTAFF);
if (i == BASE_ITEM_SHORTSPEAR) f = Bonus (t, FEAT_WEAPON_FOCUS_SPEAR, FEAT_EPIC_WEAPON_FOCUS_SHORTSPEAR, FEAT_WEAPON_OF_CHOICE_SHORTSPEAR);
if (i == BASE_ITEM_SICKLE) f = Bonus (t, FEAT_WEAPON_FOCUS_SICKLE, FEAT_EPIC_WEAPON_FOCUS_SICKLE, FEAT_WEAPON_OF_CHOICE_SICKLE);
if (i == BASE_ITEM_SLING) f = Bonus (t, FEAT_WEAPON_FOCUS_SLING, FEAT_EPIC_WEAPON_FOCUS_SLING);
if (i == BASE_ITEM_LONGBOW) f = Bonus (t, FEAT_WEAPON_FOCUS_LONGBOW, FEAT_EPIC_WEAPON_FOCUS_LONGBOW, FALSE, CLASS_TYPE_ARCANE_ARCHER);
if (i == BASE_ITEM_SHORTBOW) f = Bonus (t, FEAT_WEAPON_FOCUS_SHORTBOW, FEAT_EPIC_WEAPON_FOCUS_SHORTBOW, FALSE, CLASS_TYPE_ARCANE_ARCHER);
if (i == BASE_ITEM_SHORTSWORD) f = Bonus (t, FEAT_WEAPON_FOCUS_SHORT_SWORD, FEAT_EPIC_WEAPON_FOCUS_SHORTSWORD, FEAT_WEAPON_OF_CHOICE_SHORTSWORD);
if (i == BASE_ITEM_RAPIER) f = Bonus (t, FEAT_WEAPON_FOCUS_RAPIER, FEAT_EPIC_WEAPON_FOCUS_RAPIER, FEAT_WEAPON_OF_CHOICE_RAPIER);
if (i == BASE_ITEM_SCIMITAR) f = Bonus (t, FEAT_WEAPON_FOCUS_SCIMITAR, FEAT_EPIC_WEAPON_FOCUS_SCIMITAR, FEAT_WEAPON_OF_CHOICE_SCIMITAR);
if (i == BASE_ITEM_LONGSWORD) f = Bonus (t, FEAT_WEAPON_FOCUS_LONG_SWORD, FEAT_EPIC_WEAPON_FOCUS_LONGSWORD, FEAT_WEAPON_OF_CHOICE_LONGSWORD);
if (i == BASE_ITEM_GREATSWORD) f = Bonus (t, FEAT_WEAPON_FOCUS_GREAT_SWORD, FEAT_EPIC_WEAPON_FOCUS_GREATSWORD, FEAT_WEAPON_OF_CHOICE_GREATSWORD);
if (i == BASE_ITEM_HANDAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_HAND_AXE, FEAT_EPIC_WEAPON_FOCUS_HANDAXE, FEAT_WEAPON_OF_CHOICE_HANDAXE);
if (i == BASE_ITEM_THROWINGAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_THROWING_AXE, FEAT_EPIC_WEAPON_FOCUS_THROWINGAXE);
if (i == BASE_ITEM_BATTLEAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_BATTLE_AXE, FEAT_EPIC_WEAPON_FOCUS_BATTLEAXE, FEAT_WEAPON_OF_CHOICE_BATTLEAXE);
if (i == BASE_ITEM_GREATAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_GREAT_AXE, FEAT_EPIC_WEAPON_FOCUS_GREATAXE, FEAT_WEAPON_OF_CHOICE_GREATAXE);
if (i == BASE_ITEM_HALBERD) f = Bonus (t, FEAT_WEAPON_FOCUS_HALBERD, FEAT_EPIC_WEAPON_FOCUS_HALBERD, FEAT_WEAPON_OF_CHOICE_HALBERD);
if (i == BASE_ITEM_LIGHTHAMMER) f = Bonus (t, FEAT_WEAPON_FOCUS_LIGHT_HAMMER, FEAT_EPIC_WEAPON_FOCUS_LIGHTHAMMER, FEAT_WEAPON_OF_CHOICE_LIGHTHAMMER);
if (i == BASE_ITEM_LIGHTFLAIL) f = Bonus (t, FEAT_WEAPON_FOCUS_LIGHT_FLAIL, FEAT_EPIC_WEAPON_FOCUS_LIGHTFLAIL, FEAT_WEAPON_OF_CHOICE_LIGHTFLAIL);
if (i == BASE_ITEM_WARHAMMER) f = Bonus (t, FEAT_WEAPON_FOCUS_WAR_HAMMER, FEAT_EPIC_WEAPON_FOCUS_WARHAMMER, FEAT_WEAPON_OF_CHOICE_WARHAMMER);
if (i == BASE_ITEM_HEAVYFLAIL) f = Bonus (t, FEAT_WEAPON_FOCUS_HEAVY_FLAIL, FEAT_EPIC_WEAPON_FOCUS_HEAVYFLAIL, FEAT_WEAPON_OF_CHOICE_HEAVYFLAIL);
if (i == BASE_ITEM_KAMA) f = Bonus (t, FEAT_WEAPON_FOCUS_KAMA, FEAT_EPIC_WEAPON_FOCUS_KAMA, FEAT_WEAPON_OF_CHOICE_KAMA);
if (i == BASE_ITEM_KUKRI) f = Bonus (t, FEAT_WEAPON_FOCUS_KUKRI, FEAT_EPIC_WEAPON_FOCUS_KUKRI, FEAT_WEAPON_OF_CHOICE_KUKRI);
if (i == BASE_ITEM_SHURIKEN) f = Bonus (t, FEAT_WEAPON_FOCUS_SHURIKEN, FEAT_EPIC_WEAPON_FOCUS_SHURIKEN);
if (i == BASE_ITEM_SCYTHE) f = Bonus (t, FEAT_WEAPON_FOCUS_SCYTHE, FEAT_EPIC_WEAPON_FOCUS_SCYTHE, FEAT_WEAPON_OF_CHOICE_SCYTHE);
if (i == BASE_ITEM_KATANA) f = Bonus (t, FEAT_WEAPON_FOCUS_KATANA, FEAT_EPIC_WEAPON_FOCUS_KATANA, FEAT_WEAPON_OF_CHOICE_KATANA);
if (i == BASE_ITEM_BASTARDSWORD) f = Bonus (t, FEAT_WEAPON_FOCUS_BASTARD_SWORD, FEAT_EPIC_WEAPON_FOCUS_BASTARDSWORD, FEAT_WEAPON_OF_CHOICE_BASTARDSWORD);
if (i == BASE_ITEM_DIREMACE) f = Bonus (t, FEAT_WEAPON_FOCUS_DIRE_MACE, FEAT_EPIC_WEAPON_FOCUS_DIREMACE, FEAT_WEAPON_OF_CHOICE_DIREMACE);
if (i == BASE_ITEM_DOUBLEAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_DOUBLE_AXE, FEAT_EPIC_WEAPON_FOCUS_DOUBLEAXE, FEAT_WEAPON_OF_CHOICE_DOUBLEAXE);
if (i == BASE_ITEM_TWOBLADEDSWORD) f = Bonus (t, FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, FEAT_EPIC_WEAPON_FOCUS_TWOBLADEDSWORD, FEAT_WEAPON_OF_CHOICE_TWOBLADEDSWORD);
if (i == BASE_ITEM_CREATUREITEM) f = Bonus (t, FEAT_WEAPON_FOCUS_CREATURE, FEAT_EPIC_WEAPON_FOCUS_CREATURE);
if (i == BASE_ITEM_WHIP) f = Bonus (t, FEAT_WEAPON_FOCUS_WHIP, FEAT_EPIC_WEAPON_FOCUS_WHIP, FEAT_WEAPON_OF_CHOICE_WHIP);
if (i == BASE_ITEM_TRIDENT) f = Bonus (t, FEAT_WEAPON_FOCUS_TRIDENT, FEAT_EPIC_WEAPON_FOCUS_TRIDENT, FEAT_WEAPON_OF_CHOICE_TRIDENT);
if (i == BASE_ITEM_CLUB) f = Bonus (t, FEAT_WEAPON_FOCUS_CLUB, FEAT_EPIC_WEAPON_FOCUS_CLUB, FEAT_WEAPON_OF_CHOICE_CLUB);
if (i == BASE_ITEM_DART) f = Bonus (t, FEAT_WEAPON_FOCUS_DART, FEAT_EPIC_WEAPON_FOCUS_DART);
if (i == BASE_ITEM_DWARVENWARAXE) f = Bonus (t, FEAT_WEAPON_FOCUS_DWAXE, FEAT_EPIC_WEAPON_FOCUS_DWAXE, FEAT_WEAPON_OF_CHOICE_DWAXE);
if (f.hf) b += 1;
if (f.ef) b += 2;
if (f.wc != FALSE)
{
int l = GetLevelByClass (CLASS_TYPE_WEAPON_MASTER, t);
if (l > 4) b += 1;
l -= 10; if (l > 2) b += (l / 3);
}
if (f.aa > 0) b += (f.aa + 1) / 2;
if (GetHasFeat (FEAT_EPIC_PROWESS, t) && !GetIsRangedWeapon (i)) b += 1; // Is Epic Prowess melee only?? probably …
return b;
}
int GetAttributeBonus (object oPC, int iwt)
{
int bStr = GetAbilityModifier (ABILITY_STRENGTH, oPC);
int bDex = GetAbilityModifier (ABILITY_DEXTERITY, oPC);
if (GetIsRangedWeapon (iwt)) return bDex;
int HasFinesse = GetHasFeat (FEAT_WEAPON_FINESSE, oPC);
int MayUseFinesse = (GetIsFinesseWeapon(iwt) && HasFinesse);
int b = -99;
if ((bDex > bStr) && MayUseFinesse) b = bDex + 1000; else b = bStr;
return b;
}
int GetWeaponBonus (object w)
{
int b = 0;
int t;
itemproperty ip = GetFirstItemProperty (w);
while (GetIsItemPropertyValid (ip))
{
t = GetItemPropertyType (ip);
if (t == ITEM_PROPERTY_ATTACK_BONUS) b += GetPropertyValue(ip, "Attack Bonus: ");
if (t == ITEM_PROPERTY_ENHANCEMENT_BONUS) b += GetPropertyValue(ip, "Enhancement Bonus: ");
if (t == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER) b += GetPropertyValue(ip, "Attack Decrease: ");
if (t == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER) b += GetPropertyValue(ip, "Enhancement Decrease: ");
ip = GetNextItemProperty (w);
}
return b;
}
int GetDualWieldPenalty (object t, object w)
{
int p = 0;
if (!GetIs1HWeapon(w)) return p;
object oOffHand = GetItemInSlot (INVENTORY_SLOT_LEFTHAND, t);
if (!GetIs1HWeapon(oOffHand)) return p;
// Rangers get automatically Two_Weapon_Fighting and Ambidexerity,
// those feats are present for a query (even if not shown in the character screen).
// The feats are automatically revoked, if the armor is medium or heavy, so the query is always correct
p = -6;
if (GetHasFeat (FEAT_TWO_WEAPON_FIGHTING, t)) p = -4;
if (GetIsSmallMeleeWeapon (oOffHand)) p += 2;
return p;
}
void EstimateAB (object t, object oPC)
{
string f;
string s = GetName(t)+" (“+GetTag(t)+”) [“+ GetResRef(t) +”]\n";
// Weapon
object oEquippedWeapon = GetItemInSlot (INVENTORY_SLOT_RIGHTHAND, t);
object oEquippedGloves = GetItemInSlot (INVENTORY_SLOT_ARMS, t);
object oEquippedCWeapon = GetItemInSlot (INVENTORY_SLOT_CWEAPON_R, t);
object oWeapon = OBJECT_INVALID;
int iEquippedWeaponType = BASE_ITEM_INVALID;
if (GetIsObjectValid (oEquippedWeapon))
{
oWeapon = oEquippedWeapon;
iEquippedWeaponType = GetBaseItemType (oEquippedWeapon);
}
else
{
if (GetIsObjectValid (oEquippedGloves))
{
iEquippedWeaponType = GetBaseItemType (oEquippedGloves);
if (iEquippedWeaponType != BASE_ITEM_GLOVES)
iEquippedWeaponType = BASE_ITEM_INVALID;
else
oWeapon = oEquippedGloves;
}
else
if (GetIsObjectValid (oEquippedCWeapon))
{
iEquippedWeaponType = BASE_ITEM_CREATUREITEM;
oWeapon = oEquippedCWeapon;
}
}
string sWeapon = “Uses: " + GetName (oWeapon);
if (iEquippedWeaponType != BASE_ITEM_INVALID)
sWeapon += " (” + Get2DAString(“baseitems”, “label”, iEquippedWeaponType) + “)”;
else
sWeapon += " (No Weapon)";
// BAB
int bab = GetBaseAttackBonus(t);
s += "Base Attack Bonus: " + IntToString (bab) + “\n”;
s += sWeapon + “\n”;
// Attribute Bonus
int aab = GetAttributeBonus (t, iEquippedWeaponType);
if (aab > 500) { aab -= 1000; f = " (uses finesse)"; } else f = “”;
s += "Attribute Bonus: " + IntToString (aab) + f + “\n”;
// Weapon
int wab = 0;
if (oWeapon != OBJECT_INVALID)
{
wab = GetWeaponBonus (oWeapon);
s += "Weaponbonus: " + IntToString (wab) + “\n”;
}
// Feat Bonus
int fab = GetFeatBonus (t, iEquippedWeaponType);
s += "Featbonus: " + IntToString (fab) + “\n”;
// Dual Wield Penalty
int dwp = GetDualWieldPenalty (t, oEquippedWeapon);
s += "Dual Wield Penalty: " + IntToString (dwp) + “\n”;
// Final Result
int eab= bab + aab + wab + fab + dwp;
s += "Estimated AB: " + IntToString (eab) + “\n”;
SendMessageToPC (oPC, s);
}
void main()
{
int nEvent = GetLocalInt(OBJECT_SELF, “X2_L_LAST_ITEM_EVENT”);
if (nEvent != 0) return;
object oItem = GetItemActivated();
object oPC = GetItemActivator();
object t = GetItemActivatedTarget();
if (t == OBJECT_INVALID) return;
int iType = GetObjectType (t);
if (iType != OBJECT_TYPE_CREATURE) return;
EstimateAB (t, oPC);
}