/*////////////////////////////////////////////////////////////////////////////////////////////////////
Script Name: 0i_items
Programmer: Philos
//////////////////////////////////////////////////////////////////////////////////////////////////////
 Include scripts for use with items.
*/////////////////////////////////////////////////////////////////////////////////////////////////////
//#include "0i_main"
#include "0i_messages"
// Returns TRUE if oItem is a weapon.
int ai_GetIsWeapon(object oItem);
// Returns TRUE if oItem is a melee weapon.
int ai_GetIsMeleeWeapon(object oItem);
// Returns TRUE if oItem is a slashing weapon.
int ai_GetIsSlashingWeapon(object oItem);
// Returns TRUE if oItem is a piercing weapon.
int ai_GetIsPiercingWeapon(object oItem);
// Returns TRUE if oItem is a bludgeoning weapon.
int ai_GetIsBludgeoningWeapon(object oItem);
// Returns TRUE if oItem is an ammo.
int ai_GetIsAmmo(object oItem);
// Returns TRUE if oItem is a thrown weapon.
int ai_GetIsThrownWeapon(object oItem);
// Returns TRUE if oItem is able to be used single handed by oCreature.
int ai_GetIsSingleHandedWeapon(object oItem, object oCreature);
// Returns TRUE if oItem is a light weapon for oCreature.
int ai_GetIsLightWeapon(object oItem, object oCreature);
// Returns TRUE if oItem is able to be used two handed by oCreature.
int ai_GetIsTwoHandedWeapon(object oItem, object oCreature);
// Returns TRUE if oItem is a double weapon.
int ai_GetIsDoubleWeapon(object oItem);
// Returns TRUE if oCreature has a ranged weapon equiped and has ammo for it.
int ai_HasRangedWeaponWithAmmo(object oCreature);
// Returns TRUE if oItem is a ranged weapon.
int ai_GetIsRangeWeapon(object oItem);
// Returns the amount of damage the weapon oCreature is holding.
// nDamageAmount tells the function the amount of damage to return;
//      1 - Minimum, 2- Average, 3 Maximum.
// bMelee If it is not a melee weapon then return 0;
int ai_GetWeaponDamage(object oCreature, int nDamageAmount = 3, int bMelee = FALSE);
// Returns TRUE if oItem is a shield.
int ai_GetIsShield(object oItem);
// Returns the size of oItem using 1 = small to 6 = large.
int ai_GetItemSize(object oItem);
// Returns TRUE if the caller has a potion that is identified of nSpell.
int ai_CheckPotionIsIdentified(object oCreature, int nSpell);
// Returns an item from oCreature's inventory with sTag.
// bCheckEquiped will also look through the creatures equiped items.
// Returns OBJECT_INVALID if the items does not exist with sTag.
object ai_GetCreatureHasItem(object oCreature, string sTag, int bCheckEquiped = FALSE);
// Returns TRUE if oCreature can identify oItem based on the file SkillVsItemCost.2da
// Reports the findings to oPC unless oPC = OBJECT_INVALID.
// If the item can be identified by oCreature then it will be identified.
int ai_IdentifyItemVsKnowledge(object oCreature, object oItem, object oPC = OBJECT_INVALID);
// Identifies all items on oObject based on the file SkillVsItemCost.2da
// Reports the findings to oPC unless oPC = OBJECT_INVALID
// bIdentifyAll ignores the chart and does what it says!
void ai_IdentifyAllVsKnowledge(object oCreature, object oContainer, object oPC = OBJECT_INVALID);
// Will (Un)Identify all items on oCreature.
// If bIdentify is TRUE they will all be Identified, FALSE Unidentifies them.
void ai_SetIdentifyAllItems(object oCreature, int bIdentify = TRUE);
// Returns oWeapons attack bonus from either Enhancment or Attack bonus.
int ai_GetWeaponAtkBonus(object oWeapon);
// Returns oArmors armor bonus.
int ai_GetArmorBonus(object oArmor);
// Returns the maximum gold value that an item can have to be equiped.
int ai_GetMaxItemValueThatCanBeEquiped(int nLevel);
// Returns the minimum level that is required to equip this item.
int ai_GetMinimumEquipLevel(object oItem);
// Returns oCreatures total attack bonus with melee weapon (Mostly).
int ai_GetCreatureAttackBonus(object oCreature);
// Returns TRUE if oCreature can use oItem based on Class, Race, and Alignment
// restrictions. Also checks UseMagicDevice of oCreature.
int ai_CheckIfCanUseItem(object oCreature, object oItem);
// Returns TRUE if oCreature can use oItem due to feats.
int ai_GetIsProficientWith(object oCreature, object oItem);
// Gets the Average Damage on the weapon for Main and Off Hand to allow
// us to check which weapon is better for oCreature to equip.
// b2Handed set to TRUE returns only checks main avg damage.
// bOffHand set to TRUE returns the OffHand avg damage.
// if b2Handed & bOffHand are set to TRUE it returns main & offhand added together.
// if oOffWeapon is Set then it will return the Avg Damage assuming oItem is
// the Main weapon and oOffWeapon is in the Offhand.
float ai_GetMeleeWeaponAvgDmg(object oCreature, object oItem, int b2Handed = FALSE, int bOffHand = FALSE, object oOffWeapon = OBJECT_INVALID);
// Sets shield AC on the shield to allow us to check which shield is better
// for oCreature to equip.
int ai_SetShieldAC(object oCreature, object oItem);
// Returns TRUE if oItem has nItemPropertyType.
// nItemPropertySubType will not be used if its below 0.
int ai_GetHasItemProperty(object oItem, int nItemPropertyType, int nItemPropertySubType = -1);
// Returns the highest bonus Lock Picks needed to unlock nLockDC in oCreatures inventory.
object ai_GetBestPicks(object oCreature, int nLockDC);
// Removes all items from oCreature.
void ai_RemoveInventory(object oCreature);
// Copies all equiped and inventory items from oOldHenchman to oNewHenchman.
void ai_MoveInventory(object oOldHenchman, object oNewHenchman);
// Returns if oCreature is proficient with nBaseItem.
// PRC lets the creature use any weapon, but gives -4 penalty if not proficient.
int prc_IsProficient(object oCreature, int nBaseItem);

