//#include "x2_inc_ws_smith"
#include "prc_x2_itemprop"
#include "inc_misc_tools"
// Handles functions of thieves' tools.
void ThiefTools(object oPC,object oTarget, int iMod = 0);
// Allows easy scripting of item spell uses.
void ItemCastSpellAtObject(object oUser,int iSpell, object oTarget = OBJECT_INVALID);
// Allows easy scripting of item spell uses.
void ItemCastSpellAtLocation(object oUser,int iSpell, location lLoc);
// Handles functions of Figurines of Wonderous Power.
void FigurineWonderousPower(object oPC, object oFigurine, string sResRef,location lLoc);
// Allows a cleric/paladin to turn undead at iMod levels above thri real level.
void TurnUndead(object oPC,int iMod);
// Handles the Horn of Blasting
void HornOfBlasting (location lTarget);
// Effects for Pipes of Pain
void PipesOfPain();
// Handles special effects for the mask of the skull.
void MaskOfTheSkull(object oTarget);
// This handles the horn of Valhalla summons
void Miscc039(int iNumber, string sResRef, int iFriendly = FALSE);
// This handles the Shield of Absorption rules.
void ShieldOfAbsorption(object oPC);
// Removes Damage Reduction from Golems.
void GolemBane(object oSkin);
// This function returns true is a weapon is a Slashing weapon.
int GetWeaponSlashing(object oWeapon);
// This function returns true is a weapon is a Piercing weapon.
int GetWeaponPiercing(object oWeapon);
// This function returns true is a weapon is a Bludgeoning weapon.
int GetWeaponBludgeoning(object oWeapon);
// Returns TRUE if oItem is a weapon or ammunition.
int GetIsWeapon(object oItem);
// Returns TRUE if oItem is an armor or shield
int GetIsArmor(object oItem);
// Returns TRUE if oItem is a shield
int GetIsShield(object oItem);
// Returns the enchantment bonus on an item
// This function only works on armor and weapons
// This function will not work on RDG Ammo
int GetEnchantmentBonus(object oItem);
// Returns the base armor class of a magic armor.
int GetBaseArmorClass(object oItem);
// Returns the DMG gold piece value of any RDG enchanted item.
// iMod allows you to return a value higher what the item has.
// This function will not work on ammunition.
// WARNING THIS CAN BE A VERY INTENSIVE FUNCTION DO NOT LOOP
int GetTotalEnchantmentValue(object oItem,int iMod = 0);
// Returns TRUE is oItem is an ammunition type.
int GetIsAmmo(object oItem);
// Returns TRUE if the ranged weapon uses ammo.
// Darts as an example will return FALSE.
int GetIsLauncher(object oItem);
// Sets the gold in a container equal to iGold.
// This function will not work on creatures.
void DestroyGold(object oBox = OBJECT_SELF);
// This funtion will cause oDoor to open if it's not locked.
void MageHand (object oDoor);
// Returns the item property race to be a special bonus towards
int GetBaneRace();
// Returns teh enchantment bonus of a weapon.
// Attack bonus of a ranged weapon.
// AC bonus of armor or shields.
int ReturnItemBonus(object oItem, int ip);
// This funtion is used by items that allow a person to go upwards thru a pit trap.
// Example: Ring of Climbing.
void Fly();
// THis function will return the XP expense to create an item.
int GetItemXPCost(object oItem,int iMod = 0);
void ThiefTools(object oPC, object oTarget,int iMod)
    {
    int iDC = GetLocalInt(oTarget,"TrapDC");
    int iRoll,iOOPS;
    int iAnim = GetObjectType(oTarget);
    int iType = GetLocalInt(oTarget,"TrapType");
    AssignCommand(oPC,ClearAllActions());
    switch(iAnim)
        {
        case OBJECT_TYPE_DOOR: {AssignCommand(oPC,ActionPlayAnimation(ANIMATION_FIREFORGET_STEAL,6.0));break;}
        case OBJECT_TYPE_PLACEABLE: {AssignCommand(oPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,6.0));break;}
        case OBJECT_TYPE_TRIGGER:   {AssignCommand(oPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,6.0));break;}
        break;
        }
    if (GetIsTrapped(oTarget) && GetTrapDetectedBy(oTarget,oPC))
        {
        if (!iDC)
            iDC = ScaledDC(PartyLevel(oPC));
        if (GetIsInCombat(oPC))
            iRoll = d20() + GetSkillRank(SKILL_DISABLE_TRAP,oPC) + iMod;
        else iRoll = 20 + GetSkillRank(SKILL_DISABLE_TRAP,oPC) + iMod;

        if (iType > 1 && iDC >=25 && !GetLevelByClass(CLASS_TYPE_ROGUE,oPC))
            iOOPS = TRUE;
        else if (iRoll >= iDC)
            {
            DeleteLocalInt(oTarget,"Pit");// Had to add this to prevent pit trapped doors from having odd transitions
            SetTrapDisabled(oTarget);
            AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_TASKCOMPLETE,oPC));
            }
        else if (iRoll >= iDC-5)
            {
            SetLocalInt(oTarget,"Flagged",TRUE); // Kill trap heartbeat
            AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_CANTDO,oPC));
            oPC = GetFirstFactionMember(oPC);
            while (GetIsObjectValid(oPC))
                {
                SetTrapDetectedBy(oTarget,oPC);
                oPC = GetNextFactionMember(oPC);
                FloatingTextStringOnCreature("Trap flagged.",oPC);
                SetLocalInt(oTarget,"TrapDC",iDC);
                }
            }
        else if (iDC >= iRoll + 10)
            iOOPS = TRUE;
        else
            {
            SetLocalInt(oTarget,"TrapDC",iDC);
            AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_BADIDEA,oPC));
            SendMessageToPC(oPC,"Failed Skill Check: " +IntToString(iRoll) + " vs. DC: " +IntToString(iDC));
            }
        }
    else if (GetIsTrapped(oTarget)) // Trapped and not detected
        iOOPS = TRUE;
    else if (GetLocked(oTarget))
        {
        iDC = GetLocalInt(oTarget,"LockDC");
        if (!iDC)
            {
            if (iAnim == OBJECT_TYPE_DOOR && d100() <= JAMMED_DOOR)
                iDC = 100;
            else
                iDC = ScaledDC(PartyLevel(oPC));
            }
        if (GetIsInCombat(oPC))
            iRoll = d20() + GetSkillRank(SKILL_OPEN_LOCK,oPC) + iMod;
        else
            iRoll = 20 + GetSkillRank(SKILL_OPEN_LOCK,oPC) + iMod;
        if (iRoll >= iDC)
            {
            SetLocked(oTarget,FALSE);
            AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_TASKCOMPLETE,oPC));
            }
        else
            {
            SetLocalInt(oTarget,"LockDC",iDC);
            AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_CUSS,oPC));
            }
        }
    if (iOOPS)                     // Trap goes off.
        {
        AssignCommand(oPC,ClearAllActions(TRUE));
        AssignCommand(oTarget,ApplyTrap(oPC));
        AssignCommand(oPC,PlayVoiceChat(VOICE_CHAT_BADIDEA,oPC));
        }
    }

