Author Topic: Improving AA abilities  (Read 770 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #15 on: December 06, 2011, 02:11:41 am »


               Hmm that's a shame, as this has been requested by multiple players on our server. I guess I will have to look into some other way to boost these abilites. We have this same issue with smite, and Ki critical.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #16 on: December 06, 2011, 02:33:53 am »


               BTW in case it is helpfull this is the core_inc_post40 script:


#include "x2_inc_itemprop"
 
const int MAX_AB_BONUS = 20;               // maximum ab bonus to give out to keep values from overflowing
 
int pf_GetLevelFromXP( int nXP )
{
  int nLevel = FloatToInt(( sqrt(( IntToFloat( nXP ) * 20 ) + 2500 ) / 100 ) + 0.5 );
  return nLevel;
}
 
float calcMeleeFactor( object oPC )
{
  int nLevels = 160;
  nLevels -= ( GetLevelByclass( class_TYPE_WIZARD, oPC ) * 4 );
  nLevels -= ( GetLevelByclass( class_TYPE_SORCERER, oPC ) * 4 );
  nLevels -= ( GetLevelByclass( class_TYPE_PALEMASTER, oPC ) * 3 );
  nLevels -= ( GetLevelByclass( class_TYPE_DRAGON_DISCIPLE, oPC ) * 2 );
  nLevels -= ( GetLevelByclass( class_TYPE_CLERIC, oPC ) * 2 );
  nLevels -= ( GetLevelByclass( class_TYPE_DRUID, oPC ) * 2 );
  nLevels -= ( GetLevelByclass( class_TYPE_SHIFTER, oPC ) * 2 );
  nLevels -= ( GetLevelByclass( class_TYPE_BARD, oPC ) * 2 );
  nLevels -= ( GetLevelByclass( class_TYPE_ROGUE, oPC ) );
  nLevels -= ( GetLevelByclass( class_TYPE_MONK, oPC ) );
  nLevels -= ( GetLevelByclass( class_TYPE_ASSASSIN, oPC ) );
  nLevels -= ( GetLevelByclass( class_TYPE_SHADOWDANCER, oPC ) );
  nLevels -= ( GetLevelByclass( class_TYPE_HARPER, oPC ) );
 
 
  float fFactor = IntToFloat( nLevels ) / 160.0;
  return fFactor;
}
 
void ApplyDmgBonus( object oPC, int nDamageType, int nBonus )
{
  // max damage bonus per type is 20
  effect eDamageBonus;
  switch( nBonus )
  {
    case 0:  break;
    case 1:  nBonus = DAMAGE_BONUS_1;  break;
    case 2:  nBonus = DAMAGE_BONUS_2;  break;
    case 3:  nBonus = DAMAGE_BONUS_3;  break;
    case 4:  nBonus = DAMAGE_BONUS_4;  break;
    case 5:  nBonus = DAMAGE_BONUS_5;  break;
    case 6:  nBonus = DAMAGE_BONUS_6;  break;
    case 7:  nBonus = DAMAGE_BONUS_7;  break;
    case 8:  nBonus = DAMAGE_BONUS_8;  break;
    case 9:  nBonus = DAMAGE_BONUS_9;  break;
    case 10: nBonus = DAMAGE_BONUS_10; break;
    case 11: nBonus = DAMAGE_BONUS_11; break;
    case 12: nBonus = DAMAGE_BONUS_12; break;
    case 13: nBonus = DAMAGE_BONUS_13; break;
    case 14: nBonus = DAMAGE_BONUS_14; break;
    case 15: nBonus = DAMAGE_BONUS_15; break;
    case 16: nBonus = DAMAGE_BONUS_16; break;
    case 17: nBonus = DAMAGE_BONUS_17; break;
    case 18: nBonus = DAMAGE_BONUS_18; break;
    case 19: nBonus = DAMAGE_BONUS_19; break;
    default: nBonus = DAMAGE_BONUS_20; break;
  }
  if ( nBonus != 0 )
  {
    eDamageBonus = SupernaturalEffect( EffectDamageIncrease( nBonus, nDamageType ));
    ApplyEffectToObject( DURATION_TYPE_PERMANENT, eDamageBonus, oPC );
  }
}
 
void ApplyPost40MeleeBonus( object oPC, int nAltTxt = 0 )
{
  // Modifier introduced for barbarian rage
  float fBonusMod = GetLocalFloat(oPC, "core_post_modifier");
  int nXP = GetXP( oPC );
  int nLevel = pf_GetLevelFromXP( nXP );
  if ( nLevel > 39 )
  {
    int nStrMod = GetAbilityModifier( ABILITY_STRENGTH, oPC );
    if ( nStrMod > 11 )
    {
      itemproperty ip = ItemPropertyOnHitCastSpell( 126, 1 ); // planar rift effect
      object oWeapon = GetItemInSlot( INVENTORY_SLOT_RIGHTHAND, oPC );
      if ( IPGetIsMeleeWeapon( oWeapon ))
      {
        IPSafeAddItemProperty( oWeapon, ip, HoursToSeconds( 24 ));
        SendMessageToPC( oPC, "Adding on-hit strength damage to primary weapon" );
      }
    }
 
    string sRune = "You have no melee rune";
    int nPost = ( nLevel - 40 );
    int nPureBonus = 0;
    int nRequiredXP = ((( nLevel * ( nLevel + 1 )) / 2 ) * 1000 );
    float fMeleeFactor = calcMeleeFactor( oPC );
 
    if ( fMeleeFactor == 1.0 )
    {
      if(!nAltTxt)
        SendMessageToPC( oPC, "Additional bonus melee ab/damage for 40 levels of pure melee classes" );
      nPureBonus = nPost/8;
    }
    fMeleeFactor += fBonusMod;
 
    int nAB = FloatToInt( IntToFloat( nPost )/ 2.0 * fMeleeFactor );
 
    if ( GetIsObjectValid( GetItemPossessedBy( oPC, "GrtrMeleeRunV2" )))
    {
      fMeleeFactor *= 1.0 + (0.5);
      sRune = "You have a greater melee rune";
    }
    else if ( GetIsObjectValid( GetItemPossessedBy( oPC, "LesrMeleeRunV2" )))
    {
      fMeleeFactor *= 1.0 + (0.25);
      sRune = "You have a lesser melee rune";
    }
 
    int nBonus = FloatToInt( IntToFloat( nPost ) / 2.0 * fMeleeFactor ) + nPureBonus;
 
    nAB = ( nAB > MAX_AB_BONUS ? MAX_AB_BONUS : nAB );
 
    ApplyEffectToObject( DURATION_TYPE_PERMANENT, SupernaturalEffect( EffectAttackIncrease( nAB, ATTACK_BONUS_MISC )), oPC );
 
    if(!nAltTxt)
        SendMessageToPC( oPC, sRune + " and enough experience for level " +
                              IntToString( nLevel ) + " which gives you +" + IntToString( nAB ) +
                              " bonus AB and " + IntToString( nBonus ) + " bonus damage.  You will reach level " +
                              IntToString( nLevel + 1 ) + " at " + IntToString( nRequiredXP ) + " experience." );
    else
        SendMessageToPC(oPC, "Your Barbarian Rage Has increased your bonus damage to " + IntToString( nBonus ));
 
    ApplyDmgBonus( oPC, DAMAGE_TYPE_SLASHING, nBonus / 6 );
    ApplyDmgBonus( oPC, DAMAGE_TYPE_PIERCING, nBonus / 6 );
    ApplyDmgBonus( oPC, DAMAGE_TYPE_BLUDGEONING, nBonus / 6 + nBonus % 6 );
    ApplyDmgBonus( oPC, DAMAGE_TYPE_FIRE, nBonus / 6 );
    ApplyDmgBonus( oPC, DAMAGE_TYPE_COLD, nBonus / 6 );
    ApplyDmgBonus( oPC, DAMAGE_TYPE_ELECTRICAL, nBonus / 6 );
 
    nBonus -= 120;
    if ( nBonus > 0 )
    {
      ApplyDmgBonus( oPC, DAMAGE_TYPE_ACID, nBonus / 3 );
      ApplyDmgBonus( oPC, DAMAGE_TYPE_SONIC, nBonus / 3 );
      ApplyDmgBonus( oPC, DAMAGE_TYPE_NEGATIVE, nBonus / 3 + nBonus % 3 );
    }
    nBonus -= 60;
    if ( nBonus > 0 )
    {
      ApplyDmgBonus( oPC, DAMAGE_TYPE_DIVINE, nBonus / 3 );
      ApplyDmgBonus( oPC, DAMAGE_TYPE_POSITIVE, nBonus / 3 );
      ApplyDmgBonus( oPC, DAMAGE_TYPE_MAGICAL, nBonus / 3 + nBonus % 3 );
    }
  }
 
  //blinding speed feat changes
  if( GetHasFeat( FEAT_EPIC_BLINDING_SPEED )){
    if( GetLevelByclass( class_TYPE_PALEMASTER, oPC ) < 1 )
    {
        //get the dex mod of oPC
        int iDexMod = GetAbilityModifier( ABILITY_DEXTERITY, oPC );
        //apply this as a deflection armour bonus
        int iDexACBonus = (iDexMod * 7) / 10;
        if ( iDexACBonus > 0 )
        {
        effect eDexMod = EffectACIncrease( iDexACBonus, AC_DEFLECTION_BONUS );
        ApplyEffectToObject( DURATION_TYPE_PERMANENT, SupernaturalEffect( eDexMod ), oPC );
        SendMessageToPC( oPC, "Giving +" + IntToString( iDexACBonus ) + " AC for blinding speed" );
        }
    }
    else
        SendMessageToPC( oPC, "Palemasters do not get a bonus from blinding speed" );
  }
}
 
void ClearPost40Bonus( object oPC )
{
  // iterate through the current effects on the pc and
  // remove all attack and damage effects before adding
  // new ones
  effect eBuff = GetFirstEffect( oPC );
  while( GetIsEffectValid( eBuff ))
  {
    if (( GetEffectDurationType( eBuff ) == DURATION_TYPE_PERMANENT ) &&
        ( GetEffectSubType( eBuff ) == SUBTYPE_SUPERNATURAL ))
    {
      // only checks for permanent, supernatural buffs
      int nType = GetEffectType( eBuff );
      // remove our subtypes
      switch( nType )
      {
        case EFFECT_TYPE_ATTACK_INCREASE:
        case EFFECT_TYPE_DAMAGE_INCREASE:
        case EFFECT_TYPE_IMMUNITY:
        case EFFECT_TYPE_AC_INCREASE:
        case EFFECT_TYPE_AC_DECREASE:
        case EFFECT_TYPE_SKILL_DECREASE:
          RemoveEffect( oPC, eBuff );
          break;
      }
    }
    eBuff = GetNextEffect( oPC );
  }
}
               
               

               


                     Modifié par Lazarus Magni, 06 décembre 2011 - 02:34 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #17 on: December 06, 2011, 02:37:45 am »


               And the include:
               
               

               


                     Modifié par Lazarus Magni, 06 décembre 2011 - 02:40 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #18 on: December 06, 2011, 02:41:18 am »


               #include "core_debug"
 
//::///////////////////////////////////////////////
//:: 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);
    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)
{
    PrintString( "IPGetIPWorkContainer" );
    object oRet = DbgGetObjectByTag(X2_IP_WORK_CONTAINER_TAG);
    if (oRet == OBJECT_INVALID)
    {
        PrintString( "creating IPGetIPWorkContainer" );
        oRet = DbgCreateObject(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_ATTACK_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_ATTACK_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);
   }
 
 
   return ipRet;
}
 
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a projectile
// ----------------------------------------------------------------------------
int IPGetIsProjectile(object oItem)
{
  int nBT = GetBaseItemType(oItem);
  return (nBT == BASE_ITEM_ARROW || nBT == BASE_ITEM_BOLT || nBT == BASE_ITEM_BULLET);
}
 
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a ranged weapon
// ----------------------------------------------------------------------------
int IPGetIsRangedWeapon(object oItem)
{
    return GetWeaponRanged(oItem); // doh !
}
 
