Aller au contenu

Photo

Avoiding Bonus Spell Slot Loss When Shifting?


  • Veuillez vous connecter pour répondre
19 réponses à ce sujet

#1
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Pretty much what the title says.  I have a workaround to avoid spell slot loss due to losing casting stat (that said, is there a way to fire a script when an effect ends, in this case a polymorph?  Would be cleaner) but I'm driving myself crazy trying to figure out bonus spell slots.

1, if I add bonus spell slots to the new polymorph skin, it still loses the slots because the slots vanish for a second and erase the memorized spells

2, if I add bonus spell slots to the character's skin itself it simply doesn't apply while shifted.

3, if I add bonus spell slots to both it doesn't work either because, again, the slots vanish for a moment and erase the memorized spells

Anyone found a good way around these issues?

Modifié par MagicalMaster, 26 octobre 2013 - 02:44 .


#2
Shadooow

Shadooow
  • Members
  • 4 470 messages

MagicalMaster wrote...

(that said, is there a way to fire a script when an effect ends, in this case a polymorph?  Would be cleaner)

yes check this thread or complete solution that does this and much more - promoted in Community Patch thread.

as for the slots from items issue, I dont think there is a way to workaroud it without NWNX, with nwnx however there are several choices:

1) apply effect spell slot bonus instead of itemproperty
2) save and restore memorized slots before/after polymorph
3) edit polymorph so it does not unequip items
1,2 are possible to do with public plugins for both windows and linux, 3 is not public but I think Ive seen this somewhere maybe sinfar

#3
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
I can't use any solution that requires an override or hak (or won't in this case, at least -- Siege of the Heavens single player module with vanilla content) and that complete solution came with overrides. Are those overrides needed for that solution?

I'll probably fiddle around with that equip/unequip idea. But I already have a less-elegant but working solution so we'll see how it goes.

And can't use NWNX in this scenario. Sounds like I might just need to give up on preserving bonus spell slots from gear when shifting.

#4
Shadooow

Shadooow
  • Members
  • 4 470 messages

MagicalMaster wrote...

I can't use any solution that requires an override or hak (or won't in this case, at least -- Siege of the Heavens single player module with vanilla content) and that complete solution came with overrides. Are those overrides needed for that solution?

nope that polymorph.2da is only needed to fix temporary hitpoints replenishing and the package works without it - it uses the equip/unequip

its designed to be part of my unofficial hak in future, so there are extra functionalities you can turn on/off more info in my documentation but if you know scripting you can read what to set inside the scripts (libraries) yourself

if you have more questions, pm me

Modifié par ShaDoOoW, 26 octobre 2013 - 07:15 .


#5
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Yeah, I already started pulling it apart and learned something interesting things (I was wondering how you retrieved the actual Str/Dex/etc value from an item). Unfortunately I've already modified my shapeshifting scripts a bit so I won't be able to use your package as is, I'll need to pull relevant things out.

Does your package fix the bug where dying in Shapeshift form effectively removes all benefits from gear from the character until re-equipped or polymorphed again? Was going to try to simply re-Polymorph and un-Polymorph the player when they come back to life to fix it but I'm not sure if there's a better solution.

#6
Shadooow

Shadooow
  • Members
  • 4 470 messages

MagicalMaster wrote...

Does your package fix the bug where dying in Shapeshift form effectively removes all benefits from gear from the character until re-equipped or polymorphed again? Was going to try to simply re-Polymorph and un-Polymorph the player when they come back to life to fix it but I'm not sure if there's a better solution.

nope

pvp servers i know solves this via reequip all items option for player - but i got beter idea though untested but imo worth the shot

try removing and readding all itemproperties on all items

#7
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Seems more complicated than just repolymorphing them for half a second.

#8
HipMaestro

HipMaestro
  • Members
  • 1 515 messages

MagicalMaster wrote...
Seems more complicated than just repolymorphing them for half a second.

You may not need to repolymorph them at all, MM.  Consider...

Suppose you checked to see if/when the default polymorph script fires and then substitute your own polymorph script.  I know this has been done in vanilla because HotU contains these "wild magic" areas in one of the modules that produces some odd consequences, strange spell effects that are triggered.  

Then, once the default polymorph script has been neutralized, instead of your custom script calling on one of the default polymorph blueprints, call up a modified one that has adequate WIS and INT levels that would not wipe out the bous slots.  I don't think CHA-based spellcasting has this problem, does it? You may need to also add sufficent spellcaster levels to the blueprints so that the slots would be on the polymorphs, but they would, in essence be replicant versions of the class entering the area.  Not sure how you would handle players wearing equipment that provides bonus slots peripheral to the ability modifier, though.  

Trying to brainstorm a vanilla solution to this problem, folks.  The blind squirrel hoping to find a nut.

#9
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages

HipMaestro wrote...

You may not need to repolymorph them at all, MM.  Consider...


The repolymorphing is referring to the bug where items stop giving stats if you die wihle polymorphed, not the bonus spell slots

HipMaestro wrote...

Then, once the default polymorph script has been neutralized, instead of your custom script calling on one of the default polymorph blueprints, call up a modified one that has adequate WIS and INT levels that would not wipe out the bous slots.


Unfortunately, this would require modifying polymorph.2da since you'd need like 90+ wisdom (40+ modifier).

HipMaestro wrote...

I don't think CHA-based spellcasting has this problem, does it?


It does but you don't have to fix the spellbook each time so it's less of a big deal -- you lose the spells but don't have to mess with the spellbook each time.

HipMaestro wrote...

Not sure how you would handle players wearing equipment that provides bonus slots peripheral to the ability modifier, though.


It's the bonus slots that are the big issue :)  There's a number of workarounds for the ability modifier.  Bonus slots are much harder.

#10
Shadooow

Shadooow
  • Members
  • 4 470 messages
polymorph doesnt alter wis, int, cha

#11
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Oh, I see -- I knew Mindflayer increased Int and Cha but I didn't realize it was a scripted bonus rather than actually increasing the value. So yeah, editing the 2da wouldn't help.

#12
WhiZard

WhiZard
  • Members
  • 1 204 messages
Technically the int and wis bonuses from mindflayer are from item properties on the skin. (Inhibiting other int/wis bonuses from being merged).

#13
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Oh, even better. This is why I hate shifting in NWN : /

#14
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
We, after many attempts resolved the issue (losing item properties after dying while shifted) in Av3.  After digging I can't seem to pin it down (10+ years of development from 100+ developers will do that.)
Genisys however does have some work toward this aim I believe. And in fact we use some of it (not sure if this was the ultimate fix, but I think it is, or lead to it.) If you search the vault for Genisys I bet you can find the relevant scripts.
This is what we have, and sadly I can not tell you if this is all inclusive, or alone the final fix:
//Created by Genisys 5/4/08
//This OnActivateItem script works off the resref name of the items equipped.
//It allows those polymorphed who die to unequip all items and equip them again
//with just the use of this item. (Believe me I know how frustrating that is!)
#include "x2_inc_switches"
void main ()
{
    object oPC;
    oPC = GetItemActivator();
   AssignCommand(oPC, ClearAllActions());
if ((GetItemInSlot(INVENTORY_SLOT_NECK, oPC) != OBJECT_INVALID))
   {
    object oItem1;
    oItem1 = GetItemInSlot(INVENTORY_SLOT_NECK, oPC);
    string aTag;
    aTag = GetResRef(oItem1);
   if(aTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_NECK, oPC)));
   DelayCommand(2.0, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, aTag), INVENTORY_SLOT_NECK)));
   }
   }
 if ((GetItemInSlot(INVENTORY_SLOT_BELT, oPC) != OBJECT_INVALID))
   {
    object oItem2;
    oItem2 = GetItemInSlot(INVENTORY_SLOT_BELT, oPC);
    string bTag;
    bTag = GetResRef(oItem2);
   if(bTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_BELT, oPC)));
   DelayCommand(2.1, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, bTag), INVENTORY_SLOT_BELT)));
   }
   }

    if ((GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC) != OBJECT_INVALID))
   {
    object oItem3;
    oItem3 = GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC);
    string cTag;
    cTag = GetResRef(oItem3);
   if(cTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC)));
   DelayCommand(2.3, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, cTag), INVENTORY_SLOT_BOOTS)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_CHEST, oPC) != OBJECT_INVALID))
   {
    object oItem4;
    oItem4 = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
    string dTag;
    dTag = GetResRef(oItem4);
   if(dTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_CHEST, oPC)));
   DelayCommand(2.4, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, dTag), INVENTORY_SLOT_CHEST)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC) != OBJECT_INVALID))
   {
    object oItem5;
    oItem5 = GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC);
    string eTag;
    eTag = GetResRef(oItem5);
   if(eTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC)));
   DelayCommand(2.5, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, eTag), INVENTORY_SLOT_CLOAK)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_HEAD, oPC) != OBJECT_INVALID))
   {
    object oItem6;
    oItem6 = GetItemInSlot(INVENTORY_SLOT_HEAD, oPC);
    string fTag;
    fTag = GetResRef(oItem6);
   if(fTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_HEAD, oPC)));
   DelayCommand(2.6, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, fTag), INVENTORY_SLOT_HEAD)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC) != OBJECT_INVALID))
   {
    object oItem7;
    oItem7 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
    string gTag;
    gTag = GetResRef(oItem7);
   if(gTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC)));
   DelayCommand(2.7, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, gTag), INVENTORY_SLOT_LEFTHAND)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC) != OBJECT_INVALID))
   {
    object oItem8;
    oItem8 = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC);
    string hTag;
    hTag = GetResRef(oItem8);
   if(hTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC)));
   DelayCommand(2.8, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, hTag), INVENTORY_SLOT_LEFTRING)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) != OBJECT_INVALID))
   {
    object oItem9;
    oItem9 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
    string jTag;
    jTag = GetResRef(oItem9);
   if(jTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)));
   DelayCommand(3.0, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, jTag), INVENTORY_SLOT_RIGHTHAND)));
   }
   }
    if ((GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC) != OBJECT_INVALID))
   {
    object oItem11;
    oItem11 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC);
    string kTag;
    kTag = GetResRef(oItem11);
   if(kTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC)));
   DelayCommand(3.2, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, kTag), INVENTORY_SLOT_RIGHTRING)));
   }
   }
       if ((GetItemInSlot(INVENTORY_SLOT_ARMS, oPC) != OBJECT_INVALID))
   {
    object oItem12;
    oItem12 = GetItemInSlot(INVENTORY_SLOT_ARMS, oPC);
    string lTag;
    lTag = GetResRef(oItem12);
   if(lTag != "")
   {
   AssignCommand(oPC, ActionUnequipItem(GetItemInSlot(INVENTORY_SLOT_ARMS, oPC)));
   DelayCommand(3.4, AssignCommand(oPC, ActionEquipItem(GetItemPossessedBy(oPC, lTag), INVENTORY_SLOT_ARMS)));
   }
   }
//The End WOOSH!
}