void ItemCastSpellAtObject(object oUser,int iSpell, object oTarget = OBJECT_INVALID)
    {
    if (!GetIsObjectValid(oTarget))
        oTarget = oUser;
    AssignCommand(oUser,ActionCastSpellAtObject(iSpell ,oTarget,METAMAGIC_ANY,TRUE,0,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
    }

void ItemCastSpellAtLocation(object oUser,int iSpell, location lLoc)
    {
    AssignCommand(oUser,ActionCastSpellAtLocation(iSpell ,lLoc ,METAMAGIC_ANY,TRUE,PROJECTILE_PATH_TYPE_DEFAULT,TRUE));
    }

void FigurineWonderousPower(object oPC, object oItem, string sResRef,location lLoc)
    {
    object oTemp = CreateObject(OBJECT_TYPE_CREATURE,sResRef,lLoc);
    effect eVis;
    AddHenchman(oPC,oTemp);
    AssignCommand(oTemp,ActionTakeItem(oItem,oPC));
    }

void TurnUndead(object oPC,int iMod)
    {
    if (!GetHasFeat(FEAT_TURN_UNDEAD ,oPC))
        return;
    effect eTurned = EffectLinkEffects(EffectTurned(),EffectVisualEffect(VFX_IMP_FEAR_S));
    int iLevel = GetLevelByClass(CLASS_TYPE_CLERIC,oPC); //This is the cleric level you want the rod to be based on.
    if (!iLevel)
        iLevel = GetLevelByClass(CLASS_TYPE_PALADIN,oPC) - 2;
    iLevel += iMod;
    int iMaxHD;
    int iCharisma = GetAbilityModifier(ABILITY_CHARISMA,oPC);
    // Determine Max Level of Undead turned.
    int iCheck = d20() + iCharisma;
    if (iCheck <= 0) iMaxHD = iLevel -4;
    else if (iCheck <= 3)   iMaxHD = iLevel - 3;
    else if (iCheck <= 6)   iMaxHD = iLevel - 2;
    else if (iCheck <= 9)   iMaxHD = iLevel - 1;
    else if (iCheck <= 12)  iMaxHD = iLevel + 0;//Included for completeness
    else if (iCheck <= 15)  iMaxHD = iLevel + 1;
    else if (iCheck <= 18)  iMaxHD = iLevel + 2;
    else if (iCheck <= 21)  iMaxHD = iLevel + 3;
    else                    iMaxHD = iLevel + 4;
    int iTotalHD = d6(2) + iLevel + iCharisma;
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_IMP_RESTORATION_GREATER),oPC,3.0);
    object oTarget;
    int i;
    int j;
    for (i = 1; i <= iMaxHD;i++) //Test all undead cycling from 1 HD to iLevel HD
        {
        j = 1;
        object oTarget = GetNearestCreature(CREATURE_TYPE_RACIAL_TYPE,RACIAL_TYPE_UNDEAD,oPC,j);
        while (GetIsObjectValid(oTarget) && iLevel > 0)
            {
            if (GetHitDice(oTarget) == i
             && GetDistanceBetween(oPC,oTarget) < FeetToMeters(60.0))
                {
                if (i <= iLevel/2)
                    AssignCommand(oPC,ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectDeath(TRUE),oTarget));
                else
                    AssignCommand(oPC,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eTurned,oTarget,RoundsToSeconds(10)));
                iTotalHD += -i;
                if (iTotalHD < i)
                    break; // Break while loop if remaining turned levels is less than tested undead
                }
            oTarget = GetNearestCreature(CREATURE_TYPE_RACIAL_TYPE,RACIAL_TYPE_UNDEAD,oPC,j+=1);
            }
        if (iTotalHD < i)
            break; // Break the for loop and terminate script.
        }
    DecrementRemainingFeatUses(oPC,FEAT_TURN_UNDEAD);
    }