// ----------------------------------------------------------------------------
// Returns TRUE if oItem is a melee weapon
// ----------------------------------------------------------------------------
int IPGetIsMeleeWeapon(object oItem)
{
    //Declare major variables
    int nItem = GetBaseItemType(oItem);
 
    if((nItem == BASE_ITEM_BASTARDSWORD) ||
      (nItem == BASE_ITEM_BATTLEAXE) ||
      (nItem == BASE_ITEM_DOUBLEAXE) ||
      (nItem == BASE_ITEM_GREATAXE) ||
      (nItem == BASE_ITEM_GREATSWORD) ||
      (nItem == BASE_ITEM_HALBERD) ||
      (nItem == BASE_ITEM_HANDAXE) ||
      (nItem == BASE_ITEM_KAMA) ||
      (nItem == BASE_ITEM_KATANA) ||
      (nItem == BASE_ITEM_KUKRI) ||
      (nItem == BASE_ITEM_LONGSWORD) ||
      (nItem == BASE_ITEM_SCIMITAR) ||
      (nItem == BASE_ITEM_SCYTHE) ||
      (nItem == BASE_ITEM_SICKLE) ||
      (nItem == BASE_ITEM_TWOBLADEDSWORD) ||
      (nItem == BASE_ITEM_CLUB) ||
      (nItem == BASE_ITEM_DAGGER) ||
      (nItem == BASE_ITEM_DIREMACE) ||
      (nItem == BASE_ITEM_HEAVYFLAIL) ||
      (nItem == BASE_ITEM_LIGHTFLAIL) ||
      (nItem == BASE_ITEM_LIGHTHAMMER) ||
      (nItem == BASE_ITEM_LIGHTMACE) ||
      (nItem == BASE_ITEM_MORNINGSTAR) ||
      (nItem == BASE_ITEM_QUARTERSTAFF) ||
      (nItem == BASE_ITEM_MAGICSTAFF) ||
      (nItem == BASE_ITEM_RAPIER) ||
      (nItem == BASE_ITEM_WHIP) ||
      (nItem == BASE_ITEM_SHORTSPEAR) ||
      (nItem == BASE_ITEM_SHORTSWORD) ||
      (nItem == BASE_ITEM_WARHAMMER)  ||
      (nItem == BASE_ITEM_DWARVENWARAXE))
   {
        return TRUE;
   }
   return FALSE;
}
 