#15
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
//:://////////////////////////////
//:: Created By: Iznoghoud
//:: Last modified: January 19 2004
/*
What this script changes:
- Melee Weapon properties now carry over to the unarmed forms' claws and bite
attacks.
1) Now, items with an AC bonus (or penalty) carry over to the shifted form as
the correct type. This means if you wear an amulet of natural armor +4, and a
cloak of protection +5, and you shift to a form that gets all item properties
carried over, you will have the +4 natural armor bonus from the ammy, as well as
the +5 deflection bonus from the cloak. No longer will the highest one override
all the other AC bonuses even if they are a different type.
2) Other "stackable" item properties, like ability bonuses, skill bonuses and
saving throw bonuses, now correctly add up in shifted form. This means if you
have a ring that gives +2 strength, and a ring with +3 strength, and you shift
into a drow warrior, you get +5 strength in shifted form, where you used to get
only +3. (the highest)

This file contains the code that handles stacking item properties for the improved
Shifter and Druid wildshape scripts.
1 February 2004:
Added an option to allow or disallow AC stacking of different types.
*/
//:://////////////////////////////
//******** Begin Options *********
//***************** GENERAL OPTIONS *********************
// Set this to TRUE to allow differing types of AC bonuses on items to stack.
// (ie armor, deflection, natural) Warning: This can give shifters who multiclass
// with monk a godly AC depending on your module.
// With FALSE, AC will transfer as it did with the default Bioware shifter script.
const int GW_ALLOW_AC_STACKING = TRUE;
//***************** FOR SHIFTER SHAPES ******************
// Set this to TRUE to merge properties of boots/rings/ammy/cloak/bracers regardless
// of what polymorph.2da indicates.
// FALSE uses the polymorph.2da to decide whether to copy
const int GW_ALWAYS_COPY_ITEM_PROPS = TRUE;//FALSE;
// Set this to TRUE to merge armor/helmet properties regardless of what polymorph.2da indicates.
// FALSE uses the polymorph.2da to decide whether to copy
const int GW_ALWAYS_COPY_ARMOR_PROPS = TRUE;
// - Set this to 1 to copy over weapon properties to claw/bite attacks.
// - Set this to 2 to copy over glove properties to claw/bite attacks.
// - Set this to 3 to copy over from either weapon or gloves depending on whether a
//   weapon was worn at the time of shifting.
// - Set this to any other value ( eg 0 ) to not copy over anything to claw/bite attacks.
const int GW_COPY_WEAPON_PROPS_TO_UNARMED = 3;

//***************** FOR DRUID SHAPES ********************
// These options do nothing if you have not imported the improved Druid wild-
// and elemental shape scripts
// Set this to TRUE to merge properties of boots/rings/ammy/cloak/bracers regardless
// of what polymorph.2da indicates.
// FALSE uses the polymorph.2da to decide whether to copy
const int WS_ALWAYS_COPY_ITEM_PROPS = TRUE;//FALSE;
// Set this to TRUE to merge armor/helmet properties regardless of what polymorph.2da indicates.
// FALSE uses the polymorph.2da to decide whether to copy
const int WS_ALWAYS_COPY_ARMOR_PROPS = TRUE;
// - Set this to 1 to copy over weapon properties to claw/bite attacks.
// - Set this to 2 to copy over glove properties to claw/bite attacks.
// - Set this to 3 to copy over from either weapon or gloves depending on whether a
//   weapon was worn at the time of shifting.
// - Set this to any other value ( eg 0 ) to not copy over anything to claw/bite attacks.
const int WS_COPY_WEAPON_PROPS_TO_UNARMED = 3;
//******** End Options ***********
// Includes for various shifter and item related functions
#include "x2_inc_itemprop"
#include "x2_inc_shifter"
// **** Begin Function prototypes ****
// Copies oOld's Properties to oNew, but only properties that do not stack
// with properties of the same type. If oOld is a weapon, then bWeapon must be TRUE.
void WildshapeCopyNonStackProperties(object oOld, object oNew, int bWeapon = FALSE);
// Returns TRUE if ip is an item property that will stack with other properties
// of the same type: Ability, AC, Saves, Skills.
int GetIsStackingProperty(itemproperty ip);
// Returns the AC bonus type of oItem: AC_*_BONUS
int GetItemACType(object oItem);
// Looks for Stackable Properties on oItem, and sets local variables to count the total bonus.
// Also links any found AC bonuses/penalties to ePoly.
effect ExamineStackableProperties (object oPC, effect ePoly, object oItem );
// if bItems is TRUE, Adds the stackable properties on all the objects given to ePoly.
// if bArmor is TRUE, Adds the stackable properties on armor and helmet to ePoly.
effect AddStackablePropertiesToPoly ( object oPC, effect ePoly, int bWeapon, int bItems, int bArmor, object oArmorOld, object oRing1Old,
                                      object oRing2Old, object oAmuletOld, object oCloakOld, object oBracerOld,
                                      object oBootsOld, object oBeltOld, object oHelmetOld, object oShield, object oWeapon, object oHideOld);