int ai_GetIsWeapon(object oItem)
{
    int nType = GetBaseItemType(oItem);
    int nWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", nType));
    if(nWeaponType) return TRUE;
    return FALSE;
}
int ai_GetIsMeleeWeapon(object oItem)
{
    int nType = GetBaseItemType(oItem);
    if(StringToInt(Get2DAString("baseitems", "WeaponType", nType)) > 0)
    {
        if(StringToInt(Get2DAString("baseitems", "RangedWeapon", nType)) == 0) return TRUE;
    }
    return FALSE;
}
int ai_GetIsSingleHandedWeapon(object oItem, object oCreature)
{
  if(!ai_GetIsMeleeWeapon(oItem)) return FALSE;
  int nBaseItemType = GetBaseItemType(oItem);
  // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType));
  // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nCreatureSize = GetCreatureSize(oCreature);
  return nWeaponSize <= nCreatureSize;
}
int ai_GetIsLightWeapon(object oItem, object oCreature)
{
  if(!ai_GetIsMeleeWeapon(oItem)) return FALSE;
  int nBaseItemType = GetBaseItemType(oItem);
  // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType));
  // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nCreatureSize = GetCreatureSize(oCreature);
  return nWeaponSize < nCreatureSize;
}
int ai_GetIsTwoHandedWeapon(object oItem, object oCreature)
{
  if(!ai_GetIsMeleeWeapon(oItem)) return FALSE;
  int nBaseItemType = GetBaseItemType(oItem);
  // Weapon Size in the baseitems.2da is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nWeaponSize = StringToInt(Get2DAString("baseitems", "WeaponSize", nBaseItemType));
  // Ranged weapons have a value greater than 0 in this field. So melee weapons have 0.
  int nWeaponMelee = StringToInt(Get2DAString("baseitems", "RangedWeapon", nBaseItemType));
  // Creature size is 1 = Tiny, 2 = Small, 3 = Medium, 4 = Large.
  int nCreatureSize = GetCreatureSize(oCreature);
  return (nWeaponMelee == 0 && nWeaponSize > nCreatureSize);
}
int ai_GetIsDoubleWeapon(object oItem)
{
    int iType = GetBaseItemType(oItem);
    switch(iType)
    {
        case BASE_ITEM_DIREMACE:
        case BASE_ITEM_DOUBLEAXE:
        case BASE_ITEM_TWOBLADEDSWORD: return TRUE;
    }
    return FALSE;
}
int ai_GetIsSlashingWeapon(object oItem)
{
  int iBaseItemType = GetBaseItemType(oItem);
  int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType));
  // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing.
  return (iWeaponType == 3);
}
int ai_GetIsPiercingWeapon(object oItem)
{
  int iBaseItemType = GetBaseItemType(oItem);
  int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType));
  // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing.
  return (iWeaponType == 1);
}
int ai_GetIsBludgeoningWeapon(object oItem)
{
  int iBaseItemType = GetBaseItemType(oItem);
  int iWeaponType = StringToInt(Get2DAString("baseitems", "WeaponType", iBaseItemType));
  // Weapon Type in the baseitems.2da is 1 = Piercing, 2 = Bludgeoning, 3 = Slashing.
  return (iWeaponType == 2);
}
int ai_GetIsAmmo(object oItem)
{
   switch(GetBaseItemType(oItem))
   {
      case BASE_ITEM_ARROW: return TRUE;
      case BASE_ITEM_BOLT: return TRUE;
      case BASE_ITEM_BULLET: return TRUE;
   }
   return FALSE;
}
int ai_GetIsThrownWeapon(object oItem)
{
   switch(GetBaseItemType(oItem))
   {
      case BASE_ITEM_DART: return TRUE;
      case BASE_ITEM_SHURIKEN: return TRUE;
      case BASE_ITEM_THROWINGAXE: return TRUE;
   }
   return FALSE;
}
int ai_HasRangedWeaponWithAmmo(object oCreature)
{
    object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature);
    if(!GetWeaponRanged(oWeapon)) return FALSE;
    int nAmmoType, nWeaponType = GetBaseItemType(oWeapon);
    object oAmmo = OBJECT_INVALID;
    if(nWeaponType == BASE_ITEM_LONGBOW || nWeaponType == BASE_ITEM_SHORTBOW)
    {
        if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE;
        if(GetItemInSlot(INVENTORY_SLOT_ARROWS, oCreature) != OBJECT_INVALID) return TRUE;
        nAmmoType = BASE_ITEM_ARROW;
    }
    else if(nWeaponType == BASE_ITEM_LIGHTCROSSBOW || nWeaponType == BASE_ITEM_HEAVYCROSSBOW)
    {
        if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE;
        if(GetItemInSlot(INVENTORY_SLOT_BOLTS, oCreature) != OBJECT_INVALID) return TRUE;
        nAmmoType = BASE_ITEM_BOLT;
    }
    else if(nWeaponType == BASE_ITEM_SLING)
    {
        if(ai_GetHasItemProperty(oWeapon, ITEM_PROPERTY_UNLIMITED_AMMUNITION)) return TRUE;
        if(GetItemInSlot(INVENTORY_SLOT_BULLETS, oCreature) != OBJECT_INVALID) return TRUE;
        nAmmoType = BASE_ITEM_BULLET;
    }
    else if(nWeaponType == BASE_ITEM_THROWINGAXE) return TRUE;
    else if(nWeaponType == BASE_ITEM_SHURIKEN) return TRUE;
    else if(nWeaponType == BASE_ITEM_DART) return TRUE;
    // They don't have any ammo in the slot, but do they have ammo in the inventory?
    oAmmo = GetFirstItemInInventory(oCreature);
    while(oAmmo != OBJECT_INVALID)
    {
        if(GetBaseItemType(oAmmo) == nAmmoType)
        {
            if(nAmmoType == BASE_ITEM_ARROW) ActionEquipItem(oAmmo, INVENTORY_SLOT_ARROWS);
            else if(nAmmoType == BASE_ITEM_BOLT) ActionEquipItem(oAmmo, INVENTORY_SLOT_BOLTS);
            else if(nAmmoType == BASE_ITEM_BULLET) ActionEquipItem(oAmmo, INVENTORY_SLOT_BULLETS);
            return TRUE;
        }
        oAmmo = GetNextItemInInventory(oCreature);
    }
    //ai_Debug("0i_items", "254", "They are out of ammo!");
    return FALSE;
}
int ai_GetIsRangeWeapon(object oItem)
{
   switch(GetBaseItemType(oItem))
   {
      case BASE_ITEM_DART: return TRUE;
      case BASE_ITEM_HEAVYCROSSBOW: return TRUE;
      case BASE_ITEM_LIGHTCROSSBOW: return TRUE;
      case BASE_ITEM_LONGBOW: return TRUE;
      case BASE_ITEM_SHORTBOW: return TRUE;
      case BASE_ITEM_SHURIKEN: return TRUE;
      case BASE_ITEM_SLING: return TRUE;
      case BASE_ITEM_THROWINGAXE: return TRUE;
   }
   return FALSE;
}
int ai_GetIsFinesseWeapon(object oCreature, object oItem)
{
   switch(GetBaseItemType(oItem))
   {
       case BASE_ITEM_DAGGER: return TRUE;
       case BASE_ITEM_HANDAXE: return TRUE;
       case BASE_ITEM_KAMA: return TRUE;
       case BASE_ITEM_KUKRI: return TRUE;
       case BASE_ITEM_LIGHTHAMMER: return TRUE;
       case BASE_ITEM_LIGHTMACE: return TRUE;
       case BASE_ITEM_RAPIER:
       {
           if(GetCreatureSize(oCreature) > CREATURE_SIZE_SMALL) return TRUE;
           return FALSE;
       }
       case BASE_ITEM_SHORTSWORD: return TRUE;
       case BASE_ITEM_SICKLE: return TRUE;
       case BASE_ITEM_WHIP: return TRUE;
   }
   return FALSE;
}
int ai_GetWeaponDamage(object oCreature, int nDamageAmount = 3, int bMelee = FALSE)
{
    object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature);
    if(bMelee && ai_GetIsRangeWeapon(oItem)) return 0;
    int nWeaponDamage = GetLocalInt(oItem, "AI_WEAPON_DAMAGE");
    if(!nWeaponDamage)
    {
        if(ai_GetIsMeleeWeapon(oItem))
        {
            nWeaponDamage = GetAbilityModifier(ABILITY_STRENGTH, oCreature);
            if(ai_GetIsTwoHandedWeapon(oItem, oCreature)) nWeaponDamage += nWeaponDamage / 2;
        }
        int nWeaponDice = StringToInt(Get2DAString("baseitems", "NumDice", GetBaseItemType(oItem)));
        int nWeaponDie = StringToInt(Get2DAString("baseitems", "DieToRoll", GetBaseItemType(oItem)));
        if(nDamageAmount == 1)
        {
            nWeaponDamage += nWeaponDice;
        }
        else if(nDamageAmount == 2)
        {
            nWeaponDamage += nWeaponDice * nWeaponDie / 2;
        }
        else
        {
            nWeaponDamage += nWeaponDice * nWeaponDie;
        }
        SetLocalInt(oItem, "AI_WEAPON_DAMAGE", nWeaponDamage);
    }
    return nWeaponDamage;
}
int ai_GetIsShield(object oItem)
{
   switch(GetBaseItemType(oItem))
   {
      case BASE_ITEM_SMALLSHIELD: return TRUE;
      case BASE_ITEM_LARGESHIELD: return TRUE;
      case BASE_ITEM_TOWERSHIELD: return TRUE;
   }
   return FALSE;
 }