// ----------------------------------------------------------------------------
// Returns TRUE if weapon is a blugeoning weapon
// Uses Get2DAString!
// ----------------------------------------------------------------------------
int IPGetIsBludgeoningWeapon(object oItem)
{
  int nBT = GetBaseItemType(oItem);
  int nWeapon =  ( StringToInt(Get2DAString("baseitems","WeaponType",nBT)));
  // 2 = bludgeoning
  return (nWeapon == 2);
}
 
// ----------------------------------------------------------------------------
// 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 = DbgCreateItemOnObject("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)))
        {
           &nb
               
               

               


                     Modifié par Lazarus Magni, 06 décembre 2011 - 02:43 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Improving AA abilities
« Reply #19 on: December 06, 2011, 07:21:33 am »


               Here is a basic start to getting damage increase effects if the calculation behind them is already known.  (e.g. if someone has divine might, then the bonus from divine might is known to be the charisma modifier).  Sometimes I am giving benefit of doubt (like higher cleric/paladin level for getting divine favor bonus).


struct damage_struct
{
int nMagical, nDivine, nPiercing, nSlashing, nBludgeoning, nNegative, nPositive;
int nFire, nCold, nAcid, nElectrical, nSonic;
};


//Gets various values for damage increase effects
struct damage_struct BonusDamage(object oAttacker = OBJECT_SELF);
//Gets the larger of two numbers
int GetHigher(int n1, int n2);

int GetHigher(int n1, int n2)
{
if(n1 > n2)
 return n1;
return n2;
}

struct damage_struct BonusDamage(object oAttacker = OBJECT_SELF)
{
struct damage_struct stBonus;
//For divine might use current charisma modifier.
if(GetHasFeatEffect(FEAT_DIVINE_MIGHT))
stBonus.nDivine += GetAbilityModifier(ABILITY_CHARISMA, oAttacker);
//Divine Favor can only be cast on self, thus we can check, paladin/cleric class and give benefit of doubt, UMDers are stuck with default scroll caster level
if(GetHasSpellEffect(SPELL_DIVINE_FAVOR))
stBonus.nMagical += GetHigher(GetHigher(GetLevelByclass(class_TYPE_CLERIC, oAttacker), GetLevelByclass(class_TYPE_PALADIN, oAttacker)), 5)/3;
/*Here insert more spells/feats*/
return stBonus;
}

//This shows how to access struct values
void main()
{
struct damage_struct stDamage = BonusDamage();
int nMagicalDamage = stDamage.nMagical;
int nDivineDamage = stDamage.nDivine;
int nPiercingDamage = stDamage.nPiercing;
}


EDIT:Note that the above will note compile because this social forum always lowercases the word class.
               
               

               


                     Modifié par WhiZard, 06 décembre 2011 - 07:25 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Improving AA abilities
« Reply #20 on: December 06, 2011, 04:39:13 pm »


               BTW physical damage doesn't have to be categorized since the game engine changes its type to the weapon damage type right?

Also there is warcry, prayer, bard song, pdk feats and war domain... practically impossible to get this done correctly without NWNX. With NWNX it should be easy as NWNX has GetEffectInteger function.

But anyway, had the divine favor and might applied for all arrows with also all arrow property seems very inbalanced to me. And keep in mind that I am admin of epic loot/action module. On my server, imbue arrow is still very powerfull, death arrow is useable even with DC 20, hail can be used to exploit spawn systems, only seeker is somewhat useless.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Improving AA abilities
« Reply #21 on: December 06, 2011, 06:58:04 pm »


               

ShaDoOoW wrote...

BTW physical damage doesn't have to be categorized since the game engine changes its type to the weapon damage type right?

It does in this case because the damage is not being applied through a weapon, but rather by EffectDamage().  However for DR bypassing, it is a good idea to clump them all together (under one physical type, though I haven't tested combo types like bludgeoning/piercing).  Still, if I am defining a damage struct to potentially be used with other struct functions, I might as well declare all the basics.

Also there is warcry, prayer, bard song, pdk feats and war domain... practically impossible to get this done correctly without NWNX. With NWNX it should be easy as NWNX has GetEffectInteger function.

You can account for the vast majority of the above accurately, if you are looking specifically for them, as I performed above.  Re-calculating the amount may cause assumptions to be made (as with bard song and war domain).

But anyway, had the divine favor and might applied for all arrows with also all arrow property seems very inbalanced to me. And keep in mind that I am admin of epic loot/action module. On my server, imbue arrow is still very powerfull, death arrow is useable even with DC 20, hail can be used to exploit spawn systems, only seeker is somewhat useless.


Probably imbalanced, but at least the scripted calculation doesn't bypass immunities and damage resistance like the normal arrows would with damage increase functions.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Improving AA abilities
« Reply #22 on: December 06, 2011, 07:33:11 pm »


               Lazarus: you aksed for ideas, well my idea is to abadon this solution and rather choose a balance change that would work for you, its easier to implement and also easier to balance. For example on Antiworld, physical damage is added to magical which works for them very well and makes from AAs mage killers.

BTW I tried to implement something similar in past for fake attacks with any weapon, but I never implemented it and because of new NWNX features in past year I also abadoned this solution.

However maybe my old code could be some of use to you, so there is it:

struct offensive_info
{
int Bypass;
int Base, Bludgeoning, Divine, Magical, Positive, Negative;
int Piercing, Slashing, Acid, Cold, Fire, Sonic, Electrical;
int AB;
int CriticalThreat;
int CriticalMultiplier;
int Overwhelming;
int Massive;
int Sneak;
};

//inicialize damage, ab etc. for
//nHand - 1 onhand, 2 offhand
//oWeapon - if invalid, considering as unarmed - not work yet
struct offensive_info InitializeCombatInfo(object oAttacker, object oWeapon, int nHand, object oVersus);

struct offensive_info InitializeCombatInfo(object oAttacker, object oWeapon, int nHand, object oVersus)
{
int nBaseItemType = GetBaseItemType(oWeapon);
 if(oWeapon == OBJECT_INVALID)
 {
 oWeapon = GetItemInSlot(INVENTORY_SLOT_ARMS,oAttacker);
 nBaseItemType = BASE_ITEM_GLOVES;
 }
//sanity check?
struct offensive_info c;
c.Sneak = GetLocalInt(oAttacker,"sneak");
int nBase = StringToInt(Get2DAString("baseitems","NumDice",nBaseItemType));
int nBaseDice = StringToInt(Get2DAString("baseitems","DieToRoll",nBaseItemType));
DebugString("BaseDamage",IntToString(nBase)+"d"+IntToString(nBaseDice));
object oLeftHand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oAttacker);
int nEnhancement,nAttack,nMighty,bKeen;
int nFirst,nSecond;
int nEnchantArrow = (GetLevelByclass(class_TYPE_ARCANE_ARCHER,oAttacker)+1)/2;
 if(nBaseItemType != BASE_ITEM_LONGBOW && nBaseItemType != BASE_ITEM_SHORTBOW)
 {
 nEnchantArrow = 0;
 }
itemproperty ip = GetFirstItemProperty(oWeapon);
 while(GetIsItemPropertyValid(ip))
 {
  switch(GetItemPropertyType(ip))
  {
  case ITEM_PROPERTY_KEEN:
  bKeen = TRUE;
  break;
  case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP:
   if(GetAlignmentGoodEvil(oVersus) == GetItemPropertySubType(ip) || GetAlignmentLawChaos(oVersus) == GetItemPropertySubType(ip))
   {
   nEnhancement = GetItemPropertyCostTableValue(ip) > nEnhancement ? GetItemPropertyCostTableValue(ip) : nEnhancement;
   }
  break;
  case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT:
  nSecond = 3;
   switch(GetItemPropertySubType(ip))
   {
   case IP_CONST_ALIGNMENT_NE:
   nSecond--;
   case IP_CONST_ALIGNMENT_LE:
   nSecond--;
   case IP_CONST_ALIGNMENT_CE:
   nFirst = 5;
   break;
   case IP_CONST_ALIGNMENT_NG:
   nSecond--;
   case IP_CONST_ALIGNMENT_LG:
   nSecond--;
   case IP_CONST_ALIGNMENT_CG:
   nFirst = 4;
   break;
   case IP_CONST_ALIGNMENT_TN:
   nSecond--;
   case IP_CONST_ALIGNMENT_LN:
   nSecond--;
   case IP_CONST_ALIGNMENT_CN:
   nFirst = nSecond;
   break;
   }
   if(GetAlignmentGoodEvil(oVersus) == nFirst && GetAlignmentLawChaos(oVersus) == nSecond)
   {
   nEnhancement = GetItemPropertyCostTableValue(ip) > nEnhancement ? GetItemPropertyCostTableValue(ip) : nEnhancement;
   }
  break;
  case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP:
   if(GetRacialType(oVersus) == GetItemPropertySubType(ip))
   {
   nEnhancement = GetItemPropertyCostTableValue(ip) > nEnhancement ? GetItemPropertyCostTableValue(ip) : nEnhancement;
   }
  break;
  case ITEM_PROPERTY_ENHANCEMENT_BONUS:
  nEnhancement = GetItemPropertyCostTableValue(ip) > nEnhancement ? GetItemPropertyCostTableValue(ip) : nEnhancement;
  break;
  case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
   if(GetAlignmentGoodEvil(oVersus) == GetItemPropertySubType(ip) || GetAlignmentLawChaos(oVersus) == GetItemPropertySubType(ip))
   {
   nAttack = GetItemPropertyCostTableValue(ip) > nAttack ? GetItemPropertyCostTableValue(ip) : nAttack;
   }
  break;
  case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT:
  nSecond = 3;
   switch(GetItemPropertySubType(ip))
   {
   case IP_CONST_ALIGNMENT_NE:
   nSecond--;
   case IP_CONST_ALIGNMENT_LE:
   nSecond--;
   case IP_CONST_ALIGNMENT_CE:
   nFirst = 5;
   break;
   case IP_CONST_ALIGNMENT_NG:
   nSecond--;
   case IP_CONST_ALIGNMENT_LG:
   nSecond--;
   case IP_CONST_ALIGNMENT_CG:
   nFirst = 4;
   break;
   case IP_CONST_ALIGNMENT_TN:
   nSecond--;
   case IP_CONST_ALIGNMENT_LN:
   nSecond--;
   case IP_CONST_ALIGNMENT_CN:
   nFirst = nSecond;
   break;
   }
   if(GetAlignmentGoodEvil(oVersus) == nFirst && GetAlignmentLawChaos(oVersus) == nSecond)
   {
   nAttack = GetItemPropertyCostTableValue(ip) > nAttack ? GetItemPropertyCostTableValue(ip) : nAttack;
   }
  break;
  case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP:
   if(GetRacialType(oVersus) == GetItemPropertySubType(ip))
   {
   nAttack = GetItemPropertyCostTableValue(ip) > nAttack ? GetItemPropertyCostTableValue(ip) : nAttack;
   }
  break;
  case ITEM_PROPERTY_ATTACK_BONUS:
  nAttack = GetItemPropertyCostTableValue(ip) > nAttack ? GetItemPropertyCostTableValue(ip) : nAttack;
  break;
  case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
   if(GetAlignmentGoodEvil(oVersus) == GetItemPropertySubType(ip) || GetAlignmentLawChaos(oVersus) == GetItemPropertySubType(ip))
   {
   nFirst = GetItemPropertyCostTableValue(ip);
    switch(GetItemPropertyParam1Value(ip))
    {
    case IP_CONST_DAMAGETYPE_BLUDGEONING:
    c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nFirst : c.Bludgeoning;
    break;
    case IP_CONST_DAMAGETYPE_PIERCING:
    c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nFirst : c.Piercing;
    break;
    case IP_CONST_DAMAGETYPE_SLASHING:
    c.Slashing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Slashing)) ? nFirst : c.Slashing;
    break;
    case IP_CONST_DAMAGETYPE_MAGICAL:
    c.Magical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Magical)) ? nFirst : c.Magical;
    break;
    case IP_CONST_DAMAGETYPE_ACID:
    c.Acid = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Acid)) ? nFirst : c.Acid;
    break;
    case IP_CONST_DAMAGETYPE_COLD:
    c.Cold = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Cold)) ? nFirst : c.Cold;
    break;
    case IP_CONST_DAMAGETYPE_DIVINE:
    c.Divine = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Divine)) ? nFirst : c.Divine;
    break;
    case IP_CONST_DAMAGETYPE_ELECTRICAL:
    c.Electrical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Electrical)) ? nFirst : c.Electrical;
    break;
    case IP_CONST_DAMAGETYPE_FIRE:
    c.Fire = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Fire)) ? nFirst : c.Fire;
    break;
    case IP_CONST_DAMAGETYPE_NEGATIVE:
    c.Negative = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Negative)) ? nFirst : c.Negative;
    break;
    case IP_CONST_DAMAGETYPE_POSITIVE:
    c.Positive = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Positive)) ? nFirst : c.Positive;
    break;
    case IP_CONST_DAMAGETYPE_SONIC:
    c.Sonic = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Sonic)) ? nFirst : c.Sonic;
    break;
    }
   }
  break;
  case ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT:
  nSecond = 3;
   switch(GetItemPropertySubType(ip))
   {
   case IP_CONST_ALIGNMENT_NE:
   nSecond--;
   case IP_CONST_ALIGNMENT_LE:
   nSecond--;
   case IP_CONST_ALIGNMENT_CE:
   nFirst = 5;
   break;
   case IP_CONST_ALIGNMENT_NG:
   nSecond--;
   case IP_CONST_ALIGNMENT_LG:
   nSecond--;
   case IP_CONST_ALIGNMENT_CG:
   nFirst = 4;
   break;
   case IP_CONST_ALIGNMENT_TN:
   nSecond--;
   case IP_CONST_ALIGNMENT_LN:
   nSecond--;
   case IP_CONST_ALIGNMENT_CN:
   nFirst = nSecond;
   break;
   }
   if(GetAlignmentGoodEvil(oVersus) == nFirst && GetAlignmentLawChaos(oVersus) == nSecond)
   {
   nFirst = GetItemPropertyCostTableValue(ip);
    switch(GetItemPropertyParam1Value(ip))
    {
    case IP_CONST_DAMAGETYPE_BLUDGEONING:
    c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nFirst : c.Bludgeoning;
    break;
    case IP_CONST_DAMAGETYPE_PIERCING:
    c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nFirst : c.Piercing;
    break;
    case IP_CONST_DAMAGETYPE_SLASHING:
    c.Slashing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Slashing)) ? nFirst : c.Slashing;
    break;
    case IP_CONST_DAMAGETYPE_MAGICAL:
    c.Magical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Magical)) ? nFirst : c.Magical;
    break;
    case IP_CONST_DAMAGETYPE_ACID:
    c.Acid = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Acid)) ? nFirst : c.Acid;
    break;
    case IP_CONST_DAMAGETYPE_COLD:
    c.Cold = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Cold)) ? nFirst : c.Cold;
    break;
    case IP_CONST_DAMAGETYPE_DIVINE:
    c.Divine = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Divine)) ? nFirst : c.Divine;
    break;
    case IP_CONST_DAMAGETYPE_ELECTRICAL:
    c.Electrical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Electrical)) ? nFirst : c.Electrical;
    break;
    case IP_CONST_DAMAGETYPE_FIRE:
    c.Fire = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Fire)) ? nFirst : c.Fire;
    break;
    case IP_CONST_DAMAGETYPE_NEGATIVE:
    c.Negative = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Negative)) ? nFirst : c.Negative;
    break;
    case IP_CONST_DAMAGETYPE_POSITIVE:
    c.Positive = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Positive)) ? nFirst : c.Positive;
    break;
    case IP_CONST_DAMAGETYPE_SONIC:
    c.Sonic = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Sonic)) ? nFirst : c.Sonic;
    break;
    }
   }
  break;
  case ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP:
   if(GetRacialType(oVersus) == GetItemPropertySubType(ip))
   {
   nFirst = GetItemPropertyCostTableValue(ip);
    switch(GetItemPropertyParam1Value(ip))
    {
    case IP_CONST_DAMAGETYPE_BLUDGEONING:
    c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nFirst : c.Bludgeoning;
    break;
    case IP_CONST_DAMAGETYPE_PIERCING:
    c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nFirst : c.Piercing;
    break;
    case IP_CONST_DAMAGETYPE_SLASHING:
    c.Slashing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Slashing)) ? nFirst : c.Slashing;
    break;
    case IP_CONST_DAMAGETYPE_MAGICAL:
    c.Magical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Magical)) ? nFirst : c.Magical;
    break;
    case IP_CONST_DAMAGETYPE_ACID:
    c.Acid = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Acid)) ? nFirst : c.Acid;
    break;
    case IP_CONST_DAMAGETYPE_COLD:
    c.Cold = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Cold)) ? nFirst : c.Cold;
    break;
    case IP_CONST_DAMAGETYPE_DIVINE:
    c.Divine = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Divine)) ? nFirst : c.Divine;
    break;
    case IP_CONST_DAMAGETYPE_ELECTRICAL:
    c.Electrical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Electrical)) ? nFirst : c.Electrical;
    break;
    case IP_CONST_DAMAGETYPE_FIRE:
    c.Fire = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Fire)) ? nFirst : c.Fire;
    break;
    case IP_CONST_DAMAGETYPE_NEGATIVE:
    c.Negative = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Negative)) ? nFirst : c.Negative;
    break;
    case IP_CONST_DAMAGETYPE_POSITIVE:
    c.Positive = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Positive)) ? nFirst : c.Positive;
    break;
    case IP_CONST_DAMAGETYPE_SONIC:
    c.Sonic = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Sonic)) ? nFirst : c.Sonic;
    break;
    }
   }
  break;
  case ITEM_PROPERTY_DAMAGE_BONUS:
  nFirst = GetItemPropertyCostTableValue(ip);
   switch(GetItemPropertySubType(ip))
   {
   case IP_CONST_DAMAGETYPE_BLUDGEONING:
   c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nFirst : c.Bludgeoning;
   break;
   case IP_CONST_DAMAGETYPE_PIERCING:
   c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nFirst : c.Piercing;
   break;
   case IP_CONST_DAMAGETYPE_SLASHING:
   c.Slashing = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Slashing)) ? nFirst : c.Slashing;
   break;
   case IP_CONST_DAMAGETYPE_MAGICAL:
   c.Magical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Magical)) ? nFirst : c.Magical;
   break;
   case IP_CONST_DAMAGETYPE_ACID:
   c.Acid = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Acid)) ? nFirst : c.Acid;
   break;
   case IP_CONST_DAMAGETYPE_COLD:
   c.Cold = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Cold)) ? nFirst : c.Cold;
   break;
   case IP_CONST_DAMAGETYPE_DIVINE:
   c.Divine = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Divine)) ? nFirst : c.Divine;
   break;
   case IP_CONST_DAMAGETYPE_ELECTRICAL:
   c.Electrical = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Electrical)) ? nFirst : c.Electrical;
   break;
   case IP_CONST_DAMAGETYPE_FIRE:
   c.Fire = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Fire)) ? nFirst : c.Fire;
   break;
   case IP_CONST_DAMAGETYPE_NEGATIVE:
   c.Negative = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Negative)) ? nFirst : c.Negative;
   break;
   case IP_CONST_DAMAGETYPE_POSITIVE:
   c.Positive = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Positive)) ? nFirst : c.Positive;
   break;
   case IP_CONST_DAMAGETYPE_SONIC:
   c.Sonic = StringToInt(Get2DAString("iprp_damagecost","Rank",nFirst)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Sonic)) ? nFirst : c.Sonic;
   break;
   }
  break;
  case ITEM_PROPERTY_MASSIVE_CRITICALS://not stack with itself
  c.Massive = GetItemPropertyCostTableValue(ip) > c.Massive ? GetItemPropertyCostTableValue(ip) : c.Massive;
  break;
  case ITEM_PROPERTY_MIGHTY:
  nMighty = GetItemPropertyCostTableValue(ip) > nMighty ? GetItemPropertyCostTableValue(ip) : nMighty;
  break;
  //TODO  case ITEM_PROPERTY_NO_DAMAGE: -> overwhelming not count
  //TODO  case ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE:
  //TODO  case ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE:
  }
 ip = GetNextItemProperty(oWeapon);
 }