void HornOfBlasting (location lTarget)
    {
    effect eDam = EffectLinkEffects(EffectDamage(d10(),DAMAGE_TYPE_SONIC),EffectVisualEffect(VFX_FNF_SOUND_BURST));
    effect eDaze = EffectDazed();
    effect eDeaf = EffectDeaf();
    int iSave;
    object oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, 11.0, lTarget, TRUE, OBJECT_TYPE_ALL);
    while(GetIsObjectValid(oTarget))
        {
        iSave = FortitudeSave(oTarget,16,SAVING_THROW_TYPE_SONIC);
        if (iSave == 0)
            {
            ApplyEffectToObject(DURATION_TYPE_INSTANT,eDam,oTarget);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDaze,oTarget,RoundsToSeconds(2));
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDeaf,oTarget,RoundsToSeconds(4));
            }
        else if (iSave == 1)
            {
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDaze,oTarget,RoundsToSeconds(1));
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eDeaf,oTarget,RoundsToSeconds(2));
            }
        oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, 11.0, lTarget, TRUE, OBJECT_TYPE_ALL);
        }
    }

void PipesOfPain()
    {
    location lLoc = GetLocation(OBJECT_SELF);
    int i,iTemp;
    effect eTemp = EffectCurse(0,0,0,0,0,0);
    eTemp = EffectLinkEffects(eTemp,EffectAttackDecrease(2));
    eTemp = EffectLinkEffects(eTemp,EffectSkillDecrease(SKILL_ALL_SKILLS,2));
    eTemp = EffectLinkEffects(eTemp,EffectSavingThrowDecrease(SAVING_THROW_ALL,2));
    effect eTemp2;
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE,FeetToMeters(30.0),lLoc,FALSE);
    while (GetIsObjectValid(oTarget))
        {
        if (!WillSave(oTarget,14,SAVING_THROW_TYPE_MIND_SPELLS))
            {
            iTemp = d4(2);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_FNF_HOWL_MIND),oTarget);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eTemp,oTarget,RoundsToSeconds(iTemp));
            for (i = 1; i<= iTemp; i++)
                {
                eTemp2 = EffectLinkEffects(EffectDamage(d4(),DAMAGE_TYPE_SONIC),EffectVisualEffect(VFX_IMP_HEAD_SONIC));
                DelayCommand(RoundsToSeconds(i),CurseDamage(OBJECT_SELF,eTemp2,oTarget));
                }
            }
        oTarget = GetNextObjectInShape(SHAPE_SPHERE,FeetToMeters(30.0),lLoc,FALSE);
        }
    }

void MaskOfTheSkull(object oTarget)
    {
    if (TouchAttackRanged(oTarget))
        {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_IMP_MIRV),oTarget);
        if (!FortitudeSave(oTarget,20,SAVING_THROW_TYPE_DEATH))
            DelayCommand(1.0,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectDeath(TRUE),oTarget));
        else
            DelayCommand(1.0,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectDamage(d6(3)+13,DAMAGE_TYPE_NEGATIVE),oTarget));
        }
    else
        {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_IMP_MIRV,TRUE),oTarget);
        }
    }