int ai_GetItemSize(object oItem)
{
    int nBaseItemType = GetBaseItemType(oItem);
    int nWidth = StringToInt(Get2DAString("baseitems", "InvSlotWidth", nBaseItemType));
    int nHeight = StringToInt(Get2DAString("baseitems", "InvSlotHeight", nBaseItemType));
    return nWidth + nHeight - 1;
}
int ai_CheckPotionIsIdentified(object oCreature, int nSpell)
{
    int nPotionSpell;
    itemproperty ipPotion;
    object oPotion = GetFirstItemInInventory(oCreature);
    while(oPotion != OBJECT_INVALID)
    {
        if(GetIdentified(oPotion))
        {
            ipPotion = GetFirstItemProperty(oPotion);
            nPotionSpell = GetItemPropertySubType(ipPotion);
            nPotionSpell = StringToInt(Get2DAString("iprp_spells", "SpellIndex", nPotionSpell));
            //ai_Debug("0i_talents", "318", "Potion ID'ed? nSpell: " + IntToString(nSpell) + " nPotionSpell: " + IntToString(nPotionSpell));
            if(nSpell == nPotionSpell) return TRUE;
        }
        oPotion = GetNextItemInInventory(oCreature);
    }
    return FALSE;
}
object ai_GetCreatureHasItem(object oCreature, string sTag, int bCheckEquiped = FALSE)
{
    // Cycle through the creatures unequiped items.
    object oItem = GetFirstItemInInventory(oCreature);
    while(oItem != OBJECT_INVALID)
    {
        if(GetTag(oItem) == sTag) return oItem;
        oItem = GetNextItemInInventory(oCreature);
    }
    // Should we check the creatures equiped items.
    // If we have already found it then stop looking.
    int nSlot = 0;
    if(bCheckEquiped)
    {
       // Check all of the creatures slots(0 - 17).
       while(nSlot <= 17)
       {
            oItem = GetItemInSlot(nSlot, oCreature);
            if(GetTag(oItem) == sTag) return oItem;
            nSlot ++;
       }
    }
    return OBJECT_INVALID;
}
int ai_IdentifyItemVsKnowledge(object oCreature, object oItem, object oPC = OBJECT_INVALID)
{
    if(GetIdentified(oItem)) return FALSE;
    int nKnowledge = GetSkillRank(SKILL_LORE, oCreature);
    int nItemValue; // gold value of item
    string sBaseName;
    string sMaxValue = Get2DAString("SkillVsItemCost", "DeviceCostMax", nKnowledge);
    int nMaxValue = StringToInt(sMaxValue);
    // * Handle overflow(November 2003 - BK)
    if(sMaxValue == "") nMaxValue = 0;
    // Setting TRUE to get the true value of the item.
    SetIdentified(oItem, TRUE);
    nItemValue = GetGoldPieceValue(oItem);
    if(nMaxValue <= nItemValue)
    {
        SetIdentified(oItem, FALSE);
        if(oPC != OBJECT_INVALID)
        {
            sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem))));
            ai_SendMessages(GetName(oCreature) + " cannot identify " + sBaseName, AI_COLOR_RED, oPC);
        }
    }
    else
    {
        if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " has identified " + GetName(oItem), AI_COLOR_GREEN, oPC);
        return TRUE;
    }
    return FALSE;
}
void ai_IdentifyAllVsKnowledge(object oCreature, object oContainer, object oPC = OBJECT_INVALID)
{
    // SkillVsItemCost 2da starts 1 at 0 ... go figure!
    int nKnowledge = GetSkillRank(SKILL_LORE, oCreature) - 1;
    int nItemValue; // gold value of item
    string sBaseName;
    string sMaxValue = Get2DAString("SkillVsItemCost", "DeviceCostMax", nKnowledge);
    int nMaxValue = StringToInt(sMaxValue);
    // * Handle overflow(November 2003 - BK)
    if(sMaxValue == "") nMaxValue = 0;
    object oItem = GetFirstItemInInventory(oContainer);
    while(oItem != OBJECT_INVALID)
    {
        if(!GetIdentified(oItem))
        {
            // setting TRUE to get the true value of the item.
            SetIdentified(oItem, TRUE);
            nItemValue = GetGoldPieceValue(oItem);
            if(nMaxValue < nItemValue)
            {
                SetIdentified(oItem, FALSE);
                sBaseName = GetStringByStrRef(StringToInt(Get2DAString("baseitems", "name", GetBaseItemType(oItem))));
                if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " cannot identify " + sBaseName, AI_COLOR_RED, oPC);
            }
            else if(oPC != OBJECT_INVALID) ai_SendMessages(GetName(oCreature) + " has identified " + GetName(oItem), AI_COLOR_GREEN, oPC);
        }
        oItem = GetNextItemInInventory(oContainer);
    }
}
void ai_SetIdentifyAllItems(object oCreature, int bIdentify = TRUE)
{
    object oItem = GetFirstItemInInventory(oCreature);
    while(oItem != OBJECT_INVALID)
    {
        if(!GetIdentified(oItem)) SetIdentified(oItem, bIdentify);
        oItem = GetNextItemInInventory(oCreature);
    }
    int nSlot;
    oItem = GetItemInSlot(nSlot, oCreature);
    while(nSlot < 11)
    {
        if(!GetIdentified(oItem)) SetIdentified(oItem, bIdentify);
        oItem = GetItemInSlot(++nSlot, oCreature);
    }
}
int ai_GetWeaponAtkBonus(object oWeapon)
{
   int nCounter = 1, nPropertyType, nBonus;
    // Get first property
    itemproperty ipProperty = GetFirstItemProperty(oWeapon);
    while(GetIsItemPropertyValid(ipProperty))
    {
        // Check to see if the property type matches.
        nPropertyType = GetItemPropertyType(ipProperty);
        if(nPropertyType == 6/*ITEMPROPERTY_ENHANCEMENT*/ ||
           nPropertyType == 56/*ITEMPROPERTY_ATTACKBONUS*/)
        {
            nBonus += GetItemPropertyCostTableValue(ipProperty);
        }
        // Get the next property.
        ipProperty = GetNextItemProperty(oWeapon);
    }
    //ai_Debug("0i_items", "438", GetName(oWeapon) + " attack bonus is " + IntToString(nBonus));
    return nBonus;
}
int ai_GetArmorBonus(object oArmor)
{
    int nTorsoValue = GetItemAppearance(oArmor, ITEM_APPR_TYPE_ARMOR_MODEL, ITEM_APPR_ARMOR_MODEL_TORSO);
    //ai_Debug("0i_items", "444", "Armor Bonus: " + Get2DAString("parts_chest.2da", "ACBONUS", nTorsoValue));
    return StringToInt(Get2DAString("parts_chest", "ACBONUS", nTorsoValue));
}
int ai_GetMaxItemValueThatCanBeEquiped(int nLevel)
{
    return StringToInt(Get2DAString("itemvalue", "MAXSINGLEITEMVALUE", nLevel - 1));
}
int ai_GetMinimumEquipLevel(object oItem)
{
    int nIndex, nUnIdentified;
    if(!GetIdentified(oItem))
    {
        nUnIdentified = TRUE;
        SetIdentified(oItem, TRUE);
    }
    int nGoldValue = GetGoldPieceValue(oItem);
    if(nUnIdentified) SetIdentified(oItem, FALSE);
    int n2daMaxRow = Get2DARowCount("itemvalue");
    while(nIndex < n2daMaxRow)
    {
        if(nGoldValue <= StringToInt(Get2DAString("itemvalue", "MAXSINGLEITEMVALUE", nIndex)))
        {
            return nIndex + 1;
        }
        nIndex++;
    }
    return nIndex;
}
int ai_GetCreatureAttackBonus(object oCreature)
{
    object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature);
    int nAtkBonus = GetBaseAttackBonus(oCreature);
    if((GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) && ai_GetIsFinesseWeapon(oCreature, oWeapon)) ||
       ai_GetIsRangeWeapon(oWeapon))
    {
        nAtkBonus += GetAbilityModifier(ABILITY_DEXTERITY, oCreature);
    }
    else nAtkBonus += GetAbilityModifier(ABILITY_STRENGTH, oCreature);
    if(ai_GetIsMeleeWeapon(oWeapon)) nAtkBonus += ai_GetWeaponAtkBonus(oWeapon);
    return nAtkBonus;
 }