c.Bypass = nAttack > nEnhancement ? nAttack : nEnhancement;
 if(c.Bypass < nEnchantArrow)
 {
 c.Bypass = nEnchantArrow;
 }
struct damage_type d = WeaponDamageType(oWeapon);
 if(nEnhancement > 0)
 {
 nEnhancement = DMGBonusToIP(nEnhancement);
  if(d.type2 < 0)
  {
   switch(d.type1)
   {
   case IP_CONST_DAMAGETYPE_BLUDGEONING:
   c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nEnhancement)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nEnhancement : c.Bludgeoning;
   break;
   case IP_CONST_DAMAGETYPE_PIERCING:
   c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nEnhancement)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nEnhancement : c.Piercing;
   break;
   case IP_CONST_DAMAGETYPE_SLASHING:
   c.Slashing = StringToInt(Get2DAString("iprp_damagecost","Rank",nEnhancement)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Slashing)) ? nEnhancement : c.Slashing;
   break;
   }
  }
  else
  {//if weapon has two damage types second one is used for enhancement purposes
   switch(d.type2)
   {
   case IP_CONST_DAMAGETYPE_BLUDGEONING:
   c.Bludgeoning = StringToInt(Get2DAString("iprp_damagecost","Rank",nEnhancement)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Bludgeoning)) ? nEnhancement : c.Bludgeoning;
   break;
   case IP_CONST_DAMAGETYPE_PIERCING:
   c.Piercing = StringToInt(Get2DAString("iprp_damagecost","Rank",nEnhancement)) > StringToInt(Get2DAString("iprp_damagecost","Rank",c.Piercing)) ? nEnhancement : c.Piercing;
   break;
   }
  }
 }