void Miscc039(int iNumber, string sResRef, int iFriendly)
    {
    PlaySound("as_cv_eulpipe1");
    int i;
    object oBarbarian;
    for (i = 1; i <= iNumber; i++)
        {
        oBarbarian = CreateObject(OBJECT_TYPE_CREATURE,sResRef,GetLocation(OBJECT_SELF));
        if (!iFriendly)
            ChangeToStandardFaction(oBarbarian,STANDARD_FACTION_HOSTILE);
        }
    }

void ShieldOfAbsorption(object oPC)
    {
    object oTarget;
    object oHostile = GetFirstObjectInArea();
    while(GetIsObjectValid(oHostile))
        {
        if (GetObjectType(oHostile) == OBJECT_TYPE_CREATURE)
            {
            oTarget = GetAttackTarget(oHostile);
            if (oTarget == oPC && !GetWeaponRanged(GetLastWeaponUsed(oHostile)))
                if (GetCreatureSize(oHostile) == CREATURE_SIZE_TINY
                 | CREATURE_SIZE_SMALL
                 | CREATURE_SIZE_MEDIUM
                 | CREATURE_SIZE_LARGE)
                {
                AssignCommand(oHostile,AwardXPs(oPC));
                AssignCommand(oPC,DestroyObject(oHostile));
                }
            }
        oHostile = GetNextObjectInArea();
        }
    }

void GolemBane(object oSkin)
    {
    itemproperty ipItem = GetFirstItemProperty(oSkin);
    while (GetIsItemPropertyValid(ipItem))
        {
        if (GetItemPropertyType(ipItem) == ITEM_PROPERTY_DAMAGE_RESISTANCE)
            {
            RemoveItemProperty(oSkin,ipItem);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_FNF_TIME_STOP),GetItemPossessor(oSkin),6.0);
            }
        ipItem = GetNextItemProperty(oSkin);
        }
    }

int GetWeaponSlashing(object oWeapon)
    {
    int iType = GetBaseItemType(oWeapon);
    if (iType == BASE_ITEM_BASTARDSWORD
     || iType == BASE_ITEM_BATTLEAXE
     || iType == BASE_ITEM_DOUBLEAXE
     || iType == BASE_ITEM_DWARVENWARAXE
     || iType == BASE_ITEM_GREATAXE
     || iType == BASE_ITEM_GREATSWORD
     || iType == BASE_ITEM_HALBERD
     || iType == BASE_ITEM_HANDAXE
     || iType == BASE_ITEM_KAMA
     || iType == BASE_ITEM_KATANA
     || iType == BASE_ITEM_KUKRI
     || iType == BASE_ITEM_LONGSWORD
     || iType == BASE_ITEM_SCIMITAR
     || iType == BASE_ITEM_SCYTHE
     || iType == BASE_ITEM_SICKLE
     || iType == BASE_ITEM_TWOBLADEDSWORD
     || iType == BASE_ITEM_WHIP)
        return TRUE;
    return FALSE;
    }

int GetWeaponPiercing(object oWeapon)
    {
    int iType = GetBaseItemType(oWeapon);
    if (iType == BASE_ITEM_ARROW
     || iType == BASE_ITEM_BOLT
     || iType == BASE_ITEM_CPIERCWEAPON
     || iType == BASE_ITEM_DAGGER
     || iType == BASE_ITEM_DART
     || iType == BASE_ITEM_BASTARDSWORD
     || iType == BASE_ITEM_DOUBLEAXE
     || iType == BASE_ITEM_GREATSWORD
     || iType == BASE_ITEM_HALBERD
     || iType == BASE_ITEM_HEAVYCROSSBOW
     || iType == BASE_ITEM_KATANA
     || iType == BASE_ITEM_LIGHTCROSSBOW
     || iType == BASE_ITEM_LONGBOW
     || iType == BASE_ITEM_RAPIER
     || iType == BASE_ITEM_SCYTHE
     || iType == BASE_ITEM_SHORTBOW
     || iType == BASE_ITEM_SHORTSPEAR
     || iType == BASE_ITEM_SHORTSWORD
     || iType == BASE_ITEM_SHURIKEN)
        return TRUE;
    return FALSE;
    }

int GetWeaponBludgeoning(object oWeapon)
    {
    int iType = GetBaseItemType(oWeapon);
    if (iType == BASE_ITEM_BULLET
     || iType == BASE_ITEM_CBLUDGWEAPON
     || iType == BASE_ITEM_CLUB
     || iType == BASE_ITEM_DIREMACE
     || iType == BASE_ITEM_HEAVYFLAIL
     || iType == BASE_ITEM_LIGHTFLAIL
     || iType == BASE_ITEM_LIGHTHAMMER
     || iType == BASE_ITEM_LIGHTMACE
     || iType == BASE_ITEM_MORNINGSTAR
     || iType == BASE_ITEM_QUARTERSTAFF
     || iType == BASE_ITEM_SLING
     || iType == BASE_ITEM_WARHAMMER)
        return TRUE;
    return FALSE;
    }