// Returns the spell that applied a Polymorph Effect currently on the player.
// -1 if it was no spell, -2 if no polymorph effect found.
int ScanForPolymorphEffect(object oPC);
// Converts a number from iprp_damagetype.2da to the corresponding
// DAMAGE_TYPE_* constants.
int ConvertNumToDamTypeConstant ( int iItemDamType );
// Converts a number from iprp_immuncost.2da to the corresponding percentage of immunity
int ConvertNumToImmunePercentage ( int iImmuneCost );
// Special function to copy over weapon properties, which deals with copying
// over ranged weapons correctly.
void WildshapeCopyWeaponProperties(object oPC, object oOld, object oNew);
// Returns TRUE if oItem is a creature claw or bite.
int GetIsCreatureWeapon( object oItem );
// **** End Function prototypes ****
// **** Begin Functions, added by Iznoghoud ****
// Copies oOld's Properties to oNew, but only properties that do not stack
// with properties of the same type. If oOld is a weapon, then bWeapon must be TRUE.
void WildshapeCopyNonStackProperties(object oOld, object oNew, int bWeapon = FALSE) {
    if (GetIsObjectValid(oOld) && GetIsObjectValid(oNew))
    {
        itemproperty ip = GetFirstItemProperty(oOld);
        while (GetIsItemPropertyValid(ip)) // Loop through all the item properties.
        {
            if (bWeapon) // If a weapon, then we must make sure not to transfer between ranged and non-ranged weapons!
            {
                if (GetWeaponRanged(oOld) == GetWeaponRanged(oNew) )
                {
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                }
            }
            else
            {
                // If not a stacking property, copy over the property.
                // Dont copy on hit cast spell property unless the target is a claw/bite.
                if ( !GetIsStackingProperty(ip) && ( !(GetItemPropertyType(ip) == ITEM_PROPERTY_ONHITCASTSPELL) || GetIsCreatureWeapon(oNew) ) )
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
            }
            ip = GetNextItemProperty(oOld); // Get next property
        }
    }
}
// Returns TRUE if ip is an item property that will stack with other properties
// of the same type: Ability, AC, Saves, Skills.
int GetIsStackingProperty(itemproperty ip) {
    int iType = GetItemPropertyType(ip);
    if ( iType == 0 || ( GW_ALLOW_AC_STACKING && (iType == 1) ) ||     // Bonus to Ability, AC
         iType == 27 || ( GW_ALLOW_AC_STACKING && (iType == 28) ) ||   // Penalty to Ability, AC
           iType == 40 || iType == 41 || // Bonus to saves (against element/universal, or fort/reflex/will)
           iType == 49 || iType == 50 || // Penalty to saves (against element/universal, or fort/reflex/will)
           iType == 52 || iType == 29 || // Skill Bonus, Penalty
           iType == 51 ||                // Regeneration
           iType == 20 || iType == 24    // Damage Immunity and Vulnerability
       )
        return TRUE;
    else
        return FALSE;
}
// Returns the AC bonus type of oItem: AC_*_BONUS
int GetItemACType(object oItem) {
    switch(GetBaseItemType(oItem)) {
    case BASE_ITEM_ARMOR: // These item types always get an armor ac bonus
    case BASE_ITEM_BRACER:
        return AC_ARMOUR_ENCHANTMENT_BONUS;
        break;
    case BASE_ITEM_BELT: // These item types always get a deflection ac bonus.
    case BASE_ITEM_CLOAK:
    case BASE_ITEM_GLOVES: // Note that gloves and bracers equip in the same inventory slot,
    case BASE_ITEM_HELMET: // but do not give the same AC bonus type!!!
    case BASE_ITEM_RING:
    case BASE_ITEM_TORCH:
        return AC_DEFLECTION_BONUS;
        break;
    case BASE_ITEM_BOOTS: // Only boots give a dodge ac bonus
        return AC_DODGE_BONUS;
        break;
    case BASE_ITEM_AMULET: // Only amulets give a natural AC bonus
        return AC_NATURAL_BONUS;
        break;
    case BASE_ITEM_LARGESHIELD: // Shields give a shield AC bonus
    case BASE_ITEM_SMALLSHIELD:
    case BASE_ITEM_TOWERSHIELD:
        return AC_SHIELD_ENCHANTMENT_BONUS;
        break;
    default: // It was a weapon, or a non default item, safest to default to deflection
        return AC_DEFLECTION_BONUS;
        break;
    };
    return AC_DEFLECTION_BONUS; // This one would seem unneccesary but it won't compile otherwise.
}
// Looks for Stackable Properties on oItem, and sets local variables to count the total bonus.
// Also links any found AC bonuses/penalties to ePoly.
effect ExamineStackableProperties ( object oPC, effect ePoly, object oItem )
{
    if ( !GetIsObjectValid(oItem) ) // If not valid, dont do any unneccesary work.
        return ePoly;
    itemproperty ip = GetFirstItemProperty(oItem);
    int iSubType;
    effect eTemp;
    while ( GetIsItemPropertyValid(ip) ) // Loop through all the item properties
    {
        if ( GetIsStackingProperty(ip) ) // See if it's a stacking property
        {
            iSubType = GetItemPropertySubType(ip); // Get the item property subtype for later use.
                                            // This contains whether a bonus is str, dex,
                                            // concentration skill, universal saving throws, etc.
            switch ( GetItemPropertyType(ip) ) // Which type of property is it?
            {
                // In the case of AC modifiers, add it directly to the Polymorphing effect.
                // For the other cases, set local variables on the player to
                // make a sum of all the bonuses/penalties. We use local
                // variables here because there are no arrays in NWScript, and
                // declaring a variable for every skill, ability type and saving
                // throw type in here is a little overboard.
                case 0: // Ability Bonus
                    SetLocalInt(oPC, "ws_ability_" + IntToString(iSubType), GetLocalInt(oPC, "ws_ability_" + IntToString(iSubType)) + GetItemPropertyCostTableValue(ip) );
                    break;
                case 1: // AC Bonus
                    ePoly = EffectLinkEffects(EffectACIncrease(GetItemPropertyCostTableValue(ip),GetItemACType(oItem)), ePoly);
                    break;
                case 27: // Ability Penalty
                    SetLocalInt(oPC, "ws_ability_" + IntToString(iSubType), GetLocalInt(oPC, "ws_ability_" + IntToString(iSubType)) - GetItemPropertyCostTableValue(ip) );
                    break;
                case 28: // AC penalty
                    ePoly = EffectLinkEffects(EffectACDecrease(GetItemPropertyCostTableValue(ip)), ePoly);
                    break;
                case 52: // Skill Bonus
                    SetLocalInt(oPC, "ws_skill_" + IntToString(iSubType), GetLocalInt(oPC, "ws_skill_" + IntToString(iSubType)) + GetItemPropertyCostTableValue(ip) );
                    break;
                case 29: // Skill Penalty
                    SetLocalInt(oPC, "ws_skill_" + IntToString(iSubType), GetLocalInt(oPC, "ws_skill_" + IntToString(iSubType)) - GetItemPropertyCostTableValue(ip) );
                    break;
                case 40: // Saving Throw Bonus vs Element(or universal)
                    SetLocalInt(oPC, "ws_save_elem_" + IntToString(iSubType), GetLocalInt(oPC, "ws_save_elem_" + IntToString(iSubType)) + GetItemPropertyCostTableValue(ip) );
                    break;
                case 41: // Saving Throw Bonus specific (fort/reflex/will)
                    SetLocalInt(oPC, "ws_save_spec_" + IntToString(iSubType), GetLocalInt(oPC, "ws_save_spec_" + IntToString(iSubType)) + GetItemPropertyCostTableValue(ip) );
                    break;
                case 49: // Saving Throw Penalty vs Element(or universal)
                    SetLocalInt(oPC, "ws_save_elem_" + IntToString(iSubType), GetLocalInt(oPC, "ws_save_elem_" + IntToString(iSubType)) - GetItemPropertyCostTableValue(ip) );
                    break;
                case 50: // Saving Throw Penalty specific (fort/reflex/will)
                    SetLocalInt(oPC, "ws_save_spec_" + IntToString(iSubType), GetLocalInt(oPC, "ws_save_spec_" + IntToString(iSubType)) - GetItemPropertyCostTableValue(ip) );
                    break;
                case 51: // Regeneration
                    SetLocalInt(oPC, "ws_regen", GetLocalInt(OBJECT_SELF, "ws_regen") + GetItemPropertyCostTableValue(ip) );
                    break;
                case 20: // Damage Immunity
                    SetLocalInt(oPC, "ws_dam_immun_" + IntToString(iSubType), GetLocalInt(oPC, "ws_dam_immun_" + IntToString(iSubType)) + ConvertNumToImmunePercentage(GetItemPropertyCostTableValue(ip)) );
                    break;
                case 24: // Damage Vulnerability
                    SetLocalInt(oPC, "ws_dam_immun_" + IntToString(iSubType), GetLocalInt(oPC, "ws_dam_immun_" + IntToString(iSubType)) - ConvertNumToImmunePercentage(GetItemPropertyCostTableValue(ip)) );
                    break;
            };
        }
        ip = GetNextItemProperty(oItem);
    }
    return ePoly;
}
// if bItems is TRUE, Adds all the stackable properties on all the objects given to ePoly.
// if bItems is FALSE, Adds only the stackable properties on armor and helmet to ePoly.
effect AddStackablePropertiesToPoly ( object oPC, effect ePoly, int bWeapon, int bItems, int bArmor, object oArmorOld, object oRing1Old,
                                      object oRing2Old, object oAmuletOld, object oCloakOld, object oBracerOld,
                                      object oBootsOld, object oBeltOld, object oHelmetOld, object oShield, object oWeapon, object oHideOld)
{
    if (bArmor ) // Armor properties get carried over
    {
        ePoly = ExamineStackableProperties ( oPC, ePoly, oArmorOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oHelmetOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oShield );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oHideOld );
    }
    if ( bItems ) // Item properties get carried over
    {
        ePoly = ExamineStackableProperties ( oPC, ePoly, oRing1Old );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oRing2Old );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oAmuletOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oCloakOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oBootsOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oBeltOld );
        ePoly = ExamineStackableProperties ( oPC, ePoly, oBracerOld );
    }
    // AC bonuses are attached to ePoly inside ExamineStackableProperties
    int i; // This will loop over all the different ability subtypes (eg str, dex, con, etc)
    int j; // This will contain the sum of the stackable bonus type we're looking at
    for ( i = 0; i <= 5; i++ ) // **** Handle Ability Bonuses ****
    {
        j = GetLocalInt(oPC, "ws_ability_" + IntToString(i));
        // Add the sum of this ability bonus to the polymorph effect.
        if ( j > 0 ) // Sum was Positive
            ePoly = EffectLinkEffects(EffectAbilityIncrease(i, j), ePoly);
        else if ( j < 0 ) // Sum was Negative
            ePoly = EffectLinkEffects(EffectAbilityDecrease(i, -j), ePoly);
        DeleteLocalInt(oPC, "ws_ability_" + IntToString(i));
    }
    for ( i = 0; i <= 26; i++ ) // **** Handle Skill Bonuses ****
    {
        j = GetLocalInt(oPC, "ws_skill_" + IntToString(i));
        // Add the sum of this skill bonus to the polymorph effect.
        if ( j > 0 ) // Sum was Positive
            ePoly = EffectLinkEffects(EffectSkillIncrease(i, j), ePoly);
        else if ( j < 0 ) // Sum was Negative
            ePoly = EffectLinkEffects(EffectSkillDecrease(i, -j), ePoly);
        DeleteLocalInt(oPC, "ws_skill_" + IntToString(i));
    }
    for ( i = 0; i <= 21; i++ ) // **** Handle Saving Throw vs element Bonuses ****
    {
        j = GetLocalInt(oPC, "ws_save_elem_" + IntToString(i));
        // Add the sum of this saving throw bonus to the polymorph effect.
        if ( j > 0 ) // Sum was Positive
            ePoly = EffectLinkEffects(EffectSavingThrowIncrease(SAVING_THROW_ALL, j, i), ePoly);
        else if ( j < 0 ) // Sum was Negative
            ePoly = EffectLinkEffects(EffectSavingThrowDecrease(SAVING_THROW_ALL, -j, i), ePoly);
        DeleteLocalInt(oPC, "ws_save_elem_" + IntToString(i));
    }
    for ( i = 0; i <= 3; i++ ) // **** Handle Saving Throw specific Bonuses ****
    {
        j = GetLocalInt(oPC, "ws_save_spec_" + IntToString(i));
        // Add the sum of this saving throw bonus to the polymorph effect.
        if ( j > 0 ) // Sum was Positive
            ePoly = EffectLinkEffects(EffectSavingThrowIncrease(i, j), ePoly);
        else if ( j < 0 ) // Sum was Negative
            ePoly = EffectLinkEffects(EffectSavingThrowDecrease(i, -j), ePoly);
        DeleteLocalInt(oPC, "ws_save_spec_" + IntToString(i));
    }
    j = GetLocalInt(oPC, "ws_regen");
    if ( j > 0 )
    {
        ePoly = EffectLinkEffects(EffectRegenerate(j, 6.0), ePoly);
        DeleteLocalInt(oPC, "ws_regen" );
    }
    for ( i = 0; i <= 13; i++ ) // **** Handle Damage Immunity and Vulnerability ****
    {
        j = GetLocalInt(oPC, "ws_dam_immun_" + IntToString(i));
        // Add the sum of this Damage Immunity/Vulnerability to the polymorph effect.
        if ( j > 0 ) // Sum was Positive
            ePoly = EffectLinkEffects(EffectDamageImmunityIncrease(ConvertNumToDamTypeConstant ( i ), j), ePoly);
        else if ( j < 0 ) // Sum was Negative
            ePoly = EffectLinkEffects(EffectDamageImmunityDecrease(ConvertNumToDamTypeConstant ( i ), -j), ePoly);
        DeleteLocalInt(oPC, "ws_dam_immun_" + IntToString(i));
    }
    return ePoly; // Finally, we have the entire (possibly huge :P  ) effect to be applied to the shifter.
}
// Returns the spell that applied a Polymorph Effect currently on the player.
// -1 if it was no spell, -2 if no polymorph effect found.
int ScanForPolymorphEffect(object oPC)
{
    effect eEffect = GetFirstEffect(oPC);
    while ( GetIsEffectValid(eEffect) )
    {
        if ( GetEffectType( eEffect ) == EFFECT_TYPE_POLYMORPH )
        {
            return GetEffectSpellId(eEffect);
        }
        eEffect = GetNextEffect(oPC);
    }
    return -2;
}
// Converts a number from iprp_damagetype.2da to the corresponding
// DAMAGE_TYPE_* constants.
int ConvertNumToDamTypeConstant ( int iItemDamType )
{
    switch ( iItemDamType )
    {
        case 0:
            return DAMAGE_TYPE_BLUDGEONING;
            break;
        case 1:
            return DAMAGE_TYPE_PIERCING;
            break;
        case 2:
            return DAMAGE_TYPE_SLASHING;
            break;
        case 5:
            return DAMAGE_TYPE_MAGICAL;
            break;
        case 6:
            return DAMAGE_TYPE_ACID;
            break;
        case 7:
            return DAMAGE_TYPE_COLD;
            break;
        case 8:
            return DAMAGE_TYPE_DIVINE;
            break;
        case 9:
            return DAMAGE_TYPE_ELECTRICAL;
            break;
        case 10:
            return DAMAGE_TYPE_FIRE;
            break;
        case 11:
            return DAMAGE_TYPE_NEGATIVE;
            break;
        case 12:
            return DAMAGE_TYPE_POSITIVE;
            break;
        case 13:
            return DAMAGE_TYPE_SONIC;
            break;
        default:
            return DAMAGE_TYPE_POSITIVE;
            break;
    };
    // This one might seem unneccesary but it wont compile otherwise
    return DAMAGE_TYPE_POSITIVE;
}
// Converts a number from iprp_immuncost.2da to the corresponding percentage of immunity
int ConvertNumToImmunePercentage ( int iImmuneCost )
{
    switch ( iImmuneCost )
    {
        case 1:
            return 5;
            break;
        case 2:
            return 10;
            break;
        case 3:
            return 25;
            break;
        case 4:
            return 50;
            break;
        case 5:
            return 75;
            break;
        case 6:
            return 90;
            break;
        case 7:
            return 100;
            break;
        default:
            return 0;
            break;
    };
    return 0;
}
void WildshapeCopyWeaponProperties(object oPC, object oOld, object oNew)
{
    if (GetIsObjectValid(oOld) && GetIsObjectValid(oNew))
    {
        itemproperty ip = GetFirstItemProperty(oOld);
        // If both are Melee Weapons
        if ( !GetWeaponRanged(oOld) && !GetWeaponRanged(oNew) )
        {
            while (GetIsItemPropertyValid(ip))
            {
                AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                ip = GetNextItemProperty(oOld);
            }// while
        }
        // If both are Ranged Weapons
        else if ( GetWeaponRanged(oOld) && GetWeaponRanged(oNew) )
        {
            int bUnlimitedAmmoFound = FALSE;
            itemproperty ipNew;
            int iOldMightyValue = 0;
            object oAmmo;
            while (GetIsItemPropertyValid(ip))
            {
                if ( GetItemPropertyType(ip) == 61 ) // 61 = Unlimited Ammo
                {
                    // For some reason, when removing/replacing an unlimited
                    // ammo property, the corresponding missile type will get
                    // dropped in the player's inventory, so we have to remove
                    // that missile again to prevent abuse.
                    bUnlimitedAmmoFound = TRUE;
                    oAmmo = GetItemInSlot(INVENTORY_SLOT_ARROWS, oPC);
                    if ( !GetIsObjectValid( oAmmo ) )
                        oAmmo = GetItemInSlot(INVENTORY_SLOT_BOLTS, oPC);
                    if ( !GetIsObjectValid( oAmmo ) )
                        oAmmo = GetItemInSlot(INVENTORY_SLOT_BULLETS, oPC);
                    IPRemoveMatchingItemProperties(oNew, ITEM_PROPERTY_UNLIMITED_AMMUNITION, DURATION_TYPE_PERMANENT );
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                    DestroyObject(oAmmo);
                }
                else if ( GetItemPropertyType(ip) == 45 ) // 45 = Mighty
                {
                    ipNew = GetFirstItemProperty(oNew);
                    // Find the mighty value of the Polymorph's weapon
                    while ( GetIsItemPropertyValid(ipNew) )
                    {
                        if ( GetItemPropertyType( ipNew ) == 45 )
                        {
                            iOldMightyValue = GetItemPropertyCostTableValue( ipNew );
                            break;
                        }
                        ipNew = GetNextItemProperty(oNew);
                    } // while
                    // If new mighty value bigger, remove old one and add new one.
                    if ( GetItemPropertyCostTableValue(ip) > iOldMightyValue )
                    {
                        RemoveItemProperty(oNew, ipNew);
                        AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                    }
                }
                else
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                ip = GetNextItemProperty(oOld);
            } // while
            // Add basic unlimited ammo if neccesary
            if ( bUnlimitedAmmoFound == FALSE && !GetItemHasItemProperty(oNew, ITEM_PROPERTY_UNLIMITED_AMMUNITION ) )
                AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyUnlimitedAmmo(), oNew);
        }
    }
    else if ( GetWeaponRanged(oNew) )
    {
        // Add basic unlimited ammo if neccesary
        if ( !GetItemHasItemProperty(oNew, ITEM_PROPERTY_UNLIMITED_AMMUNITION ) )
            AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyUnlimitedAmmo(), oNew);
    }
}
// Returns TRUE if oItem is a creature claw or bite.
int GetIsCreatureWeapon( object oItem )
{
    int iBaseItemType = GetBaseItemType(oItem);
    switch ( iBaseItemType )
    {
        case BASE_ITEM_CBLUDGWEAPON:
        case BASE_ITEM_CPIERCWEAPON:
        case BASE_ITEM_CSLASHWEAPON:
        case BASE_ITEM_CSLSHPRCWEAP:
            return TRUE;
        default:
            return FALSE;
    };
    return FALSE;
}
// **** End Functions, added by Iznoghoud ****