int bWeaponChoice = GetHasFeat(StringToInt(Get2DAString("weaponfeats","WC",nBaseItemType)),oAttacker);
int nStrMod = GetAbilityModifier(ABILITY_STRENGTH,oAttacker);
int nWisMod = GetAbilityModifier(ABILITY_WISDOM,oAttacker);
int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY,oAttacker);
int bRanged = GetWeaponRanged(oWeapon);
float fDistance;
c.AB = GetBaseAttackBonus(oAttacker)+nEnchantArrow;
 if(GetHasFeat(FEAT_WEAPON_FINESSE,oAttacker) && GetIsFinessableWeapon(nBaseItemType))
 {
 c.AB+= nDexMod > nStrMod ? nDexMod : nStrMod;
 }
 else if(bRanged)
 {
  switch(GetCurrentAction(oVersus))
  {//-2 ab in ranged if target is moving
  case ACTION_MOVETOPOINT:
  case ACTION_FOLLOW:
  case ACTION_RANDOMWALK:
  c.AB-= 2;
  break;
  }
  if(GetHasFeat(FEAT_POINT_BLANK_SHOT,oAttacker))
  {//Point Blank Shot -> +1ab if target is in 15 feet distance
  fDistance = GetDistanceBetween(oAttacker,oVersus);
   if(fDistance <= FeetToMeters(15.0) && fDistance > 0.0)
   {
   c.AB++;
   }
  }
  else
  {
  object oEnemy = GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oAttacker);
   if(GetIsObjectValid(oEnemy) && GetDistanceBetween(oAttacker,oVersus) <= 3.5)
   {//shooting in meelee -> -4 ab penalty
   c.AB-= 4;
   }
  }
  if(GetHasFeat(FEAT_ZEN_ARCHERY,oAttacker))
  {
  c.AB+= nWisMod > nDexMod ? nWisMod : nDexMod;
  }
  else
  {
  c.AB+= nDexMod;
  }
 }
 else
 {
 c.AB+= nStrMod;
 }