int GetIsWeapon(object oItem)
    {
    int iType = GetBaseItemType(oItem);
    if (iType ==  BASE_ITEM_ARROW
     || iType == BASE_ITEM_BASTARDSWORD
     || iType == BASE_ITEM_BATTLEAXE
     || iType == BASE_ITEM_BOLT
     || iType == BASE_ITEM_BULLET
     || iType == BASE_ITEM_CLUB
     || iType == BASE_ITEM_DAGGER
     || iType == BASE_ITEM_DART
     || iType == BASE_ITEM_DIREMACE
     || iType == BASE_ITEM_DOUBLEAXE
     || iType == BASE_ITEM_DWARVENWARAXE
     || iType == BASE_ITEM_GREATAXE
     || iType == BASE_ITEM_GREATSWORD
     || iType == BASE_ITEM_GRENADE
     || iType == BASE_ITEM_HALBERD
     || iType == BASE_ITEM_HANDAXE
     || iType == BASE_ITEM_HEAVYCROSSBOW
     || iType == BASE_ITEM_HEAVYFLAIL
     || iType == BASE_ITEM_KAMA
     || iType == BASE_ITEM_KATANA
     || iType == BASE_ITEM_KUKRI
     || iType == BASE_ITEM_LIGHTCROSSBOW
     || iType == BASE_ITEM_LIGHTFLAIL
     || iType == BASE_ITEM_LIGHTHAMMER
     || iType == BASE_ITEM_LIGHTMACE
     || iType ==  BASE_ITEM_LONGBOW
     || iType == BASE_ITEM_LONGSWORD
     || iType == BASE_ITEM_MORNINGSTAR
     || iType == BASE_ITEM_QUARTERSTAFF
     || iType == BASE_ITEM_RAPIER
     || iType == BASE_ITEM_SCIMITAR
     || iType == BASE_ITEM_SCYTHE
     || iType == BASE_ITEM_SHORTBOW
     || iType == BASE_ITEM_SHORTSPEAR
     || iType == BASE_ITEM_SHORTSWORD
     || iType == BASE_ITEM_SHURIKEN
     || iType == BASE_ITEM_SICKLE
     || iType == BASE_ITEM_SLING
     || iType == BASE_ITEM_THROWINGAXE
     || iType == BASE_ITEM_TWOBLADEDSWORD
     || iType == BASE_ITEM_WARHAMMER
     || iType == BASE_ITEM_WHIP)
        return TRUE;
    return FALSE;
    }

int GetIsArmor(object oItem)
    {
    int iType = GetBaseItemType(oItem);
    if (iType ==  BASE_ITEM_ARMOR
     || iType == BASE_ITEM_LARGESHIELD
     || iType == BASE_ITEM_SMALLSHIELD
     || iType == BASE_ITEM_TOWERSHIELD)
        return TRUE;
    return FALSE;
    }

int GetIsShield(object oItem)
    {
    int iType = GetBaseItemType(oItem);
    if (iType == BASE_ITEM_LARGESHIELD
     || iType == BASE_ITEM_SMALLSHIELD
     || iType == BASE_ITEM_TOWERSHIELD)
        return TRUE;
    return FALSE;
    }

int GetIsAmmo(object oItem)
    {
    int iType = GetBaseItemType(oItem);
    if (iType == BASE_ITEM_ARROW
     || iType == BASE_ITEM_BOLT
     || iType == BASE_ITEM_BULLET)
        return TRUE;
    return FALSE;
    }

int GetIsLauncher(object oItem)
    {
    {
    int iType = GetBaseItemType(oItem);
    if (iType == BASE_ITEM_HEAVYCROSSBOW
     || iType == BASE_ITEM_LIGHTCROSSBOW
     || iType == BASE_ITEM_LONGBOW
     || iType == BASE_ITEM_SHORTBOW
     || iType == BASE_ITEM_SLING)
        return TRUE;
    return FALSE;
    }
    }

int GetBaseArmorClass(object oItem)
    {
    return GetItemACValue(oItem) - GetEnchantmentBonus(oItem);
    }

int GetEnchantmentBonus(object oItem)
    {
    int i;
    int iType = GetBaseItemType(oItem);
    int ipItem;
    if (GetIsArmor(oItem))
        ipItem = ITEM_PROPERTY_AC_BONUS;
    else if (GetIsLauncher(oItem))
        ipItem = ITEM_PROPERTY_ATTACK_BONUS;
    else
        ipItem = ITEM_PROPERTY_ENHANCEMENT_BONUS;
    return ReturnItemBonus(oItem,ipItem);
    }