#16
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
.

Modifié par Lazarus Magni, 28 octobre 2013 - 04:24 .


#17
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
//::///////////////////////////////////////////////
//:: Item Property Functions
//:: x2_inc_itemprop
//:: Copyright © 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
    Holds item property and item modification
    specific code.
    If you look for anything specific to item
    properties, your chances are good to find it
    in here.
*/
//:://////////////////////////////////////////////
//:: Created By: Georg Zoeller
//:: Created On: 2003-06-05
//:: Last Update: 2003-10-07
//:://////////////////////////////////////////////
// *  The tag of the ip work container, a placeable which has to be set into each
// *  module that is using any of the crafting functions.
const string  X2_IP_WORK_CONTAINER_TAG = "x2_plc_ipbox";
// *  2da for the AddProperty ItemProperty
const string X2_IP_ADDRPOP_2DA = "des_crft_props" ;
// *  2da for the Poison Weapon Itemproperty
const string X2_IP_POISONWEAPON_2DA = "des_crft_poison" ;
// *  2da for armor appearance
const string X2_IP_ARMORPARTS_2DA = "des_crft_aparts" ;
// *  2da for armor appearance
const string X2_IP_ARMORAPPEARANCE_2DA = "des_crft_appear" ;
// * Base custom token for item modification conversations (do not change unless you want to change the conversation too)
const int    XP_IP_ITEMMODCONVERSATION_CTOKENBASE = 12220;
const int    X2_IP_ITEMMODCONVERSATION_MODE_TAILOR = 0;
const int    X2_IP_ITEMMODCONVERSATION_MODE_CRAFT = 1;
// * Number of maximum item properties allowed on most items
const int    X2_IP_MAX_ITEM_PROPERTIES = 8;
// *  Constants used with the armor modification system
const int    X2_IP_ARMORTYPE_NEXT = 0;
const int    X2_IP_ARMORTYPE_PREV = 1;
const int    X2_IP_ARMORTYPE_RANDOM = 2;
const int    X2_IP_WEAPONTYPE_NEXT = 0;
const int    X2_IP_WEAPONTYPE_PREV = 1;
const int    X2_IP_WEAPONTYPE_RANDOM = 2;
// *  Policy constants for IPSafeAddItemProperty()
const int    X2_IP_ADDPROP_POLICY_REPLACE_EXISTING = 0;
const int    X2_IP_ADDPROP_POLICY_KEEP_EXISTING = 1;
const int    X2_IP_ADDPROP_POLICY_IGNORE_EXISTING =2;

// *  removes all itemproperties with matching nItemPropertyType and nItemPropertyDuration
void  IPRemoveMatchingItemProperties( object oItem, int nItemPropertyType, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY, int nItemPropertySubType = -1 );
// *  Removes ALL item properties from oItem matching nItemPropertyDuration
void  IPRemoveAllItemProperties( object oItem, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY );
// *  returns TRUE if item can be equipped.
// *  Uses Get2DAString, so do not use in a loop!
int   IPGetIsItemEquipable( object oItem );
// *  Changes the color of an item armor
// *  oItem        - The armor
// *  nColorType   - ITEM_APPR_ARMOR_COLOR_* constant
// *  nColor       - color from 0 to 63
// *  Since oItem is destroyed in the process, the function returns
// *  the item created with the color changed
object IPDyeArmor( object oItem, int nColorType, int nColor );
// *  Returns the container used for item property and appearance modifications in the
// *  module. If it does not exist, create it.
object IPGetIPWorkContainer( object oCaller = OBJECT_SELF );
// *  This function needs to be rather extensive and needs to be updated if there are new
// *  ip types we want to use, but it goes into the item property include anyway
itemproperty IPGetItemPropertyByID( int nPropID, int nParam1 = 0, int nParam2 = 0, int nParam3 = 0, int nParam4 = 0 );
// *  returns TRUE if oItem is a ranged weapon
int   IPGetIsRangedWeapon( object oItem );
// *  return TRUE if oItem is a melee weapon
int   IPGetIsMeleeWeapon( object oItem );
// *  return TRUE if oItem is a projectile (bolt, arrow, etc)
int   IPGetIsProjectile( object oItem );
// *  returns true if weapon is blugeoning (used for poison)
// *  This uses Get2DAstring, so it is slow. Avoid using in loops!
int   IPGetIsBludgeoningWeapon( object oItem );
// *  Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given in nSPELL_ID
// *  This uses Get2DAstring, so it is slow. Avoid using in loops!
// *  returns -1 if there is no matching property for a spell
int   IPGetIPConstCastSpellFromSpellID( int nSpellID );
// *  Returns TRUE if an item has ITEM_PROPERTY_ON_HIT and the specified nSubType
// *  possible values for nSubType can be taken from IPRP_ONHIT.2da
// *  popular ones:
// *  5 - Daze   19 - ItemPoison   24 - Vorpal
int   IPGetItemHasItemOnHitPropertySubType( object oTarget, int nSubType );
// *  Returns the number of possible armor part variations for the specified part
// *  nPart - ITEM_APPR_ARMOR_MODEL_* constant
// *  Uses Get2DAstring, so do not use in loops
int   IPGetNumberOfAppearances( int nPart );

// *  Returns the next valid appearance type for oArmor
// *  nPart - ITEM_APPR_ARMOR_MODEL_* constant
// *  Uses Get2DAstring, so do not use in loops
int   IPGetNextArmorAppearanceType(object oArmor, int nPart);
// *  Returns the previous valid appearance type for oArmor
// *  nPart - ITEM_APPR_ARMOR_MODEL_* constant
// *  Uses Get2DAstring, so do not use in loops
int   IPGetPrevArmorAppearanceType(object oArmor, int nPart);
// *  Returns a random valid appearance type for oArmor
// *  nPart - ITEM_APPR_ARMOR_MODEL_* constant
// *  Uses Get2DAstring, so do not use in loops
int   IPGetRandomArmorAppearanceType(object oArmor, int nPart);
// * Returns a new armor based of oArmor with nPartModified
// * nPart - ITEM_APPR_ARMOR_MODEL_* constant of the part to be changed
// * nMode -
// *        X2_IP_ARMORTYPE_NEXT    - next valid appearance
// *        X2_IP_ARMORTYPE_PREV    - previous valid apperance;
// *        X2_IP_ARMORTYPE_RANDOM  - random valid appearance;
// *
// * bDestroyOldOnSuccess - Destroy oArmor in process?
// * Uses Get2DAstring, so do not use in loops
object IPGetModifiedArmor(object oArmor, int nPart, int nMode, int bDestroyOldOnSuccess);
// *  Add an item property in a safe fashion, preventing unwanted stacking
// *  Parameters:
// *   oItem     - the item to add the property to
// *   ip        - the itemproperty to add
// *   fDuration - set 0.0f to add the property permanent, anything else is temporary
// *   nAddItemPropertyPolicy - How to handle existing properties. Valid values are:
// *      X2_IP_ADDPROP_POLICY_REPLACE_EXISTING - remove any property of the same type, subtype, durationtype before adding;
// *      X2_IP_ADDPROP_POLICY_KEEP_EXISTING - do not add if any property with same type, subtype and durationtype already exists;
// *      X2_IP_ADDPROP_POLICY_IGNORE_EXISTING - add itemproperty in any case - Do not Use with OnHit or OnHitSpellCast props!
// *
// *  bIgnoreDurationType - If set to TRUE, an item property will be considered identical even if the DurationType is different. Be careful when using this
// *                        with X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, as this could lead to a temporary item property removing a permanent one
// *  bIgnoreSubType      - If set to TRUE an item property will be considered identical even if the SubType is different.
void  IPSafeAddItemProperty(object oItem, itemproperty ip, float fDuration =0.0f, int nAddItemPropertyPolicy = X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, int bIgnoreDurationType = FALSE, int bIgnoreSubType = FALSE);
// *  Wrapper for GetItemHasItemProperty that returns true if
// *  oItem has an itemproperty that matches ipCompareTo by Type AND DurationType AND SubType
// *  nDurationType = Valid DURATION_TYPE_* or -1 to ignore
// *  bIgnoreSubType - If set to TRUE an item property will be considered identical even if the SubType is different.
int   IPGetItemHasProperty(object oItem, itemproperty ipCompareTo, int nDurationType, int bIgnoreSubType = FALSE);
// *  returns FALSE it the item has no sequencer property
// *  returns number of spells that can be stored in any other case
int   IPGetItemSequencerProperty(object oItem);
// *  returns TRUE if the item has the OnHit:IntelligentWeapon property.
int   IPGetIsIntelligentWeapon(object oItem);
// *  Mapping between numbers and power constants for ITEM_PROPERTY_DAMAGE_BONUS
// *  returns the appropriate ITEM_PROPERTY_DAMAGE_POWER_* constant for nNumber
int   IPGetDamagePowerConstantFromNumber(int nNumber);
// *  returns the appropriate ITEM_PROPERTY_DAMAGE_BONUS_= constant for nNumber
// *  Do not pass in any number <1 ! Will return -1 on error
int   IPGetDamageBonusConstantFromNumber(int nNumber);
// *  Special Version of Copy Item Properties for use with greater wild shape
// *  oOld - Item equipped before polymorphing (source for item props)
// *  oNew - Item equipped after polymorphing  (target for item props)
// *  bWeapon - Must be set TRUE when oOld is a weapon.
void  IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE);
// *  Returns the current enhancement bonus of a weapon (+1 to +20), 0 if there is
// *  no enhancement bonus. You can test for a specific type of enhancement bonus
// *  by passing the appropritate ITEM_PROPERTY_ENHANCEMENT_BONUS* constant into
// *  nEnhancementBonusType
int   IPGetWeaponEnhancementBonus(object oWeapon, int nEnhancementBonusType = ITEM_PROPERTY_ENHANCEMENT_BONUS);
// *  Shortcut function to set the enhancement bonus of a weapon to a certain bonus
// *  Specifying bOnlyIfHigher as TRUE will prevent a bonus lower than the requested
// *  bonus from being applied. Valid values for nBonus are 1 to 20.
void  IPSetWeaponEnhancementBonus(object oWeapon, int nBonus, int bOnlyIfHigher = TRUE);
// *  Shortcut function to upgrade the enhancement bonus of a weapon by the
// *  number specified in nUpgradeBy. If the resulting new enhancement bonus
// *  would be out of bounds (>+20), it will be set to +20
void  IPUpgradeWeaponEnhancementBonus(object oWeapon, int nUpgradeBy);
// *  Returns TRUE if a character has any item equipped that has the itemproperty
// *  defined in nItemPropertyConst in it (ITEM_PROPERTY_* constant)
int   IPGetHasItemPropertyOnCharacter(object oPC, int nItemPropertyConst);
// *  Returns an integer with the number of properties present oItem
int   IPGetNumberOfItemProperties(object oItem);
 