c.AB += GetHasFeat(FEAT_EPIC_PROWESS,oAttacker);
c.AB += GetHasFeat(StringToInt(Get2DAString("weaponfeats","WF",nBaseItemType)),oAttacker);
c.AB += GetHasFeat(StringToInt(Get2DAString("weaponfeats","EWF",nBaseItemType)),oAttacker) ? 2 : 0;
 if(bWeaponChoice)
 {
 int nWM = GetLevelByclass(class_TYPE_WEAPON_MASTER,oAttacker);
  if(nWM > 4) //WM na lvl 5 +1ab
  {
  c.AB++;
  nWM = (nWM-10)/3;
   if(nWM > 0)//kazde 3 lvl nad 10 +1ab
   {
   c.AB+= nWM;
   }
  }
 }
int bDouble = GetIsDoubleWeapon(oWeapon); //IPGetIsMeleeWeapon(oLeftHand)
int bLight = GetIsLightWeapon(oWeapon) || bDouble;
 if(GetIsObjectValid(oLeftHand) && (oLeftHand == oWeapon || bDouble || Get2DAString("weaponfeats","EWF",GetBaseItemType(oLeftHand)) != "-"))
 {//dual wield
 c.AB-= 10;
  if(GetHasFeat(374,oAttacker) && GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CHEST,oAttacker)) ? NWNXFuncs_GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST,oAttacker)) : 0 < 4)
  {//ranger dual wield feat
  c.AB+= 6;
  }
  else
  {
   if(GetHasFeat(FEAT_AMBIDEXTERITY,oAttacker))
   {
   c.AB+= 4;
   }
   if(GetHasFeat(FEAT_TWO_WEAPON_FIGHTING,oAttacker))
   {
   c.AB+= 2;
   }
  }
  if(bLight)
  {//its light - TODO support for oversized two weapon fighting
  c.AB+= 2;
  }
 }
 if(GetActionMode(oAttacker,ACTION_MODE_FLURRY_OF_BLOWS) || GetActionMode(oAttacker,ACTION_MODE_RAPID_SHOT))
 {
 c.AB-= 2;
 }
 else if(GetActionMode(oAttacker,ACTION_MODE_EXPERTISE))
 {
 c.AB-= 5;
 }
 else if(GetActionMode(oAttacker,ACTION_MODE_IMPROVED_EXPERTISE))
 {
 c.AB-= 10;
 }
////////////////////////////////////////////////////////////////////////////////
 if(oLeftHand != oWeapon)//special bonuses from my old-new prestige classes
 {                       //dispater, hextor, power attack/shot
 c.AB+= GetLocalInt(oAttacker,"rAB");
 }
 else
 {
 c.AB+= GetLocalInt(oAttacker,"lAB");
 }
////////////////////////////////////////////////////////////////////////////////
c.CriticalMultiplier = StringToInt(Get2DAString("baseitems","CritHitMult",nBaseItemType));
 if(bWeaponChoice && GetHasFeat(FEAT_INCREASE_MULTIPLIER,oAttacker))
 {
 c.CriticalMultiplier++;
 }
int nCritThreat = StringToInt(Get2DAString("baseitems","CritThreat",nBaseItemType));
nCritThreat*= 1+bKeen+GetHasFeat(StringToInt(Get2DAString("weaponfeats","IC",nBaseItemType)),oAttacker);
 if(bWeaponChoice && GetHasFeat(FEAT_KI_CRITICAL,oAttacker))
 {
 nCritThreat+= 2;
 }
c.CriticalThreat = 21-nCritThreat;
 if(GetHasFeat(StringToInt(Get2DAString("weaponfeats","OC",nBaseItemType)),oAttacker))
 {//overwhelming critical feat handling
 c.Overwhelming = c.CriticalMultiplier;//ingame description wrong its 1d6more
 }