int GetTotalEnchantmentValue(object oItem,int iMod)
    {
    int iEnc = GetLocalInt(oItem,"Enc");
    int iArmor = GetIsArmor(oItem);
    int iWeapon = GetIsWeapon(oItem);
    if (!iEnc && (iArmor|| iWeapon))
        {
        iEnc = GetEnchantmentBonus(oItem);
        if (iEnc > 0)// This seems like a lot of hidden loops runnig back to back. I know it has holes. Need to learn how to do the 2DA look ups properly before I can fix.
            {
            if (iWeapon)
                {
                if (GetWeaponRanged(oItem))
                    {
                    if (IPGetItemHasProperty(oItem,ItemPropertyUnlimitedAmmo(IP_CONST_UNLIMITEDAMMO_BASIC),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    else if (IPGetItemHasProperty(oItem,ItemPropertyUnlimitedAmmo(IP_CONST_UNLIMITEDAMMO_1D6FIRE),DURATION_TYPE_PERMANENT,TRUE))
                        iEnc+=2;// checks for all other unlimited ammo weapons.
                    if (IPGetItemHasProperty(oItem,ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY,IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE),DURATION_TYPE_PERMANENT)) // This property is used for all enchant the ammo weapons.
                        {
                        if (GetLocalInt(oItem,"DamageType") == IP_CONST_DAMAGETYPE_MAGICAL)
                            iEnc += 4;
                        else
                            iEnc+= 1;
                        }
                    }
                else
                    {
                    if (IPGetItemHasProperty(oItem,ItemPropertyACBonus(1),DURATION_TYPE_PERMANENT,TRUE))
                        iEnc+=1; // Checks for ALL defender weapons.
                    if (IPGetItemHasProperty(oItem,ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGEBONUS_1d6),DURATION_TYPE_PERMANENT))
                        iEnc+=4;
                    else if (IPGetItemHasProperty(oItem,ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGEBONUS_1d6),DURATION_TYPE_PERMANENT,TRUE))
                        iEnc+=1;// Checks for all all elemental weapons if not brillant
                    if (IPGetItemHasProperty(oItem,ItemPropertyKeen(),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyBonusFeat(IP_CONST_FEAT_CLEAVE),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyCastSpell(IP_CONST_CASTSPELL_BULLS_STRENGTH_3,IP_CONST_CASTSPELL_NUMUSES_1_USE_PER_DAY),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyOnHitProps(IP_CONST_ONHIT_SLAYRACE,IP_CONST_ONHIT_SAVEDC_14,IP_CONST_RACIALTYPE_UNDEAD),DURATION_TYPE_PERMANENT))
                        iEnc+=2;
                    if (IPGetItemHasProperty(oItem,ItemPropertyOnHitProps(IP_CONST_ONHIT_WOUNDING,IP_CONST_ONHIT_SAVEDC_20),DURATION_TYPE_PERMANENT))
                        iEnc+=2;
                    if (IPGetItemHasProperty(oItem,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_SLOW,IP_CONST_SPELLLEVEL_5),DURATION_TYPE_PERMANENT))
                        iEnc+=4;
                    if (IPGetItemHasProperty(oItem,ItemPropertyOnHitProps(IP_CONST_ONHIT_VORPAL,20),DURATION_TYPE_PERMANENT))
                        iEnc+=5;
                    }
                if (IPGetItemHasProperty(oItem,ItemPropertyEnhancementBonusVsRace(IP_CONST_RACIALTYPE_ABERRATION,2),DURATION_TYPE_PERMANENT,TRUE))
                    iEnc+=2;// Checks for all bane weapons. NOTE This is abuseable but is very expensive for the PC to do so
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),DURATION_TYPE_PERMANENT,TRUE))
                    iEnc+=2;// Checks for all alignment weapons. NOTE This is abuseable but is very expensive for the PC to do so
                if (IPGetItemHasProperty(oItem,ItemPropertyHaste(),DURATION_TYPE_PERMANENT))
                    iEnc+=4;
                }
            else // Armor and Shields
                {
                if (GetIsShield(oItem))
                    {
                    if (IPGetItemHasProperty(oItem,ItemPropertyBonusFeat(IP_CONST_FEAT_KNOCKDOWN),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyOnHitCastSpell(SPELL_BLINDNESS_AND_DEAFNESS,4),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_PIERCING,IP_CONST_DAMAGESOAK_5_HP),DURATION_TYPE_PERMANENT))
                        iEnc+=2;
                    if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_PIERCING,IP_CONST_DAMAGESOAK_10_HP),DURATION_TYPE_PERMANENT))
                        iEnc+=2;
                    }
                else
                    {
                    if (IPGetItemHasProperty(oItem,ItemPropertySkillBonus(SKILL_TUMBLE,10),DURATION_TYPE_PERMANENT))
                    iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertySkillBonus(SKILL_HIDE,10),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertySkillBonus(SKILL_MOVE_SILENTLY,10),DURATION_TYPE_PERMANENT))
                        iEnc+=1;
                    if (IPGetItemHasProperty(oItem,ItemPropertyCastSpell(IP_CONST_CASTSPELL_SPELL_MANTLE_13,IP_CONST_CASTSPELL_NUMUSES_1_USE_PER_DAY),DURATION_TYPE_PERMANENT))
                        iEnc+=5;
                    }

                if (IPGetItemHasProperty(oItem,ItemPropertyLight(IP_CONST_LIGHTBRIGHTNESS_BRIGHT,IP_CONST_LIGHTCOLOR_YELLOW),DURATION_TYPE_PERMANENT,TRUE))
                    iEnc+=1;
                if (IPGetItemHasProperty(oItem,ItemPropertyBonusSpellResistance(IP_CONST_SPELLRESISTANCEBONUS_20),DURATION_TYPE_PERMANENT))
                    iEnc+=5;
                else if (IPGetItemHasProperty(oItem,ItemPropertyBonusSpellResistance(IP_CONST_SPELLRESISTANCEBONUS_18),DURATION_TYPE_PERMANENT))
                    iEnc+=4;
                else if (IPGetItemHasProperty(oItem,ItemPropertyBonusSpellResistance(IP_CONST_SPELLRESISTANCEBONUS_16),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                else if (IPGetItemHasProperty(oItem,ItemPropertyBonusSpellResistance(IP_CONST_SPELLRESISTANCEBONUS_14),DURATION_TYPE_PERMANENT))
                    iEnc+=2;

                if (IPGetItemHasProperty(oItem,ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB),DURATION_TYPE_PERMANENT)
                 && IPGetItemHasProperty(oItem,ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_CRITICAL_HITS),DURATION_TYPE_PERMANENT)
                 && IPGetItemHasProperty(oItem,ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_KNOCKDOWN),DURATION_TYPE_PERMANENT))
                    iEnc+=5;
                else if (IPGetItemHasProperty(oItem,ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_CRITICAL_HITS),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                else if (IPGetItemHasProperty(oItem,ItemPropertyImmunityMisc(IP_CONST_IMMUNITYMISC_BACKSTAB),DURATION_TYPE_PERMANENT))
                    iEnc+=1;

                if (IPGetItemHasProperty(oItem,ItemPropertyTrueSeeing(),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ACID,IP_CONST_DAMAGERESIST_10),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGERESIST_10),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_FIRE,IP_CONST_DAMAGERESIST_10),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_ELECTRICAL,IP_CONST_DAMAGERESIST_10),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_SONIC,IP_CONST_DAMAGERESIST_10),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                if (IPGetItemHasProperty(oItem,ItemPropertyDamageReduction(IP_CONST_DAMAGEREDUCTION_1,IP_CONST_DAMAGESOAK_5_HP),DURATION_TYPE_PERMANENT))
                    iEnc+=3;
                }
            }
        SetLocalInt(oItem,"Enc",iEnc); // Now that item total enchantment has been found store it for future use.
        }
    int iMW = GetLocalInt(oItem,"MW");
    if (iEnc > 0)
        iMW = TRUE;
    iEnc += iMod;
    if (iEnc > 20) iEnc = 20; // This should not happen with a player made item but the random item generator CAN blow this limit.
    int iGold = GetLocalInt(oItem,"BaseValue");
    int iGold2;
    if (!iGold)
        iGold = GetGoldPieceValue(oItem);
    int iAC;
    if (iArmor|| iWeapon)
        {
        switch (iEnc)
            {
            case 0: break;
            case 1: {iGold2 += 2000;break;}
            case 2: {iGold2 += 8000;break;}
            case 3: {iGold2 += 18000;break;}
            case 4: {iGold2 += 32000;break;}
            case 5: {iGold2 += 50000;break;}
            case 6: {iGold2 += 720000;break;}
            case 7: {iGold2 += 980000;break;}
            case 8: {iGold2 += 1280000;break;}
            case 9: {iGold2 += 1620000;break;}
            case 10: {iGold2 += 2000000;break;}
            case 11: {iGold2 += 2420000;break;}
            case 12: {iGold2 += 2880000;break;}
            case 13: {iGold2 += 3380000;break;}
            case 14: {iGold2 += 3920000;break;}
            case 15: {iGold2 += 4500000;break;}
            case 16: {iGold2 += 5120000;break;}
            case 17: {iGold2 += 5780000;break;}
            case 18: {iGold2 += 6480000;break;}
            case 19: {iGold2 += 7220000;break;}
            case 20: {iGold2 += 8000000;break;}
            }
        if (iArmor)
            iGold2 = iGold2/2;
        iGold += iGold2;
        if (iMW)
            {
            if (iArmor) iGold += 150;
            else iGold +=300;
            }
        }
    return iGold;
    }