int ai_CheckUseMagicDevice(object oCreature, string sColumn, object oItem)
{
    if(!GetLocalInt(GetModule(), AI_RULE_ALLOW_UMD)) return FALSE;
    int nUMD = GetSkillRank(SKILL_USE_MAGIC_DEVICE, oCreature);
    //ai_Debug("0i_talents", "1600", GetName(oCreature) + " is check UMD: " + IntToString(nUMD));
    if(nUMD < 1) return FALSE;
    int nDC, nIndex, nItemValue = GetGoldPieceValue(oItem);
    while(nIndex < 55)
    {
        //ai_Debug("0i_talents", "1605", GetName(oItem) + " has a value of " +
        //         Get2DAString("skillvsitemcost", "DeviceCostMax", nIndex) +
        //         " nIndex: " + IntToString(nIndex));
        if(nItemValue < StringToInt(Get2DAString("skillvsitemcost", "DeviceCostMax", nIndex)))
        {
            //ai_Debug("0i_talents", "1610", "nUMD >= " + Get2DAString("skillvsitemcost", sColumn, nIndex));
            if(nUMD >= StringToInt(Get2DAString("skillvsitemcost", sColumn, nIndex))) return TRUE;
            return FALSE;
        }
        nIndex++;
    }
    return FALSE;
}
int ai_CheckIfCanUseItem(object oCreature, object oItem)
{
    int bAlign, bClass, bRace, bAlignLimit, bClassLimit, bRaceLimit;
    int nIprpSubType, nItemPropertyType;
    // Check to see if this item is limited to a specific alignment, class, or race.
    int nAlign1 = GetAlignmentLawChaos(oCreature);
    int nAlign2 = GetAlignmentGoodEvil(oCreature);
    int nRace = GetRacialType(oCreature);
    //ai_Debug("0i_items", "615", "nAlign1: " + IntToString(nAlign1) +
    //         " nAlign2: " + IntToString(nAlign2) + " nRace: " + IntToString(nRace));
    itemproperty ipProp = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ipProp))
    {
        nItemPropertyType = GetItemPropertyType(ipProp);
        //ai_Debug("0i_items", "620", "ItempropertyType(62/63/64/65): " + IntToString(nItemPropertyType));
        if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_ALIGNMENT_GROUP)
        {
            bAlignLimit = TRUE;
            // SubType is the group index for iprp_aligngrp.2da
            nIprpSubType = GetItemPropertySubType(ipProp);
            //ai_Debug("0i_items", "626", "nIprpSubType: " + IntToString(nIprpSubType));
            if(nIprpSubType == nAlign1 || nIprpSubType == nAlign2) bAlign = TRUE;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_SPECIFIC_ALIGNMENT)
        {
            bAlignLimit = TRUE;
            // SubType is the alignment index for iprp_alignment.2da
            nIprpSubType = GetItemPropertySubType(ipProp);
            //ai_Debug("0i_items", "634", "nIprpSubType: " + IntToString(nIprpSubType));
            if(nIprpSubType == 0 && nAlign1 == 2 && nAlign2 == 4) bAlign = TRUE;
            else if(nIprpSubType == 1 && nAlign1 == 2 && nAlign2 == 1) bAlign = TRUE;
            else if(nIprpSubType == 2 && nAlign1 == 2 && nAlign2 == 5) bAlign = TRUE;
            else if(nIprpSubType == 3 && nAlign1 == 1 && nAlign2 == 4) bAlign = TRUE;
            else if(nIprpSubType == 4 && nAlign1 == 1 && nAlign2 == 1) bAlign = TRUE;
            else if(nIprpSubType == 5 && nAlign1 == 1 && nAlign2 == 5) bAlign = TRUE;
            else if(nIprpSubType == 6 && nAlign1 == 3 && nAlign2 == 4) bAlign = TRUE;
            else if(nIprpSubType == 7 && nAlign1 == 3 && nAlign2 == 1) bAlign = TRUE;
            else if(nIprpSubType == 8 && nAlign1 == 3 && nAlign2 == 5) bAlign = TRUE;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_CLASS)
        {
            bClassLimit = TRUE;
            // SubType is the class index for classes.2da
            nIprpSubType = GetItemPropertySubType(ipProp);
            //ai_Debug("0i_items", "650", "nIprpSubType: " + IntToString(nIprpSubType));
            int nClassPosition = 1;
            int nClass = GetClassByPosition(nClassPosition, oCreature);
            while(nClassPosition <= AI_MAX_CLASSES_PER_CHARACTER)
            {
                if(nIprpSubType == nClass) bClass = TRUE;
                nClass = GetClassByPosition(++nClassPosition, oCreature);
            }
        }
        else if(nItemPropertyType == ITEM_PROPERTY_USE_LIMITATION_RACIAL_TYPE)
        {
            bRaceLimit = TRUE;
            // SubType is the race index for racialtypes.2da
            nIprpSubType = GetItemPropertySubType(ipProp);
            //ai_Debug("0i_items", "664", "nIprpSubType: " + IntToString(nIprpSubType));
            if(nIprpSubType == nRace) bRace = TRUE;
        }
        ipProp = GetNextItemProperty(oItem);
    }
    //ai_Debug("0i_items", "669", "bAlignLimit: " + IntToString(bAlignLimit) + " bAlign: " + IntToString(bAlign) +
    //         " bClassLimit: " + IntToString(bClassLimit) + " bClass: " + IntToString(bClass) +
    //         " bRaceLimit: " + IntToString(bRaceLimit) + " bRace: " + IntToString(bRace));
    if(bClassLimit && !bClass && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Class", oItem)) return FALSE;
    if(bRaceLimit && !bRace && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Race", oItem)) return FALSE;
    if(bAlignLimit && !bAlign && !ai_CheckUseMagicDevice(oCreature, "SkillReq_Align", oItem)) return FALSE;
    return TRUE;
}
int ai_GetIsProficientWith(object oCreature, object oItem)
{
    int nWeaponType = GetBaseItemType(oItem);
    // In the PRC you can equip any weapon.
    if(GetLocalInt(GetModule(), AI_USING_PRC)) return TRUE;
    int nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat0", nWeaponType));
    // If it is 0 then it doesn't require a feat or we are at the end of the
    // feat requirements.
    if(nFeat == 0) return TRUE;
    if(GetHasFeat(nFeat, oCreature)) return TRUE;
    nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat1", nWeaponType));
    if(nFeat == 0) return FALSE;
    if(GetHasFeat(nFeat, oCreature)) return TRUE;
    nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat2", nWeaponType));
    if(nFeat == 0) return FALSE;
    if(GetHasFeat(nFeat, oCreature)) return TRUE;
    nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat3", nWeaponType));
    if(nFeat == 0) return FALSE;
    if(GetHasFeat(nFeat, oCreature)) return TRUE;
    nFeat = StringToInt(Get2DAString("baseitems", "ReqFeat4", nWeaponType));
    if(nFeat == 0) return FALSE;
    if(GetHasFeat(nFeat, oCreature)) return TRUE;
    return FALSE;
}
float ai_GetMeleeWeaponAvgDmg(object oCreature, object oItem, int b2Handed = FALSE, int bOffHand = FALSE, object oOffWeapon = OBJECT_INVALID)
{
    // Has this weapon already been calculated for this creature?
    if(oCreature == GetLocalObject(oItem, "AI_CREATURE_POSSESSION"))
    {
        // Return the Main weapons Avg Damage while using a weapon in the off hand.
        if(oOffWeapon != OBJECT_INVALID)
        {
            // We recalculate all OffWeapon avg damage unless its a double weapon.
            if(oOffWeapon == oItem)
            {
                float fMain2WDmg = GetLocalFloat(oItem, "AI_MAIN_2W_HAND_AVG_DMG");
                // If they passed that this is a 2handed weapon then return the total
                // Avg Dmg for oItem. Used for double weapons.
                if(b2Handed)
                {
                    fMain2WDmg += ai_GetMeleeWeaponAvgDmg(oCreature, oItem, FALSE, TRUE);
                }
                if(AI_DEBUG) ai_Debug("0i_items", "611", GetName(oItem) + " avg dmg with Offhand weapon (" + GetName(oOffWeapon) + ") " + FloatToString(fMain2WDmg, 0, 2));
                return fMain2WDmg;
            }
        }
        // Return the avg dmg for oItem assuming it is in the OffHand.
        else if(bOffHand)
        {
            float fOffHandDmg = GetLocalFloat(oItem, "AI_OFFHAND_AVG_DMG");
            if(AI_DEBUG) ai_Debug("0i_items", "618", GetName(oItem) + " fOffHandAvgDmg: " + FloatToString(fOffHandDmg, 0, 2));
            return fOffHandDmg;
        }
        // If we get here then Return the avg dmg for oItem assuming its in the main hand.
        else
        {
            float fMainDmg = GetLocalFloat(oItem, "AI_AVG_DMG");
            if(AI_DEBUG)ai_Debug("0i_items", "623", GetName(oItem) + " fMainDmg: " + FloatToString(fMainDmg, 0, 2));
            return fMainDmg;
        }
    }
    // Set the creature to this item that we are calculationg the avg damages for.
    SetLocalObject(oItem, "AI_CREATURE_POSSESSION", oCreature);
    int nItemType = GetBaseItemType(oItem);
    // Figure average damage for one attack, or two with two weapons.
    // We are keeping it simple to reduce time and checks.
    // Get the weapons base stats.
    int nMinDmg = StringToInt(Get2DAString("baseitems", "NumDice", nItemType));
    int nMaxDmg = nMinDmg * StringToInt(Get2DAString("baseitems", "DieToRoll", nItemType));
    int nThreat = StringToInt(Get2DAString("baseitems", "CritThreat", nItemType));
    int nMultiplier = StringToInt(Get2DAString("baseitems", "CritHitMult", nItemType));
    int nIndex, nBonusMinDmg, nBonusMaxDmg, nItemPropertyType, nNumDice;
    // We set ToHit to 10 for a 50% chance to hit without modifiers.
    float fCritBonusDmg, fToHit = 10.0;
    if(GetLocalInt(GetModule(), AI_USING_PRC))
    {
        if(!prc_IsProficient(oCreature, nItemType)) fToHit -= 4.0;
    }
    // Check oCreature's feats.
    if(GetHasFeat(FEAT_WEAPON_FINESSE, oCreature) &&
       ai_GetIsLightWeapon(oItem, oCreature))
    {
        // Add Dexterity modifier to the Attack bonus.
        nIndex = GetAbilityModifier(ABILITY_DEXTERITY, oCreature);
    }
    else
    {
        // Add Strength modifier to the attack bonus.
        nIndex = GetAbilityModifier(ABILITY_STRENGTH, oCreature);
        // Add 1/2 strength modifier to damage for 2handed weapons, but not Double weapons.
        if(b2Handed && !bOffHand)
        {
            nMinDmg += nIndex / 2;
            nMaxDmg += nIndex / 2;
        }
    }
    fToHit += nIndex;
    if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponFocusFeat", nItemType)), oCreature, TRUE))
    {
        fToHit += 1.0;
        if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponSpecializationFeat", nItemType)), oCreature, TRUE))
        {
            nMinDmg += 2;
            nMaxDmg += 2;
        }
        if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponFocusFeat", nItemType)), oCreature, TRUE))
        {
            fToHit += 2.0;
            if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponSpecializationFeat", nItemType)), oCreature, TRUE))
            {
                nMinDmg += 4;
                nMaxDmg += 4;
            }
        }
    }
    if(GetHasFeat(StringToInt(Get2DAString("baseitems", "WeaponImprovedCriticalFeat", nItemType)), oCreature, TRUE))
    {
        nMultiplier += nMultiplier;
        if(GetHasFeat(StringToInt(Get2DAString("baseitems", "EpicWeaponOverwhelmingCriticalFeat", nItemType)), oCreature, TRUE))
        {
            if(nMultiplier > 3) fCritBonusDmg = 10.5;
            else if(nMultiplier == 3) fCritBonusDmg = 7.0;
            else fCritBonusDmg = 3.5;
        }
    }
    // Check oItem's properties.
    itemproperty ipProperty = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ipProperty))
    {
        nItemPropertyType = GetItemPropertyType(ipProperty);
        if(nItemPropertyType == ITEM_PROPERTY_ENHANCEMENT_BONUS)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nBonusMinDmg += nIndex;
            nBonusMaxDmg += nIndex;
            fToHit += IntToFloat(nIndex);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_DAMAGE_BONUS)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nNumDice = StringToInt(Get2DAString("iprp_damagecost", "NumDice", nIndex));
            nBonusMinDmg += nNumDice;
            nBonusMaxDmg += nNumDice * StringToInt(Get2DAString("iprp_damagecost", "Die", nIndex));
        }
        else if(nItemPropertyType == ITEM_PROPERTY_ATTACK_BONUS)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            fToHit += IntToFloat(nIndex);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_KEEN)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nMultiplier += nMultiplier;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_HASTE)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nMinDmg += nMinDmg;
            nMaxDmg += nMaxDmg;
            nBonusMinDmg += nBonusMinDmg;
            nBonusMaxDmg += nBonusMaxDmg;
            nMultiplier += nMultiplier;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_MASSIVE_CRITICALS)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nNumDice = StringToInt(Get2DAString("iprp_damagecost", "NumDice", nIndex));
            fCritBonusDmg += IntToFloat(nNumDice) + IntToFloat(nNumDice * StringToInt(Get2DAString("iprp_damagecost", "Die", nIndex))) / 2.0;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nBonusMinDmg -= nIndex;
            nBonusMaxDmg -= nIndex;
            fToHit -= IntToFloat(nIndex);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            fToHit -= IntToFloat(nIndex);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_DAMAGE)
        {
            nIndex = GetItemPropertyCostTableValue(ipProperty);
            nBonusMinDmg -= nIndex;
            nBonusMaxDmg -= nIndex;
        }
        else if(nItemPropertyType == ITEM_PROPERTY_NO_DAMAGE)
        {
            // A weapon always does a minimum of 1 pnt of damage.
            nMinDmg = 1;
            nMaxDmg = 1;
        }
        ipProperty = GetNextItemProperty(oItem);
    }
    float fAvgDmg = IntToFloat(nMinDmg + nMaxDmg + nBonusMinDmg + nBonusMaxDmg) / 2;
    // Set value for Offhand chance to hit.
    float fOffHandToHit = fToHit - 10.0;
    float fOffHandAvgDmg = fAvgDmg;
    // Set value for Main hand chance to hit with a weapon in Off hand.
    float fMain2HandToHit = fToHit - 6.0;
    float fMain2HandAvgDmg = fAvgDmg;
    // Calculate the avg dmg for oItem used in the main hand with no Off hand weapon.
    fToHit = fToHit / 20.0;
    float fThreatChance = (IntToFloat(nThreat) / 20.0) * fToHit;
    fAvgDmg = (fAvgDmg * fToHit) + ((fAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance);
    SetLocalFloat(oItem, "AI_AVG_DMG", fAvgDmg);
    if(AI_DEBUG) ai_Debug("0i_items", "768", GetName(oItem) + " fSingleAvgDmg: " + FloatToString(fAvgDmg, 0, 2));
    if(!b2Handed || (b2Handed && oOffWeapon != OBJECT_INVALID))
    {
        // Calculate chance to hit based on two weapon feats and main hand vs off hand.
        if(GetHasFeat(374/*Dual_Wield*/, oCreature))
        {
            if(ai_GetArmorBonus(GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature)) < 4)
            {
                fMain2HandToHit += 2.0;
                fOffHandToHit += 6.0;
            }
        }
        else
        {
            if(GetHasFeat(FEAT_AMBIDEXTERITY, oCreature)) fOffHandToHit += 4.0;
            if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING, oCreature))
            {
                fMain2HandToHit += 2.0;
                fOffHandToHit += 2.0;
            }
        }
        if(ai_GetIsLightWeapon(oItem, oCreature)) fOffHandToHit += 2.0;
        if(oOffWeapon != OBJECT_INVALID &&
          (ai_GetIsLightWeapon(oOffWeapon, oCreature) || ai_GetIsDoubleWeapon(oItem)))
        {
            fMain2HandToHit += 2.0;
        }
        // Calculate the avg dmg for oItem used in the main hand with an off hand weapon.
        fMain2HandToHit = fMain2HandToHit / 20.0;
        fThreatChance = (IntToFloat(nThreat) / 20.0) * fMain2HandToHit;
        fMain2HandAvgDmg = (fMain2HandAvgDmg * fMain2HandToHit) + ((fMain2HandAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance);
        SetLocalFloat(oItem, "AI_MAIN_2W_HAND_AVG_DMG", fMain2HandAvgDmg);
        if(AI_DEBUG) ai_Debug("0i_items", "768", GetName(oItem) + " fMain2HandAvgDmg: " + FloatToString(fMain2HandAvgDmg, 0, 2));
        // Calculate the avg dmg for oItem used in the off hand.
        fOffHandToHit = fOffHandToHit / 20.0;
        fThreatChance = (IntToFloat(nThreat) / 20.0) * fOffHandToHit;
        fOffHandAvgDmg = (fOffHandAvgDmg * fOffHandToHit) + ((fOffHandAvgDmg * IntToFloat(nMultiplier) + fCritBonusDmg) * fThreatChance);
        SetLocalFloat(oItem, "AI_OFFHAND_AVG_DMG", fOffHandAvgDmg);
        if(AI_DEBUG) ai_Debug("0i_items", "790", GetName(oItem) + " fOffHandAvgDmg: " + FloatToString(fOffHandAvgDmg, 0, 2));
        // Return the correct value based on params passed.
        if(oOffWeapon != OBJECT_INVALID)
        {
            // This is used only for double weapons! Must pass b2Handed = TRUE and
            // oOffWeapon = the double weapon that was passes as oItem.
            if(b2Handed) return fMain2HandAvgDmg + fOffHandAvgDmg;
            return fMain2HandAvgDmg;
        }
        if(bOffHand) return fOffHandAvgDmg;
    }
    return fAvgDmg;
}
int ai_SetShieldAC(object oCreature, object oItem)
{
    if(oCreature == GetLocalObject(oItem, "AI_CREATURE_POSSESSION"))
    {
        return GetLocalInt(oItem, "AI_SHIELD_AC");
    }
    // Set the creature who has this item for setting the power of.
    SetLocalObject(oItem, "AI_CREATURE_POSSESSION", oCreature);
    int nItemType = GetBaseItemType(oItem);
    int nAC, nItemPropertyType;
    if(nItemType == BASE_ITEM_SMALLSHIELD) nAC = 1;
    else if(nItemType == BASE_ITEM_LARGESHIELD) nAC = 2;
    else if(nItemType == BASE_ITEM_TOWERSHIELD) nAC = 3;
    itemproperty ipProperty = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ipProperty))
    {
        nItemPropertyType = GetItemPropertyType(ipProperty);
        if(nItemPropertyType == ITEM_PROPERTY_AC_BONUS)
        {
            nAC += GetItemPropertyCostTableValue(ipProperty);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_DECREASED_AC)
        {
            nAC -= GetItemPropertyCostTableValue(ipProperty);
        }
        else if(nItemPropertyType == ITEM_PROPERTY_HASTE)
        {
            nAC += 4;
        }
        ipProperty = GetNextItemProperty(oItem);
    }
    SetLocalInt(oItem, "AI_SHIELD_AC", nAC);
    if(AI_DEBUG) ai_Debug("0i_items", "718", GetName(oItem) + " nAC: " + IntToString(nAC));
    return nAC;
}
int ai_GetHasItemProperty(object oItem, int nItemPropertyType, int nItemPropertySubType = -1)
{
    itemproperty ipProperty = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ipProperty))
    {
        if(GetItemPropertyType(ipProperty) == nItemPropertyType)
        {
            if(nItemPropertySubType > -1)
            {
                if(GetItemPropertySubType(ipProperty) == nItemPropertySubType) return TRUE;
            }
            else return TRUE;
        }
        ipProperty = GetNextItemProperty(oItem);
    }
    return FALSE;
}
object ai_GetBestPicks(object oCreature, int nLockDC)
{
    int nSkill = GetSkillRank(SKILL_OPEN_LOCK, oCreature);
    int nBonus, nBestBonus = 99, nNeededBonus = nLockDC - nSkill - 20;
    //ai_Debug("0i_items", "651", "nNeededBonus: " + IntToString(nNeededBonus));
    // We don't need to use any picks!
    if(nNeededBonus < 1) return OBJECT_INVALID;
    object oBestItem = OBJECT_INVALID;
    object oItem = GetFirstItemInInventory(oCreature);
    while(oItem != OBJECT_INVALID)
    {
        if(GetBaseItemType(oItem) == BASE_ITEM_THIEVESTOOLS)
        {
            // Get the tools bonus.
            itemproperty ipProperty = GetFirstItemProperty(oItem);
            while(GetIsItemPropertyValid(ipProperty))
            {
                if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_THIEVES_TOOLS)
                {
                    nBonus = GetItemPropertyCostTableValue(ipProperty);
                    if(nBonus >= nNeededBonus && nBonus < nBestBonus)
                    {
                        nBestBonus = nBonus;
                        oBestItem = oItem;
                        SetLocalInt(oBestItem, "AI_BONUS", nBestBonus);
                        break;
                    }
                }
                ipProperty = GetNextItemProperty(oItem);
            }
        }
        oItem = GetNextItemInInventory(oCreature);
    }
    return oBestItem;
}
void ai_RemoveInventory(object oCreature)
{
    object oItem = GetFirstItemInInventory(oCreature);
    while(oItem != OBJECT_INVALID)
    {
        DestroyObject(oItem);
        oItem = GetNextItemInInventory(oCreature);
    }
    int nIndex;
    for(nIndex = 0; nIndex <= 13; nIndex++)
    {
        oItem = GetItemInSlot(nIndex, oCreature);
        DestroyObject(oItem);
    }
}
void ai_MoveInventory(object oOldHenchman, object oNewHenchman)
{
    // Move all inventory items.
    object oItem = GetFirstItemInInventory(oOldHenchman);
    while(oItem != OBJECT_INVALID)
    {
        CopyItem(oItem, oNewHenchman, TRUE);
        oItem = GetNextItemInInventory(oOldHenchman);
    }
    // Move all equiped items and equip on oNewHenchman.
    int nIndex;
    object oNewItem;
    for(nIndex = 0; nIndex <= 13; nIndex++)
    {
        oItem = GetItemInSlot(nIndex, oOldHenchman);
        if(oItem != OBJECT_INVALID)
        {
            oNewItem = CopyItem(oItem, oNewHenchman, TRUE);
            if(!GetIdentified(oNewItem)) SetIdentified(oNewItem, TRUE);
            ActionEquipItem(oNewItem, nIndex);
        }
    }
}
int prc_IsProficient(object oCreature, int nBaseItem)
{
    switch(nBaseItem)
    {
        //special case: counts as simple for chitine
        case BASE_ITEM_SHORTSWORD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature)
                 || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 && GetRacialType(oCreature) == 76/*RACIAL_TYPE_CHITINE*/)
                 || GetHasFeat(7901/*FEAT_WEAPON_PROFICIENCY_SHORTSWORD*/, oCreature);

        case BASE_ITEM_LONGSWORD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature)
                 || GetHasFeat(7902/*FEAT_WEAPON_PROFICIENCY_LONGSWORD*/, oCreature);

        case BASE_ITEM_BATTLEAXE:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 && GetRacialType(oCreature) == 216/*RACIAL_TYPE_GNOLL*/)
                 || GetHasFeat(7903/*FEAT_WEAPON_PROFICIENCY_BATTLEAXE*/, oCreature);

        case BASE_ITEM_BASTARDSWORD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature)
                 || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature)
                 || GetHasFeat(7904/*FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD*/, oCreature);

        case BASE_ITEM_LIGHTFLAIL:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(7905/*FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL*/, oCreature);

        case BASE_ITEM_WARHAMMER:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(7906/*FEAT_WEAPON_PROFICIENCY_WARHAMMER*/, oCreature);

        case BASE_ITEM_LONGBOW:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature)
                 || GetHasFeat(7907/*FEAT_WEAPON_PROFICIENCY_LONGBOW*/, oCreature);

        case BASE_ITEM_LIGHTMACE:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(7908/*FEAT_WEAPON_PROFICIENCY_LIGHT_MACE*/, oCreature);

        case BASE_ITEM_HALBERD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(7909/*FEAT_WEAPON_PROFICIENCY_HALBERD*/, oCreature);

        case BASE_ITEM_SHORTBOW:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature)
                 || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 && GetRacialType(oCreature) == 216/*RACIAL_TYPE_GNOLL*/)
                 || GetHasFeat(7910/*FEAT_WEAPON_PROFICIENCY_SHORTBOW*/, oCreature);

        case BASE_ITEM_TWOBLADEDSWORD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature)
                 || GetHasFeat(7911/*FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD*/, oCreature);

        case BASE_ITEM_GREATSWORD:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(7912/*FEAT_WEAPON_PROFICIENCY_GREATSWORD*/, oCreature);

        case BASE_ITEM_GREATAXE:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(7913/*FEAT_WEAPON_PROFICIENCY_GREATAXE*/, oCreature);

        case BASE_ITEM_DART:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature)
                 || GetHasFeat(7914/*FEAT_WEAPON_PROFICIENCY_DART*/, oCreature);

        case BASE_ITEM_DIREMACE:
            return GetHasFeat(7915/*FEAT_WEAPON_PROFICIENCY_DIRE_MACE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_DOUBLEAXE:
            return GetHasFeat(7916/*FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_HEAVYFLAIL:
            return GetHasFeat(7917/*FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case BASE_ITEM_LIGHTHAMMER:
            return GetHasFeat(7918/*FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case BASE_ITEM_HANDAXE:
            return GetHasFeat(7919/*FEAT_WEAPON_PROFICIENCY_HANDAXE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature);

        case BASE_ITEM_KAMA:
            return GetHasFeat(7920/*FEAT_WEAPON_PROFICIENCY_KAMA*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_KATANA:
            return GetHasFeat(7921/*FEAT_WEAPON_PROFICIENCY_KATANA*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_KUKRI:
            return GetHasFeat(7922/*FEAT_WEAPON_PROFICIENCY_KUKRI*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_MORNINGSTAR:
            return GetHasFeat(7923/*FEAT_WEAPON_PROFICIENCY_MORNINGSTAR*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature);

        case BASE_ITEM_QUARTERSTAFF:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_WIZARD, oCreature);

        case BASE_ITEM_RAPIER:
            return GetHasFeat(7924/*FEAT_WEAPON_PROFICIENCY_RAPIER*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELF, oCreature);

        case BASE_ITEM_SCIMITAR:
            return GetHasFeat(7925/*FEAT_WEAPON_PROFICIENCY_SCIMITAR*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature);

        case BASE_ITEM_SCYTHE:
            return GetHasFeat(7926/*FEAT_WEAPON_PROFICIENCY_SCYTHE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case BASE_ITEM_SHORTSPEAR:
            return GetHasFeat(7927/*FEAT_WEAPON_PROFICIENCY_SHORTSPEAR*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature);

        case BASE_ITEM_SHURIKEN:
             return GetHasFeat(7928/*FEAT_WEAPON_PROFICIENCY_SHURIKEN*/, oCreature)
                  || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature)
                  || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature);

        case BASE_ITEM_SICKLE:
            return GetHasFeat(7929/*FEAT_WEAPON_PROFICIENCY_SICKLE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature);

        case BASE_ITEM_SLING:
            return GetHasFeat(7930/*FEAT_WEAPON_PROFICIENCY_SLING*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature);

        case BASE_ITEM_THROWINGAXE:
            return GetHasFeat(7931/*FEAT_WEAPON_PROFICIENCY_THROWING_AXE*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 || GetHasFeat(3600/*FEAT_MINDBLADE*/, oCreature);

        case BASE_ITEM_CSLASHWEAPON:
        case BASE_ITEM_CPIERCWEAPON:
        case BASE_ITEM_CBLUDGWEAPON:
        case BASE_ITEM_CSLSHPRCWEAP:
            return GetHasFeat(FEAT_WEAPON_PROFICIENCY_CREATURE, oCreature);

        case BASE_ITEM_TRIDENT:
            return GetHasFeat(7932/*FEAT_WEAPON_PROFICIENCY_TRIDENT*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_DRUID, oCreature);

        case 124://BASE_ITEM_DOUBLE_SCIMITAR:
            return GetHasFeat(7948/*FEAT_WEAPON_PROFICIENCY_DOUBLE_SCIMITAR*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case 119://BASE_ITEM_FALCHION:
            return GetHasFeat(7943/*FEAT_WEAPON_PROFICIENCY_FALCHION*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case 125://BASE_ITEM_GOAD:
            return GetHasFeat(7949/*FEAT_WEAPON_PROFICIENCY_GOAD*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature);

        case 122://BASE_ITEM_HEAVY_MACE:
            return GetHasFeat(7946/*FEAT_WEAPON_PROFICIENCY_HEAVY_MACE*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_SIMPLE, oCreature);

        case 115://BASE_ITEM_HEAVY_PICK:
            return GetHasFeat(7939/*FEAT_WEAPON_PROFICIENCY_HEAVY_PICK*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case 116://BASE_ITEM_LIGHT_PICK:
            return GetHasFeat(7940/*FEAT_WEAPON_PROFICIENCY_LIGHT_PICK*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case 121://BASE_ITEM_KATAR:
            return GetHasFeat(7945/*FEAT_WEAPON_PROFICIENCY_KATAR*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case 123://BASE_ITEM_MAUL:
            return GetHasFeat(7947/*FEAT_WEAPON_PROFICIENCY_MAUL*/, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        case 118://BASE_ITEM_NUNCHAKU:
            return GetHasFeat(7942/*FEAT_WEAPON_PROFICIENCY_NUNCHAKU*/, oCreature)
                                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case 117://BASE_ITEM_SAI:
            return GetHasFeat(7941/*FEAT_WEAPON_PROFICIENCY_SAI*/, oCreature)
                                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MONK, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case 120://BASE_ITEM_SAP:
            return GetHasFeat(7944/*FEAT_WEAPON_PROFICIENCY_SAP*/, oCreature)
                                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_ROGUE, oCreature)
                || GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature);

        //special case: counts as martial for dwarves
        case BASE_ITEM_DWARVENWARAXE:
            return GetHasFeat(7933/*FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE*/, oCreature)
                 || (GetHasFeat(FEAT_WEAPON_PROFICIENCY_MARTIAL, oCreature)
                 && GetHasFeat(4710/*FEAT_DWARVEN*/, oCreature))
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);

        case BASE_ITEM_WHIP:
            return GetHasFeat(7934/*FEAT_WEAPON_PROFICIENCY_WHIP*/, oCreature)
                 || GetHasFeat(FEAT_WEAPON_PROFICIENCY_EXOTIC, oCreature);
    }
    return TRUE;
}
int ai_GetItemUses(object oItem, int nItemPropertySubType)
{
    int nUses;
    itemproperty ipProperty = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ipProperty))
    {
        if(GetItemPropertyType(ipProperty) == ITEM_PROPERTY_HEALERS_KIT) return GetItemStackSize(oItem);
        if(nItemPropertySubType > -1)
        {
            if(GetItemPropertySubType(ipProperty) == nItemPropertySubType)
            {
                // Get how they use the item (charges or uses per day).
                nUses = GetItemPropertyCostTableValue(ipProperty);
                if(nUses == 1) return GetItemStackSize(oItem);
                else if(nUses > 1 && nUses < 7) return GetItemCharges(oItem);
                else if(nUses == 7 || nUses == 13) return 999;
                else if(nUses > 7 && nUses < 13) return GetItemPropertyUsesPerDayRemaining(oItem, ipProperty);
            }
        }
        else return TRUE;
        ipProperty = GetNextItemProperty(oItem);
    }
    return FALSE;
}