nSecond = StringToInt(Get2DAString("baseitems","DieToRoll",nBaseItemType));
 for(nFirst = StringToInt(Get2DAString("baseitems","NumDice",nBaseItemType));nFirst > 0;nFirst--)
 {//base weapon damage
 c.Base+= Random(nSecond)+1;
 }
DebugString("BaseDamage",IntToString(c.Base));
c.Base+= nEnchantArrow;
 if(!bRanged || nBaseItemType == BASE_ITEM_THROWINGAXE || nBaseItemType == BASE_ITEM_DART)
 {//light weapon gets only 50% damage from str, two handed weapons get 1.5x damage from str
 nFirst = (nStrMod/2)*2 != nStrMod;//this makes rounding upward
 c.Base = bLight && nHand == 2 ? nStrMod/2+nFirst : GetIsTwoHandedWeapon(oWeapon) ? (nStrMod*15)/10 : nStrMod;
 }
 else
 {
  switch(nBaseItemType)
  {
  case BASE_ITEM_HEAVYCROSSBOW:
  case BASE_ITEM_LIGHTCROSSBOW:
  case BASE_ITEM_SHURIKEN:
   if(!nMighty) //these three weapons do not have penalty for negative strenght
   {
   nMighty = -1;
   }
  }
  if(nMighty > -1)
  {
  c.Base+= (nStrMod > nMighty ? nMighty : nStrMod);
  }
 }
//specialization handling
c.Base+= GetHasFeat(StringToInt(Get2DAString("weaponfeats","WS",nBaseItemType)),oAttacker) ? 2 : 0;
c.Base+= GetHasFeat(StringToInt(Get2DAString("weaponfeats","EWS",nBaseItemType)),oAttacker) ? 4 : 0;

 for(nFirst=261;nFirst < 282;nFirst++)
 {//ranger bonuses handling
  if(nFirst-261 == GetRacialType(oVersus))
  {
   if(GetHasFeat(nFirst,oAttacker))
   {
   c.Base+= 1+GetLevelByclass(class_TYPE_RANGER,oAttacker)/5;
   }
   if(GetHasFeat(FEAT_EPIC_BANE_OF_ENEMIES,oAttacker))
   {
   c.Base+= d6(2);
   c.AB+= 2;
   }
  break;
  }
 }
DebugInt("Bypass",c.Bypass);
DebugString("Magical",Get2DAString("iprp_damagecost","Label",c.Magical));
DebugString("Fire",Get2DAString("iprp_damagecost","Label",c.Fire));
DebugString("Acid",Get2DAString("iprp_damagecost","Label",c.Acid));
DebugString("Cold",Get2DAString("iprp_damagecost","Label",c.Cold));
DebugString("Sonic",Get2DAString("iprp_damagecost","Label",c.Sonic));
DebugString("Electrical",Get2DAString("iprp_damagecost","Label",c.Electrical));
DebugString("Slashing",Get2DAString("iprp_damagecost","Label",c.Slashing));
DebugString("Bludgeoning",Get2DAString("iprp_damagecost","Label",c.Bludgeoning));
DebugString("Piercing",Get2DAString("iprp_damagecost","Label",c.Piercing));
DebugInt("AB (only base)",c.AB);
DebugString("Massive",Get2DAString("iprp_damagecost","Label",c.Massive));
DebugString("Overwhelming",IntToString(c.Overwhelming)+"d6");
DebugInt("CriticalThreat",c.CriticalThreat);
DebugInt("CriticalMultiplier",c.CriticalMultiplier);
DebugString("Sneak d6",IntToString(c.Sneak)+"d6");
c.Piercing = IPToDMGBonus(c.Piercing);
c.Slashing = IPToDMGBonus(c.Slashing);
c.Bludgeoning = IPToDMGBonus(c.Bludgeoning);
c.Magical = IPToDMGBonus(c.Magical);
c.Acid = IPToDMGBonus(c.Acid);
c.Cold = IPToDMGBonus(c.Cold);
c.Electrical = IPToDMGBonus(c.Electrical);
c.Sonic = IPToDMGBonus(c.Sonic);
c.Divine = IPToDMGBonus(c.Divine);
c.Positive = IPToDMGBonus(c.Positive);
c.Negative = IPToDMGBonus(c.Negative);
c.Massive = IPToDMGBonus(c.Massive);
 if(c.Overwhelming)
 {
 c.Overwhelming = d6(c.Overwhelming);
 }
DebugInt("Bypass",c.Bypass);
DebugString("BaseDamage",IntToString(c.Base));
DebugString("Magical",Get2DAString("iprp_damagecost","Label",c.Magical));
DebugString("Fire",Get2DAString("iprp_damagecost","Label",c.Fire));
DebugString("Acid",Get2DAString("iprp_damagecost","Label",c.Acid));
DebugString("Cold",Get2DAString("iprp_damagecost","Label",c.Cold));
DebugString("Sonic",Get2DAString("iprp_damagecost","Label",c.Sonic));
DebugString("Electrical",Get2DAString("iprp_damagecost","Label",c.Electrical));
DebugString("Slashing",Get2DAString("iprp_damagecost","Label",c.Slashing));
DebugString("Bludgeoning",Get2DAString("iprp_damagecost","Label",c.Bludgeoning));
DebugString("Piercing",Get2DAString("iprp_damagecost","Label",c.Piercing));
DebugInt("AB (only base)",c.AB);
DebugString("Massive",Get2DAString("iprp_damagecost","Label",c.Massive));
DebugString("Overwhelming",IntToString(c.Overwhelming)+"d6");
DebugInt("CriticalThreat",c.CriticalThreat);
DebugInt("CriticalMultiplier",c.CriticalMultiplier);
DebugString("Sneak d6",IntToString(c.Sneak)+"d6");

int nABCap = c.Bypass;
effect e = GetFirstEffect(oAttacker);
object oCreator;
//TODO
int favor, prayer, bardsong, aid, cursesong, bless, might, torm;
 while(GetIsEffectValid(e))
 {
 oCreator = GetEffectCreator(e);
  switch(GetEffectSpellId(e))
  {
  case SPELL_DIVINE_FAVOR://fortunately this effect can be present only once
  nFirst = GetCasterLevel(oCreator);
  nSecond = nFirst > 14 ? 5 : nFirst/3;
   if(favor < nSecond)
   {
   favor = nSecond;
   }
  break;
  case SPELL_PRAYER:
  prayer = 1;
  break;
  case SPELL_AID:
  aid = 1;
  break;
  case SPELL_BLESS:
  bless = 1;
  break;
  case SPELL_DIVINE_MIGHT:
  might = GetAbilityModifier(ABILITY_CHARISMA,oAttacker);
  break;
  case FEAT_DIVINE_WRATH:
  //torm = ?;TODO
  break;
  }
 e = GetNextEffect(oAttacker);
 }
/*struct damage_type d = WeaponDamageType(oWeapon);
  if(d.type2 > -1)
  {
  int bOdd = (nHextorDMG/2)*2 != nHextorDMG;
  nHextorDMG = nHextorDMG/2;
  bOdd = bOdd ? nHextorDMG+1 : nHextorDMG;
   switch(d.type2)
   {
   case 0:
   nBludgeoning+= bOdd;
   break;
   case 1:
   nPiercing+= bOdd;
   break;
   case 2:
   nSlashing+= bOdd;
   break;
   }
  }
  switch(d.type1)
  {
  case 0:
  nBludgeoning+= nHextorDMG;
  break;
  case 1:
  nPiercing+= nHextorDMG;
  break;
  case 2:
  nSlashing+= nHextorDMG;
  break;
  }   */