void DestroyGold(object oBox = OBJECT_SELF)
    {
    object oGold = GetFirstItemInInventory(oBox);
    while (GetIsObjectValid(oGold))
        {
        if (GetBaseItemType(oGold) == BASE_ITEM_GOLD)
            DestroyObject(oGold);
        oGold = GetNextItemInInventory(oBox);
        }
    }

int ReturnItemBonus(object oItem, int ipConstant)
    {
    itemproperty ipFirst = GetFirstItemProperty(oItem);
    int nBonus = 0;
    while (GetIsItemPropertyValid(ipFirst) == TRUE)
    {
        if (GetItemPropertyType(ipFirst) == ipConstant)
        {
            int nSubType = GetItemPropertyCostTableValue(ipFirst);
            //SpeakString("Found an attack bonus! SubType = " + IntToString(nSubType));
            nBonus = nBonus + (nSubType);
            return nBonus; // * Quick exit. Got what I need
        }
        ipFirst = GetNextItemProperty(oItem);
    }
    //SpeakString("Attack Bonus = " + IntToString(nBonus));
    return nBonus;
    }

int GetBaneRace()
    {
    int iRace;
    int iRoll = d100();
    if (iRoll <= 5) iRace = IP_CONST_RACIALTYPE_ABERRATION;
    else if (iRoll <= 8) iRace = IP_CONST_RACIALTYPE_ANIMAL;
    else if (iRoll <= 13) iRace = IP_CONST_RACIALTYPE_BEAST;
    else if (iRoll <= 20) iRace = IP_CONST_RACIALTYPE_CONSTRUCT;
    else if (iRoll <= 25) iRace = IP_CONST_RACIALTYPE_DRAGON;
    else if (iRoll <= 30) iRace = IP_CONST_RACIALTYPE_ELEMENTAL;
    else if (iRoll <= 35) iRace = IP_CONST_RACIALTYPE_FEY;
    else if (iRoll <= 40) iRace = IP_CONST_RACIALTYPE_GIANT;
    else if (iRoll <= 45) iRace = IP_CONST_RACIALTYPE_MAGICAL_BEAST;
    else if (iRoll <= 50)
        {
        iRoll = d4();
        if (iRoll = 1)      iRace = IP_CONST_RACIALTYPE_HUMANOID_GOBLINOID;
        else if (iRoll = 2) iRace = IP_CONST_RACIALTYPE_HUMANOID_MONSTROUS;
        else if (iRoll = 3) iRace = IP_CONST_RACIALTYPE_HUMANOID_ORC;
        else if (iRoll = 4) iRace = IP_CONST_RACIALTYPE_HUMANOID_REPTILIAN;
        }
    else if (iRoll <= 77) iRace = IP_CONST_RACIALTYPE_OUTSIDER;
    else if (iRoll <= 85) iRace = IP_CONST_RACIALTYPE_SHAPECHANGER;
    else if (iRoll <= 92) iRace = IP_CONST_RACIALTYPE_UNDEAD;
    else if (iRoll <= 94) iRace = IP_CONST_RACIALTYPE_VERMIN;
    else
        {
        iRoll = Random(7)+1;
        if (iRoll = 1)      iRace = IP_CONST_RACIALTYPE_DWARF;
        else if (iRoll = 2) iRace = IP_CONST_RACIALTYPE_ELF;
        else if (iRoll = 3) iRace = IP_CONST_RACIALTYPE_GNOME;
        else if (iRoll = 4) iRace = IP_CONST_RACIALTYPE_HALFELF;
        else if (iRoll = 5) iRace = IP_CONST_RACIALTYPE_HALFLING;
        else if (iRoll = 6) iRace = IP_CONST_RACIALTYPE_HALFORC;
        else                iRace = IP_CONST_RACIALTYPE_HUMAN;
        }
    return iRace;
    }

void MageHand (object oDoor)
    {
    effect eVis = EffectVisualEffect(VFX_DUR_BIGBYS_GRASPING_HAND);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eVis,oDoor,6.0);
    DelayCommand(3.0,AssignCommand(oDoor,ActionOpenDoor(oDoor)));
    }

void Fly()
    {
    object oFall = GetNearestObjectByTag("Fall");
    object oTrap = GetLocalObject(oFall,"Dest");
    if (GetDistanceToObject(oFall) <= 5.0)
        {
        if (GetIsObjectValid(oTrap))
            JumpToLocation(GetLocation(oTrap));
        }
    }

int GetItemXPCost(object oItem,int iMod = 0)
    {
    return GetTotalEnchantmentValue(oItem,iMod)/25;
    }