//------------------------------------------------------------------------------
//                         I M P L E M E N T A T I O N
//------------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Removes all itemproperties with matching nItemPropertyType and
// nItemPropertyDuration (a DURATION_TYPE_* constant)
// ----------------------------------------------------------------------------
void IPRemoveMatchingItemProperties(object oItem, int nItemPropertyType, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY, int nItemPropertySubType = -1)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    // valid ip?
    while (GetIsItemPropertyValid(ip))
    {
        // same property type?
        if ((GetItemPropertyType(ip) == nItemPropertyType))
        {
            // same duration or duration ignored?
            if (GetItemPropertyDurationType(ip) == nItemPropertyDuration || nItemPropertyDuration == -1)
            {
                 // same subtype or subtype ignored
                 if  (GetItemPropertySubType(ip) == nItemPropertySubType || nItemPropertySubType == -1)
                 {
                      // Put a warning into the logfile if someone tries to remove a permanent ip with a temporary one!
                      /*if (nItemPropertyDuration == DURATION_TYPE_TEMPORARY &&  GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT)
                      {
                         WriteTimestampedLogEntry("x2_inc_itemprop:: IPRemoveMatchingItemProperties() - WARNING: Permanent item property removed by temporary on "+GetTag(oItem));
                      }
                      */
                      RemoveItemProperty(oItem, ip);
                 }
            }
        }
        ip = GetNextItemProperty(oItem);
    }
}
// ----------------------------------------------------------------------------
// Removes ALL item properties from oItem matching nItemPropertyDuration
// ----------------------------------------------------------------------------
void IPRemoveAllItemProperties(object oItem, int nItemPropertyDuration = DURATION_TYPE_TEMPORARY)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyDurationType(ip) == nItemPropertyDuration)
        {
            RemoveItemProperty(oItem, ip);
        }
        ip = GetNextItemProperty(oItem);
    }
}
// ----------------------------------------------------------------------------
// returns TRUE if item can be equipped. Uses Get2DAString, so do not use in a loop!
// ----------------------------------------------------------------------------
int IPGetIsItemEquipable(object oItem)
{
    int nBaseType =GetBaseItemType(oItem);
    // fix, if we get BASE_ITEM_INVALID (usually because oItem is invalid), we
    // need to make sure that this function returns FALSE
    if(nBaseType==BASE_ITEM_INVALID) return FALSE;
    string sResult = Get2DAString("baseitems","EquipableSlots",nBaseType);
    return  (sResult != "0x00000");
}
// ----------------------------------------------------------------------------
// Changes the color of an item armor
// oItem        - The armor
// nColorType   - ITEM_APPR_ARMOR_COLOR_* constant
// nColor       - color from 0 to 63
// Since oItem is destroyed in the process, the function returns
// the item created with the color changed
// ----------------------------------------------------------------------------
object IPDyeArmor(object oItem, int nColorType, int nColor)
{
        object oRet = CopyItemAndModify(oItem,ITEM_APPR_TYPE_ARMOR_COLOR,nColorType,nColor,TRUE);
        DestroyObject(oItem); // remove old item
        return oRet; //return new item
}
// ----------------------------------------------------------------------------
// Returns the container used for item property and appearance modifications in the
// module. If it does not exist, it is created
// ----------------------------------------------------------------------------
object IPGetIPWorkContainer(object oCaller = OBJECT_SELF)
{
    object oRet = GetObjectByTag(X2_IP_WORK_CONTAINER_TAG);
    if (oRet == OBJECT_INVALID)
    {
        oRet = CreateObject(OBJECT_TYPE_PLACEABLE,X2_IP_WORK_CONTAINER_TAG,GetLocation(oCaller));
        effect eInvis =  EffectVisualEffect( VFX_DUR_CUTSCENE_INVISIBILITY);
        eInvis = ExtraordinaryEffect(eInvis);
        ApplyEffectToObject(DURATION_TYPE_PERMANENT,eInvis,oRet);
        if (oRet == OBJECT_INVALID)
        {
            WriteTimestampedLogEntry("x2_inc_itemprop - critical: Missing container with tag " +X2_IP_WORK_CONTAINER_TAG + "!!");
        }
    }