return c;
}


               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #23 on: December 06, 2011, 10:04:43 pm »


               Thanks for the continued input you all.

ShaDoOoW wrote...

BTW physical damage doesn't have to be categorized since the game engine changes its type to the weapon damage type right?

Also there is warcry, prayer, bard song, pdk feats and war domain... practically impossible to get this done correctly without NWNX. With NWNX it should be easy as NWNX has GetEffectInteger function.

But anyway, had the divine favor and might applied for all arrows with also all arrow property seems very inbalanced to me. And keep in mind that I am admin of epic loot/action module. On my server, imbue arrow is still very powerfull, death arrow is useable even with DC 20, hail can be used to exploit spawn systems, only seeker is somewhat useless.


Just to give you a frame of referance Shadooow, a lvl 200 FTR/WM with one of the top end great axes, does about 4-6k dmg on a crit. By comparison a similarially leveled and equiped AA does decent dmg on regular/critical hits, Imbue is really nice, and death arrow is also quite nice, however with hail and seeker they are doing about 150 and 250 dmg respectively for these abilities. The abilities also sacrifice all other actions for that round I believe. So as you can see they are pretty useless by comparison.

You do make a good point though about hail. There are 20-30 maps in the mod (of over 1000+) that use sparky spawns, and in these areas hail is a bit exploitable (also since it recharges, and isn't just a flat 5x/rest.) It doesn't do much dmg, but when hitting 100 targets at once, obviously that's a different story. Fortunately these areas are few compared to all the areas in the mod, but they are quite popolar ones. But for this reason it might be good to only marginally increase hail (If at all), but substantially increase seeker.

Edit: P.S. we do use nwnx.
               
               

               


                     Modifié par Lazarus Magni, 06 décembre 2011 - 10:05 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #24 on: December 06, 2011, 10:07:55 pm »


               

WhiZard wrote...

Here is a basic start to getting damage increase effects if the calculation behind them is already known. (e.g. if someone has divine might, then the bonus from divine might is known to be the charisma modifier). Sometimes I am giving benefit of doubt (like higher cleric/paladin level for getting divine favor bonus).


struct damage_struct
{
int nMagical, nDivine, nPiercing, nSlashing, nBludgeoning, nNegative, nPositive;
int nFire, nCold, nAcid, nElectrical, nSonic;
};


//Gets various values for damage increase effects
struct damage_struct BonusDamage(object oAttacker = OBJECT_SELF);
//Gets the larger of two numbers
int GetHigher(int n1, int n2);

int GetHigher(int n1, int n2)
{
if(n1 > n2)
return n1;
return n2;
}

struct damage_struct BonusDamage(object oAttacker = OBJECT_SELF)
{
struct damage_struct stBonus;
//For divine might use current charisma modifier.
if(GetHasFeatEffect(FEAT_DIVINE_MIGHT))
stBonus.nDivine += GetAbilityModifier(ABILITY_CHARISMA, oAttacker);
//Divine Favor can only be cast on self, thus we can check, paladin/cleric class and give benefit of doubt, UMDers are stuck with default scroll caster level
if(GetHasSpellEffect(SPELL_DIVINE_FAVOR))
stBonus.nMagical += GetHigher(GetHigher(GetLevelByclass(class_TYPE_CLERIC, oAttacker), GetLevelByclass(class_TYPE_PALADIN, oAttacker)), 5)/3;
/*Here insert more spells/feats*/
return stBonus;
}

//This shows how to access struct values
void main()
{
struct damage_struct stDamage = BonusDamage();
int nMagicalDamage = stDamage.nMagical;
int nDivineDamage = stDamage.nDivine;
int nPiercingDamage = stDamage.nPiercing;
}


EDIT:Note that the above will note compile because this social forum always lowercases the word class.


This looks promising Whizard, but I am not exactly sure how to intergrate this into say the seeker script (or the include) to take into account the post 40 dmg?
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #25 on: December 06, 2011, 10:10:20 pm »


               Thanks for sharing the code Shadooow, but I am not sure what I would do with this? I will try to look it over in more depth though.

Quote
ShaDoOoW wrote...

Lazarus: you aksed for ideas, well my idea is to abadon this solution and rather choose a balance change that would work for you, its easier to implement and also easier to balance. For example on Antiworld, physical damage is added to magical which works for them very well and makes from AAs mage killers.

BTW I tried to implement something similar in past for fake attacks with any weapon, but I never implemented it and because of new NWNX features in past year I also abadoned this solution.

However maybe my old code could be some of use to you, so there is it:
Quote
               
               

               


                     Modifié par Lazarus Magni, 06 décembre 2011 - 10:11 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Improving AA abilities
« Reply #26 on: December 06, 2011, 10:58:52 pm »


               What would you do? Probably reuse some knowhow that is there and you missed it like massive damage, ranger favored enemy etc. at least if you are still going this route.

To implement post 40 bonus into  AA arrows is easy, try this:

int Post40DMGBonusForAA(object oPC)
{
 // Modifier introduced for barbarian rage
 float fBonusMod = GetLocalFloat(oPC, "core_post_modifier");
 int nXP = GetXP( oPC );
 int nLevel = pf_GetLevelFromXP( nXP );
 if ( nLevel < 40 )
 {
return 0;
}
   int nStrMod = GetAbilityModifier( ABILITY_STRENGTH, oPC );
   
   int nPost = ( nLevel - 40 );
   int nPureBonus = 0;
   int nRequiredXP = ((( nLevel * ( nLevel + 1 )) / 2 ) * 1000 );
   float fMeleeFactor = calcMeleeFactor( oPC );

   if ( fMeleeFactor == 1.0 )
   {
     nPureBonus = nPost/8;
   }
   fMeleeFactor += fBonusMod;

   int nAB = FloatToInt( IntToFloat( nPost )/ 2.0 * fMeleeFactor );

   if ( GetIsObjectValid( GetItemPossessedBy( oPC, "GrtrMeleeRunV2" )))
   {
     fMeleeFactor *= 1.0 + (0.5);
}
   else if ( GetIsObjectValid( GetItemPossessedBy( oPC, "LesrMeleeRunV2" )))
   {
     fMeleeFactor *= 1.0 + (0.25);
   }

   int nBonus = FloatToInt( IntToFloat( nPost ) / 2.0 * fMeleeFactor ) + nPureBonus;
   return nBonus;
   }


and then add the value of
int post40dmg = Post40DMGBonusForAA(oPC);
into AA arrow damage calculation as a piercing for example.
               
               

               


                     Modifié par ShaDoOoW, 06 décembre 2011 - 11:01 .
                     
                  


            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Improving AA abilities
« Reply #27 on: December 06, 2011, 11:45:00 pm »


               Ahh that's cool, thank you shadooow, I will look into this.