    return oRet;
}
// ----------------------------------------------------------------------------
// This function needs to be rather extensive and needs to be updated if there are new
// ip types we want to use, but it goes into the item property include anyway
// ----------------------------------------------------------------------------
itemproperty IPGetItemPropertyByID(int nPropID, int nParam1 = 0, int nParam2 = 0, int nParam3 = 0, int nParam4 = 0)
{
   itemproperty ipRet;
   if (nPropID == ITEM_PROPERTY_ABILITY_BONUS)
   {
        ipRet = ItemPropertyAbilityBonus(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_AC_BONUS)
   {
        ipRet = ItemPropertyACBonus(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP)
   {
        ipRet = ItemPropertyACBonusVsAlign(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE)
   {
        ipRet = ItemPropertyACBonusVsDmgType(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP)
   {
        ipRet = ItemPropertyACBonusVsRace(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT)
   {
        ipRet = ItemPropertyACBonusVsSAlign(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS)
   {
        ipRet = ItemPropertyAttackBonus(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP)
   {
        ipRet = ItemPropertyAttackBonusVsAlign(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP)
   {
        ipRet = ItemPropertyAttackBonusVsRace(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT)
   {
        ipRet = ItemPropertyAttackBonusVsSAlign(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION)
   {
        ipRet = ItemPropertyWeightReduction(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_BONUS_FEAT)
   {
        ipRet = ItemPropertyBonusFeat(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)
   {
        ipRet = ItemPropertyBonusLevelSpell(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_CAST_SPELL)
   {
        ipRet = ItemPropertyCastSpell(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS)
   {
        ipRet = ItemPropertyDamageBonus(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP)
   {
        ipRet = ItemPropertyDamageBonusVsAlign(nParam1, nParam2, nParam3);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP)
   {
        ipRet = ItemPropertyDamageBonusVsRace(nParam1, nParam2, nParam3);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT)
   {
        ipRet = ItemPropertyDamageBonusVsSAlign(nParam1, nParam2, nParam3);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_REDUCTION)
   {
        ipRet = ItemPropertyDamageReduction(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_RESISTANCE)
   {
        ipRet = ItemPropertyDamageResistance(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DAMAGE_VULNERABILITY)
   {
        ipRet = ItemPropertyDamageResistance(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DARKVISION)
   {
        ipRet = ItemPropertyDarkvision();
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_ABILITY_SCORE)
   {
        ipRet = ItemPropertyDecreaseAbility(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_AC)
   {
        ipRet = ItemPropertyDecreaseAC(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER)
   {
        ipRet = ItemPropertyAttackPenalty(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER)
   {
        ipRet = ItemPropertyEnhancementPenalty(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_SAVING_THROWS)
   {
        ipRet = ItemPropertyReducedSavingThrow(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC)
   {
        ipRet = ItemPropertyBonusSavingThrowVsX(nParam1, nParam2);
   }
    else if (nPropID == ITEM_PROPERTY_DECREASED_SKILL_MODIFIER)
   {
        ipRet = ItemPropertyDecreaseSkill(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ENHANCED_CONTAINER_REDUCED_WEIGHT)
   {
        ipRet = ItemPropertyContainerReducedWeight(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS)
   {
        ipRet = ItemPropertyEnhancementBonus(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP)
   {
        ipRet = ItemPropertyEnhancementBonusVsAlign(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT)
   {
        ipRet = ItemPropertyEnhancementBonusVsSAlign(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP)
   {
        ipRet = ItemPropertyEnhancementBonusVsRace(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE)
   {
        ipRet = ItemPropertyExtraMeleeDamageType(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE)
   {
        ipRet = ItemPropertyExtraRangeDamageType(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_HASTE)
   {
        ipRet = ItemPropertyHaste();
   }
   else if (nPropID == ITEM_PROPERTY_KEEN)
   {
        ipRet = ItemPropertyKeen();
   }
   else if (nPropID == ITEM_PROPERTY_LIGHT)
   {
        ipRet = ItemPropertyLight(nParam1,nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_MASSIVE_CRITICALS)
   {
        ipRet = ItemPropertyMassiveCritical(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_NO_DAMAGE)
   {
        ipRet = ItemPropertyNoDamage();
   }
   else if (nPropID == ITEM_PROPERTY_ON_HIT_PROPERTIES)
   {
        ipRet = ItemPropertyOnHitProps(nParam1, nParam2, nParam3);
   }
   else if (nPropID == ITEM_PROPERTY_TRAP)
   {
        ipRet = ItemPropertyTrap(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_TRUE_SEEING)
   {
        ipRet = ItemPropertyTrueSeeing();
   }
   else if (nPropID == ITEM_PROPERTY_UNLIMITED_AMMUNITION)
   {
        ipRet = ItemPropertyUnlimitedAmmo(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_ONHITCASTSPELL)
   {
        ipRet = ItemPropertyOnHitCastSpell(nParam1, nParam2);
   }
   else if (nPropID == ITEM_PROPERTY_ARCANE_SPELL_FAILURE)
   {
        ipRet = ItemPropertyArcaneSpellFailure(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_ADDITIONAL)//new itemproperty from patch 1.69
   {
        ipRet = ItemPropertyAdditional(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_MATERIAL)  //new itemproperty from patch 1.69
   {
        ipRet = ItemPropertyMaterial(nParam1);
   }
   else if (nPropID == ITEM_PROPERTY_QUALITY)   //new itemproperty from patch 1.69
   {
        ipRet = ItemPropertyQuality(nParam1);
   }
   return ipRet;
}
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a projectile
// ----------------------------------------------------------------------------
int IPGetIsProjectile(object oItem)
{
    switch(GetBaseItemType(oItem))
    {
        case BASE_ITEM_ARROW:
        case BASE_ITEM_BOLT:
        case BASE_ITEM_BULLET:
        return TRUE;
    }
    return FALSE;
}
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a ranged weapon
// ----------------------------------------------------------------------------
int IPGetIsRangedWeapon(object oItem)
{
    return GetWeaponRanged(oItem); // doh !
}
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a melee weapon
// 1.70 by Shadooow: made the function custom content weapons compatible
// ----------------------------------------------------------------------------
int IPGetIsMeleeWeapon(object oItem)
{
int nBaseItem = GetBaseItemType(oItem);
 if(nBaseItem == BASE_ITEM_INVALID || GetWeaponRanged(oItem))
 return FALSE;
return StringToInt(Get2DAString("baseitems","WeaponType",nBaseItem)) > 0;
}
// ----------------------------------------------------------------------------
// Returns TRUE if weapon is a blugeoning weapon. Uses Get2DAString!
// 1.70 by Shadooow: bludgeoning+piercing weapons like morningstars are now considered to be bludgeoning as well.
// ----------------------------------------------------------------------------
int IPGetIsBludgeoningWeapon(object oItem)
{
int nBaseItem = GetBaseItemType(oItem);
 if(nBaseItem == BASE_ITEM_INVALID)// fix, if we get BASE_ITEM_INVALID (usually because oItem is invalid), we
 return FALSE;                     // need to make sure that this function returns FALSE
 switch(StringToInt(Get2DAString("baseitems","WeaponType",nBaseItem)))
 {
 case 2://bludgeoning
 case 5://bludgeoning+piercing
 return TRUE;
 }
return FALSE;
}
// ----------------------------------------------------------------------------
// Return the IP_CONST_CASTSPELL_* ID matching to the SPELL_* constant given
// in nSPELL_ID.
// This uses Get2DAstring, so it is slow. Avoid using in loops!
// returns -1 if there is no matching property for a spell
// ----------------------------------------------------------------------------
int IPGetIPConstCastSpellFromSpellID(int nSpellID)
{
    // look up Spell Property Index
    string sTemp = Get2DAString("des_crft_spells","IPRP_SpellIndex",nSpellID);
    /*
    if (sTemp == "") // invalid nSpellID
    {
        PrintString("x2_inc_craft.nss::GetIPConstCastSpellFromSpellID called with invalid nSpellID" + IntToString(nSpellID));
        return -1;
    }
    */
    int nSpellPrpIdx = StringToInt(sTemp);
    return nSpellPrpIdx;
}
// ----------------------------------------------------------------------------
// Returns TRUE if an item has ITEM_PROPERTY_ON_HIT and the specified nSubType
// possible values for nSubType can be taken from IPRP_ONHIT.2da
// popular ones:
//       5 - Daze
//      19 - ItemPoison
//      24 - Vorpal
// ----------------------------------------------------------------------------
int IPGetItemHasItemOnHitPropertySubType(object oTarget, int nSubType)
{
    if (GetItemHasItemProperty(oTarget,ITEM_PROPERTY_ON_HIT_PROPERTIES))
    {
        itemproperty ipTest = GetFirstItemProperty(oTarget);
        // loop over item properties to see if there is already a poison effect
        while (GetIsItemPropertyValid(ipTest))
        {
            if (GetItemPropertySubType(ipTest) == nSubType)   //19 == onhit poison
            {
                return TRUE;
            }
          ipTest = GetNextItemProperty(oTarget);
         }
    }
    return FALSE;
}
// ----------------------------------------------------------------------------
// Returns the number of possible armor part variations for the specified part
// nPart - ITEM_APPR_ARMOR_MODEL_* constant
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
int IPGetNumberOfArmorAppearances(int nPart)
{
    int nRet;
    //SpeakString(Get2DAString(X2_IP_ARMORPARTS_2DA ,"NumParts",nPart));
    nRet = StringToInt(Get2DAString(X2_IP_ARMORPARTS_2DA ,"NumParts",nPart));
    return nRet;
}
// ----------------------------------------------------------------------------
// (private)
// Returns the previous or next armor appearance type, depending on the specified
// mode (X2_IP_ARMORTYPE_NEXT || X2_IP_ARMORTYPE_PREV)
// ----------------------------------------------------------------------------
int IPGetArmorAppearanceType(object oArmor, int nPart, int nMode)
{
    string sMode;
    switch (nMode)
    {
        case        X2_IP_ARMORTYPE_NEXT : sMode ="Next";
                    break;
        case        X2_IP_ARMORTYPE_PREV : sMode ="Prev";
                    break;
    }
    int nCurrApp  = GetItemAppearance(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,nPart);
    int nRet;
    if (nPart ==ITEM_APPR_ARMOR_MODEL_TORSO)
    {
        nRet = StringToInt(Get2DAString(X2_IP_ARMORAPPEARANCE_2DA ,sMode,nCurrApp));
        return nRet;
    }
    else
    {
        int nMax =  IPGetNumberOfArmorAppearances(nPart)-1; // index from 0 .. numparts -1
        int nMin =  1; // this prevents part 0 from being chosen (naked)
        // return a random valid armor tpze
        if (nMode == X2_IP_ARMORTYPE_RANDOM)
        {
            return Random(nMax)+nMin;
        }
        else
        {
            if (nMode == X2_IP_ARMORTYPE_NEXT)
            {
                // current appearance is max, return min
                if (nCurrApp == nMax)
                {
                    return nMin;
                }
                // current appearance is min, return max  -1
                else if (nCurrApp == nMin)
                {
                    nRet = nMin+1;
                    return nRet;
                }
                //SpeakString("next");
                // next
                nRet = nCurrApp +1;
                return nRet;
            }
            else                // previous
            {
                // current appearance is max, return nMax-1
                if (nCurrApp == nMax)
                {
                    nRet = nMax--;
                    return nRet;
                }
                // current appearance is min, return max
                else if (nCurrApp == nMin)
                {
                    return nMax;
                }
                //SpeakString("prev");
                nRet = nCurrApp -1;
                return nRet;
            }
        }
     }
}
// ----------------------------------------------------------------------------
// Returns the next valid appearance type for oArmor
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
int IPGetNextArmorAppearanceType(object oArmor, int nPart)
{
    return IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_NEXT);
}
// ----------------------------------------------------------------------------
// Returns the next valid appearance type for oArmor
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
int IPGetPrevArmorAppearanceType(object oArmor, int nPart)
{
    return IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_PREV);
}
// ----------------------------------------------------------------------------
// Returns the next valid appearance type for oArmor
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
int IPGetRandomArmorAppearanceType(object oArmor, int nPart)
{
    return  IPGetArmorAppearanceType(oArmor, nPart, X2_IP_ARMORTYPE_RANDOM);
}
// ----------------------------------------------------------------------------
// Returns a new armor based of oArmor with nPartModified
// nPart - ITEM_APPR_ARMOR_MODEL_* constant of the part to be changed
// nMode -
//          X2_IP_ARMORTYPE_NEXT    - next valid appearance
//          X2_IP_ARMORTYPE_PREV    - previous valid apperance;
//          X2_IP_ARMORTYPE_RANDOM  - random valid appearance (torso is never changed);
// bDestroyOldOnSuccess - Destroy oArmor in process?
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
object IPGetModifiedArmor(object oArmor, int nPart, int nMode, int bDestroyOldOnSuccess)
{
    int nNewApp = IPGetArmorAppearanceType(oArmor, nPart,  nMode );
    //SpeakString("old: " + IntToString(GetItemAppearance(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,nPart)));
    //SpeakString("new: " + IntToString(nNewApp));
    object oNew = CopyItemAndModify(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL, nPart, nNewApp,TRUE);
    if (oNew != OBJECT_INVALID)
    {
        if( bDestroyOldOnSuccess )
        {
            DestroyObject(oArmor);
        }
        return oNew;
    }
    // Safety fallback, return old armor on failures
       return oArmor;
}
// ----------------------------------------------------------------------------
// Creates a special ring on oCreature that gives
// all weapon and armor proficiencies to the wearer
// Item is set non dropable
// ----------------------------------------------------------------------------
object IPCreateProficiencyFeatItemOnCreature(object oCreature)
{
    // create a simple golden ring
    object  oRing = CreateItemOnObject("nw_it_mring023",oCreature);
    // just in case
    SetDroppableFlag(oRing, FALSE);
    itemproperty ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_HEAVY);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_MEDIUM);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    ip = ItemPropertyBonusFeat(IP_CONST_FEAT_ARMOR_PROF_LIGHT);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_EXOTIC);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_MARTIAL);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    ip = ItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_SIMPLE);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oRing);
    return oRing;
}
// ----------------------------------------------------------------------------
// Add an item property in a safe fashion, preventing unwanted stacking
// Parameters:
//   oItem     - the item to add the property to
//   ip        - the itemproperty to add
//   fDuration - set 0.0f to add the property permanent, anything else is temporary
//   nAddItemPropertyPolicy - How to handle existing properties. Valid values are:
//     X2_IP_ADDPROP_POLICY_REPLACE_EXISTING - remove any property of the same type, subtype, durationtype before adding;
//     X2_IP_ADDPROP_POLICY_KEEP_EXISTING - do not add if any property with same type, subtype and durationtype already exists;
//     X2_IP_ADDPROP_POLICY_IGNORE_EXISTING - add itemproperty in any case - Do not Use with OnHit or OnHitSpellCast props!
//   bIgnoreDurationType  - If set to TRUE, an item property will be considered identical even if the DurationType is different. Be careful when using this
//                          with X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, as this could lead to a temporary item property removing a permanent one
//   bIgnoreSubType       - If set to TRUE an item property will be considered identical even if the SubType is different.
//
// * WARNING: This function is used all over the game. Touch it and break it and the wrath
//            of the gods will come down on you faster than you can saz "I didn't do it"
// ----------------------------------------------------------------------------
void IPSafeAddItemProperty(object oItem, itemproperty ip, float fDuration =0.0f, int nAddItemPropertyPolicy = X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, int bIgnoreDurationType = FALSE, int bIgnoreSubType = FALSE)
{
    int nType = GetItemPropertyType(ip);
    int nSubType = GetItemPropertySubType(ip);
    int nDuration;
    // if duration is 0.0f, make the item property permanent
    if (fDuration == 0.0f)
    {
        nDuration = DURATION_TYPE_PERMANENT;
    } else
    {
        nDuration = DURATION_TYPE_TEMPORARY;
    }
    int nDurationCompare = nDuration;
    if (bIgnoreDurationType)
    {
        nDurationCompare = -1;
    }
    if (nAddItemPropertyPolicy == X2_IP_ADDPROP_POLICY_REPLACE_EXISTING)
    {
        // remove any matching properties
        if (bIgnoreSubType)
        {
            nSubType = -1;
        }
        IPRemoveMatchingItemProperties(oItem, nType, nDurationCompare, nSubType );
    }
    else if (nAddItemPropertyPolicy == X2_IP_ADDPROP_POLICY_KEEP_EXISTING )
    {
         // do not replace existing properties
        if(IPGetItemHasProperty(oItem, ip, nDurationCompare, bIgnoreSubType))
        {
          return; // item already has property, return
        }
    }
    else //X2_IP_ADDPROP_POLICY_IGNORE_EXISTING
    {
    }
    if (nDuration == DURATION_TYPE_PERMANENT)
    {
        AddItemProperty(nDuration,ip, oItem);
    }
    else
    {
        AddItemProperty(nDuration,ip, oItem,fDuration);
    }
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
int IPGetItemHasProperty(object oItem, itemproperty ipCompareTo, int nDurationCompare, int bIgnoreSubType = FALSE)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    //PrintString ("Filter - T:" + IntToString(GetItemPropertyType(ipCompareTo))+ " S: " + IntToString(GetItemPropertySubType(ipCompareTo)) + " (Ignore: " + IntToString (bIgnoreSubType) + ") D:" + IntToString(nDurationCompare));
    while (GetIsItemPropertyValid(ip))
    {
        // PrintString ("Testing - T: " + IntToString(GetItemPropertyType(ip)));
        if ((GetItemPropertyType(ip) == GetItemPropertyType(ipCompareTo)))
        {
             //PrintString ("**Testing - S: " + IntToString(GetItemPropertySubType(ip)));
             if (GetItemPropertySubType(ip) == GetItemPropertySubType(ipCompareTo) || bIgnoreSubType)
             {
               // PrintString ("***Testing - d: " + IntToString(GetItemPropertyDurationType(ip)));
                if (GetItemPropertyDurationType(ip) == nDurationCompare || nDurationCompare == -1)
                {
                    //PrintString ("***FOUND");
                      return TRUE; // if duration is not ignored and durationtypes are equal, true
                 }
            }
        }
        ip = GetNextItemProperty(oItem);
&am

Modifié par Lazarus Magni, 28 octobre 2013 - 04:25 .


#18
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
 }
    //PrintString ("Not Found");
    return FALSE;
}

object IPGetTargetedOrEquippedMeleeWeapon(object oTarget = OBJECT_INVALID)
{
    if(oTarget == OBJECT_INVALID)
    {
        oTarget = GetSpellTargetObject();
    }
    if(GetIsObjectValid(oTarget) && GetObjectType(oTarget)==OBJECT_TYPE_ITEM)
    {
        if(IPGetIsMeleeWeapon(oTarget))
        {
            return oTarget;
        }
    return OBJECT_INVALID;
    }
    object oWeapon1 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oTarget);
    if(GetIsObjectValid(oWeapon1) && IPGetIsMeleeWeapon(oWeapon1))
    {
        return oWeapon1;
    }
    //this can probably happen only if the right weapon is custom base type
    oWeapon1 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oTarget);
    if(GetIsObjectValid(oWeapon1) && IPGetIsMeleeWeapon(oWeapon1))
    {
        return oWeapon1;
    }
    oWeapon1 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R,oTarget);
    if(GetIsObjectValid(oWeapon1))
    {
        return oWeapon1;
    }
    oWeapon1 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L,oTarget);//left creature weapon was ommited
    if(GetIsObjectValid(oWeapon1))
    {
        return oWeapon1;
    }
    oWeapon1 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B,oTarget);
    if(GetIsObjectValid(oWeapon1))
    {
        return oWeapon1;
    }
return OBJECT_INVALID;
}
object IPGetTargetedOrEquippedArmor(int bAllowShields = FALSE, object oTarget = OBJECT_INVALID)
{
    if(oTarget == OBJECT_INVALID)
    {
        oTarget = GetSpellTargetObject();
    }
    if(GetIsObjectValid(oTarget) && GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
    {
        switch(GetBaseItemType(oTarget))
        {
            case BASE_ITEM_LARGESHIELD:
            case BASE_ITEM_SMALLSHIELD:
            case BASE_ITEM_TOWERSHIELD:
            if(!bAllowShields)
            {
               break;
            }
            case BASE_ITEM_ARMOR:
            return oTarget;
        }
    return OBJECT_INVALID;
    }
    object oArmor1 = GetItemInSlot(INVENTORY_SLOT_CHEST,oTarget);
    if(GetIsObjectValid(oArmor1) && GetBaseItemType(oArmor1) == BASE_ITEM_ARMOR)
    {
        return oArmor1;
    }
    if(bAllowShields)
    {
        oArmor1 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oTarget);
        if(GetIsObjectValid(oArmor1))
        {
            switch(GetBaseItemType(oArmor1))
            {
                case BASE_ITEM_LARGESHIELD:
                case BASE_ITEM_SMALLSHIELD:
                case BASE_ITEM_TOWERSHIELD:
                return oArmor1;
            }
         }
    }
    return OBJECT_INVALID;
}
// ----------------------------------------------------------------------------
// Returns FALSE it the item has no sequencer property
// Returns number of spells that can be stored in any other case
// ----------------------------------------------------------------------------
int IPGetItemSequencerProperty(object oItem)
{
    if (!GetItemHasItemProperty(oItem, ITEM_PROPERTY_CAST_SPELL))
    {
        return FALSE;
    }
    int nCnt;
    itemproperty ip = GetFirstItemProperty(oItem);
    while (GetIsItemPropertyValid(ip) && nCnt ==0)
    {
        if (GetItemPropertyType(ip) ==ITEM_PROPERTY_CAST_SPELL)
        {
            if(GetItemPropertySubType(ip) == 523) // sequencer 3
            {
                nCnt =  3;
            }
            else if(GetItemPropertySubType(ip) == 522) // sequencer 2
            {
                nCnt =  2;
            }
            else if(GetItemPropertySubType(ip) == 521) // sequencer 1
            {
                nCnt =  1;
            }
        }
        ip = GetNextItemProperty(oItem);
    }
    return nCnt;
}
void IPCopyItemProperties(object oSource, object oTarget, int bIgnoreCraftProps = TRUE)
{
    itemproperty ip = GetFirstItemProperty(oSource);
    int nSub;
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT)
        {
            if (bIgnoreCraftProps)
            {
                if (GetItemPropertyType(ip) ==ITEM_PROPERTY_CAST_SPELL)
                {
                    nSub = GetItemPropertySubType(ip);
                    // filter crafting properties
                    if (nSub != 498 && nSub != 499 && nSub  != 526 && nSub != 527)
                    {
                        AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget);
                    }
                }
                else
                {
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget);
                }
            }
            else
            {
                AddItemProperty(DURATION_TYPE_PERMANENT,ip,oTarget);
            }
        }
        ip = GetNextItemProperty(oSource);
    }
}
int IPGetIsIntelligentWeapon(object oItem)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyType(ip) ==  ITEM_PROPERTY_ONHITCASTSPELL)
        {
            if(GetItemPropertySubType(ip) == IP_CONST_ONHIT_CASTSPELL_INTELLIGENT_WEAPON_ONHIT)
            {
                return TRUE;
            }
        }
        ip = GetNextItemProperty(oItem);
    }
    return FALSE;
}
// ----------------------------------------------------------------------------
// (private)
// ----------------------------------------------------------------------------
int IPGetWeaponAppearanceType(object oWeapon, int nPart, int nMode)
{
    string sMode;
    switch (nMode)
    {
        case        X2_IP_WEAPONTYPE_NEXT : sMode ="Next";
                    break;
        case        X2_IP_WEAPONTYPE_PREV : sMode ="Prev";
                    break;
    }
    int nCurrApp  = GetItemAppearance(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL,nPart);
    int nRet;
    int nMax =  9;// IPGetNumberOfArmorAppearances(nPart)-1; // index from 0 .. numparts -1
    int nMin =  1;
    // return a random valid armor tpze
    if (nMode == X2_IP_WEAPONTYPE_RANDOM)
    {
        return Random(nMax)+nMin;
    }
    else
    {
        if (nMode == X2_IP_WEAPONTYPE_NEXT)
        {
            // current appearance is max, return min
            if (nCurrApp == nMax)
            {
                return nMax;
            }
            // current appearance is min, return max  -1
            else if (nCurrApp == nMin)
            {
                nRet = nMin +1;
                return nRet;
            }
            //SpeakString("next");
            // next
            nRet = nCurrApp +1;
            return nRet;
        }
        else                // previous
        {
            // current appearance is max, return nMax-1
            if (nCurrApp == nMax)
            {
                nRet = nMax--;
                return nRet;
            }
            // current appearance is min, return max
            else if (nCurrApp == nMin)
            {
                return nMin;
            }
            //SpeakString("prev");
            nRet = nCurrApp -1;
            return nRet;
        }

     }
}
// ----------------------------------------------------------------------------
// Returns a new armor based of oArmor with nPartModified
// nPart - ITEM_APPR_WEAPON_MODEL_* constant of the part to be changed
// nMode -
//          X2_IP_WEAPONTYPE_NEXT    - next valid appearance
//          X2_IP_WEAPONTYPE_PREV    - previous valid apperance;
//          X2_IP_WEAPONTYPE_RANDOM  - random valid appearance (torso is never changed);
// bDestroyOldOnSuccess - Destroy oArmor in process?
// Uses Get2DAstring, so do not use in loops
// ----------------------------------------------------------------------------
object IPGetModifiedWeapon(object oWeapon, int nPart, int nMode, int bDestroyOldOnSuccess)
{
    int nNewApp = IPGetWeaponAppearanceType(oWeapon, nPart,  nMode );
    //SpeakString("old: " + IntToString(GetItemAppearance(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL,nPart)));
    //SpeakString("new: " + IntToString(nNewApp));
    object oNew = CopyItemAndModify(oWeapon,ITEM_APPR_TYPE_WEAPON_MODEL, nPart, nNewApp,TRUE);
    if (oNew != OBJECT_INVALID)
    {
        if( bDestroyOldOnSuccess )
        {
            DestroyObject(oWeapon);
        }
        return oNew;
    }
    // Safety fallback, return old weapon on failures
       return oWeapon;
}

object IPCreateAndModifyArmorRobe(object oArmor, int nRobeType)
{
    object oRet = CopyItemAndModify(oArmor,ITEM_APPR_TYPE_ARMOR_MODEL,ITEM_APPR_ARMOR_MODEL_ROBE,nRobeType+2,TRUE);
    if (GetIsObjectValid(oRet))
    {
        return oRet;
    }
    // safety net
    return oArmor;
}
// ----------------------------------------------------------------------------
// Provide mapping between numbers and power constants for
// ITEM_PROPERTY_DAMAGE_BONUS
// ----------------------------------------------------------------------------
int IPGetDamagePowerConstantFromNumber(int nNumber)
{
    switch (nNumber)
    {
        case 0: return DAMAGE_POWER_NORMAL;
        case 1: return DAMAGE_POWER_PLUS_ONE;
        case 2: return  DAMAGE_POWER_PLUS_TWO;
        case 3: return DAMAGE_POWER_PLUS_THREE;
        case 4: return DAMAGE_POWER_PLUS_FOUR;
        case 5: return DAMAGE_POWER_PLUS_FIVE;
        case 6: return DAMAGE_POWER_PLUS_SIX;
        case 7: return DAMAGE_POWER_PLUS_SEVEN;
        case 8: return DAMAGE_POWER_PLUS_EIGHT;
        case 9: return DAMAGE_POWER_PLUS_NINE;
        case 10: return DAMAGE_POWER_PLUS_TEN;
        case 11: return DAMAGE_POWER_PLUS_ELEVEN;
        case 12: return DAMAGE_POWER_PLUS_TWELVE;
        case 13: return DAMAGE_POWER_PLUS_THIRTEEN;
        case 14: return DAMAGE_POWER_PLUS_FOURTEEN;
        case 15: return DAMAGE_POWER_PLUS_FIFTEEN;
        case 16: return DAMAGE_POWER_PLUS_SIXTEEN;
        case 17: return DAMAGE_POWER_PLUS_SEVENTEEN;
        case 18: return DAMAGE_POWER_PLUS_EIGHTEEN;
        case 19: return DAMAGE_POWER_PLUS_NINTEEN;
        case 20: return DAMAGE_POWER_PLUS_TWENTY;
    }
    if (nNumber>20)
    {
        return DAMAGE_POWER_PLUS_TWENTY;
    }
    return DAMAGE_POWER_NORMAL;
}
// ----------------------------------------------------------------------------
// Provide mapping between numbers and bonus constants for ITEM_PROPERTY_DAMAGE_BONUS
// Note that nNumber should be > 0!
// ----------------------------------------------------------------------------
int IPGetDamageBonusConstantFromNumber(int nNumber)
{
    switch (nNumber)
    {
        case 1:  return DAMAGE_BONUS_1;
        case 2:  return DAMAGE_BONUS_2;
        case 3:  return DAMAGE_BONUS_3;
        case 4:  return DAMAGE_BONUS_4;
        case 5:  return DAMAGE_BONUS_5;
        case 6:  return DAMAGE_BONUS_6;
        case 7:  return DAMAGE_BONUS_7;
        case 8:  return DAMAGE_BONUS_8;
        case 9:  return DAMAGE_BONUS_9;
        case 10: return DAMAGE_BONUS_10;
        case 11:  return DAMAGE_BONUS_11;
        case 12:  return DAMAGE_BONUS_12;
        case 13:  return DAMAGE_BONUS_13;
        case 14:  return DAMAGE_BONUS_14;
        case 15:  return DAMAGE_BONUS_15;
        case 16:  return DAMAGE_BONUS_16;
        case 17:  return DAMAGE_BONUS_17;
        case 18:  return DAMAGE_BONUS_18;
        case 19:  return DAMAGE_BONUS_19;
        case 20:  return DAMAGE_BONUS_20;
    }
    if (nNumber>20)
    {
        return DAMAGE_BONUS_20;
    }
    return -1;
}
// ----------------------------------------------------------------------------
// GZ, Sept. 30 2003
// Special Version of Copy Item Properties for use with greater wild shape
// oOld - Item equipped before polymorphing (source for item props)
// oNew - Item equipped after polymorphing  (target for item props)
// bWeapon - Must be set TRUE when oOld is a weapon.
// ----------------------------------------------------------------------------
void IPWildShapeCopyItemProperties(object oOld, object oNew, int bWeapon = FALSE)
{
    if (GetIsObjectValid(oOld) && GetIsObjectValid(oNew))
    {
        itemproperty ip = GetFirstItemProperty(oOld);
        while (GetIsItemPropertyValid(ip))
        {
            if(GetItemPropertyType(ip) == ITEM_PROPERTY_ABILITY_BONUS && GetItemPropertySubType(ip) == IP_CONST_ABILITY_CON)
            {
            //do nothing
            }
            else if (bWeapon)
            {
                if (GetWeaponRanged(oOld) == GetWeaponRanged(oNew)   )
                {
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
                }
            }
            else
            {
                    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oNew);
            }
            ip = GetNextItemProperty(oOld);
        }
    }
}
// ----------------------------------------------------------------------------
// Returns the current enhancement bonus of a weapon (+1 to +20), 0 if there is
// no enhancement bonus. You can test for a specific type of enhancement bonus
// by passing the appropritate ITEM_PROPERTY_ENHANCEMENT_BONUS* constant into
// nEnhancementBonusType
// ----------------------------------------------------------------------------
int IPGetWeaponEnhancementBonus(object oWeapon, int nEnhancementBonusType = ITEM_PROPERTY_ENHANCEMENT_BONUS)
{
    itemproperty ip = GetFirstItemProperty(oWeapon);
    int nFound = 0;
    while (nFound == 0 && GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyType(ip) ==nEnhancementBonusType)
        {
            nFound = GetItemPropertyCostTableValue(ip);
        }
        ip = GetNextItemProperty(oWeapon);
    }
    return nFound;
}
// ----------------------------------------------------------------------------
// Shortcut function to set the enhancement bonus of a weapon to a certain bonus
// Specifying bOnlyIfHigher as TRUE will prevent a bonus lower than the requested
// bonus from being applied. Valid values for nBonus are 1 to 20.
// ----------------------------------------------------------------------------
void IPSetWeaponEnhancementBonus(object oWeapon, int nBonus, int bOnlyIfHigher = TRUE)
{
    int nCurrent = IPGetWeaponEnhancementBonus(oWeapon);
    if (nBonus < 1)
    {
        return;
    }
    else if(nBonus > 20)//1.70 new feature, if higher than 20, allow at least 20!
    {
        nBonus = 20;
    }
    if (bOnlyIfHigher && nCurrent >= nBonus)//1.70 fix, if only higher then must not be equal too
    {
        return;
    }
    itemproperty ip = GetFirstItemProperty(oWeapon);
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyType(ip) ==ITEM_PROPERTY_ENHANCEMENT_BONUS)
        {
            RemoveItemProperty(oWeapon,ip);
        }
        ip = GetNextItemProperty(oWeapon);
    }
    ip = ItemPropertyEnhancementBonus(nBonus);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapon);
}

// ----------------------------------------------------------------------------
// Shortcut function to upgrade the enhancement bonus of a weapon by the
// number specified in nUpgradeBy. If the resulting new enhancement bonus
// would be out of bounds (>+20), it will be set to +20
// ----------------------------------------------------------------------------
void IPUpgradeWeaponEnhancementBonus(object oWeapon, int nUpgradeBy)
{
    int nCurrent = IPGetWeaponEnhancementBonus(oWeapon);
    itemproperty ip = GetFirstItemProperty(oWeapon);
    int nNew = nCurrent + nUpgradeBy;
    if (nNew < 1)
    {
        nNew = 1;
    }
    else if (nNew >20)
    {
       nNew = 20;
    }
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyType(ip) ==ITEM_PROPERTY_ENHANCEMENT_BONUS)
        {
            RemoveItemProperty(oWeapon,ip);
        }
        ip = GetNextItemProperty(oWeapon);
    }
    ip = ItemPropertyEnhancementBonus(nNew);
    AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapon);
}
int IPGetHasItemPropertyByConst(int nItemProp, object oItem)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    while (GetIsItemPropertyValid(ip))
    {
        if (GetItemPropertyType(ip) ==nItemProp)
        {
            return TRUE;
        }
        ip = GetNextItemProperty(oItem);
    }
    return FALSE;
}
// ----------------------------------------------------------------------------
// Returns TRUE if a use limitation of any kind is present on oItem
// ----------------------------------------------------------------------------
int IPGetHasUseLimitation(object oItem)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    while(GetIsItemPropertyValid(ip))
    {
        switch(GetItemPropertyType(ip))
        {
            case ITEM_PROPERTY_USE_LIMITATION_ALIGNMENT_GROUP:
            case ITEM_PROPERTY_USE_LIMITATION_CLASS:
            case ITEM_PROPERTY_USE_LIMITATION_RACIAL_TYPE:
            case ITEM_PROPERTY_USE_LIMITATION_SPECIFIC_ALIGNMENT:
            return TRUE;
        }
   ip = GetNextItemProperty(oItem);
   }
   return FALSE;
}
//------------------------------------------------------------------------------
// GZ, Oct 2003
// Returns TRUE if a character has any item equipped that has the itemproperty
// defined in nItemPropertyConst in it (ITEM_PROPERTY_* constant)
//------------------------------------------------------------------------------
int IPGetHasItemPropertyOnCharacter(object oPC, int nItemPropertyConst)
{
    object oWeaponOld = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
    object oArmorOld  = GetItemInSlot(INVENTORY_SLOT_CHEST,oPC);
    object oRing1Old  = GetItemInSlot(INVENTORY_SLOT_LEFTRING,oPC);
    object oRing2Old  = GetItemInSlot(INVENTORY_SLOT_RIGHTRING,oPC);
    object oAmuletOld = GetItemInSlot(INVENTORY_SLOT_NECK,oPC);
    object oCloakOld  = GetItemInSlot(INVENTORY_SLOT_CLOAK,oPC);
    object oBootsOld  = GetItemInSlot(INVENTORY_SLOT_BOOTS,oPC);
    object oBeltOld   = GetItemInSlot(INVENTORY_SLOT_BELT,oPC);
    object oHelmetOld = GetItemInSlot(INVENTORY_SLOT_HEAD,oPC);
    object oLeftHand  = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
    int bHas =  IPGetHasItemPropertyByConst(nItemPropertyConst, oWeaponOld);
     bHas = bHas ||  IPGetHasItemPropertyByConst(nItemPropertyConst, oLeftHand);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oArmorOld);
    if (bHas)
        return TRUE;
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oRing1Old);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oRing2Old);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oAmuletOld);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oCloakOld);
    if (bHas)
        return TRUE;
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oBootsOld);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oBeltOld);
    bHas = bHas || IPGetHasItemPropertyByConst(nItemPropertyConst, oHelmetOld);
    return bHas;
}
//------------------------------------------------------------------------------
// GZ, Oct 24, 2003
// Returns an integer with the number of properties present oItem
//------------------------------------------------------------------------------
int IPGetNumberOfItemProperties(object oItem)
{
    itemproperty ip = GetFirstItemProperty(oItem);
    int nCount = 0;
    while (GetIsItemPropertyValid(ip))
    {
        nCount++;
        ip = GetNextItemProperty(oItem);
    }
    return nCount;
}
//1.70 by Shadooow, private function for shifter polymorp and con bonus issue
int IPGetBestConBonus(int bestCon, object oItem)
{
    int nCon;
    itemproperty ip = GetFirstItemProperty(oItem);
    while (GetIsItemPropertyValid(ip))
    {
        if(GetItemPropertyType(ip) == ITEM_PROPERTY_ABILITY_BONUS && GetItemPropertySubType(ip) == IP_CONST_ABILITY_CON)
        {
            nCon = GetItemPropertyCostTableValue(ip);
            if(nCon > bestCon)
            {
                bestCon = nCon;
            }
        }
        ip = GetNextItemProperty(oItem);
    }
    return bestCon;
}

#19
Lazarus Magni

Lazarus Magni
  • Members
  • 1 134 messages
Delete the &am at the end of the second last post.

After an hour of digging through our mod, this is the best I could find. Not sure if this is what we use, but this is my best guess.

#20
MagicalMaster

MagicalMaster
  • Members
  • 2 002 messages
Appreciated, Lazarus, but I've come up with a simpler solution that fixes the item properties (reshift and unshift once they come back to life for a split second) and also have a solution in place for the wisdom spell slots while shifted.

Mainly the bonus spell slots that I'm worried about now.

Your scripts are a lot more elegant for merging but I'm trying to spend a minimum of time on this specific project. Already spent like twice as much time on shifters as every other class put together!