PRC8/nwn/nwnprc/trunk/include/prc_inc_unarmed.nss
Jaysyn904 0f43e5cbd2 2025-04-15 Update
Added Elven blades to Weaponmaster prereqs
Fixed Beckon the Frozen
Fixed bug with Fire Brand
Fixed duration bug with Improved Invisibility
Added Soul Eater to Shifter prereqs
Fixed ability based class prereqs in prc_prereq.nss
Update Eye of Gruumsh for epic levels
Update Ur-Priest for epic levels
Update Forsaker for epic levels
Update Anima Mage for epic levels
Update Serene Guardian for epic levels
Bladesinger abilities can use chain shirts
Fixed Elemental Abjuration
Fixed bug with prc cache creature.
Forsakers can use non-magic items (heal kits, alchemy, etc)
Updated ruleset.2da for NWNEE update
Updated AotS bonus feats

-Notes
Added 3.5e Template index
Added 3.5e update booklet

Removed release archive
2025-04-15 18:10:14 -04:00

575 lines
25 KiB
Plaintext

//:://////////////////////////////////////////////
//:: Unarmed evaluation include
//:: prc_inc_unarmed
//:://////////////////////////////////////////////
/*
Handles attack bonus, damage and itemproperties
for creature weapons created based on class
and race abilities.
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Constant declarations */
//////////////////////////////////////////////////
const int ITEM_PROPERTY_WOUNDING = 69;
const string CALL_UNARMED_FEATS = "CALL_UNARMED_FEATS";
const string CALL_UNARMED_FISTS = "CALL_UNARMED_FISTS";
const string UNARMED_CALLBACK = "UNARMED_CALLBACK";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
// Determines the amount of unarmed damage a character can do
// ==========================================================
// oCreature a creature whose unarmed damage dice are
// being evaluated
//
// Returns one of the IP_CONST_MONSTERDAMAGE_* constants
int FindUnarmedDamage(object oCreature);
// Adds appropriate unarmed feats to the skin. Goes with UnarmedFists()
// ====================================================================
// oCreature a creature whose unarmed combat feats to handle
//
// Do not call this directly from your evaluation script. Instead, set
// the local variable CALL_UNARMED_FEATS on the creature to TRUE.
// This is done to avoid bugs from redundant calls to these functions.
void UnarmedFeats(object oCreature);
// Creates/strips a creature weapon and applies bonuses. Goes with UnarmedFeats()
// ==============================================================================
// oCreature a creature whose creature weapon to handle
//
// Do not call this directly from your evaluation script. Instead, set
// the local variable CALL_UNARMED_FISTS on the creature to TRUE.
// This is done to avoid bugs from redundant calls to these functions.
//
// If you are going to add properties to the creature weapons, hook
// your script for callback after this is evaluated by calling
// AddEventScript(oPC, CALLBACKHOOK_UNARMED, "your_script", FALSE, FALSE);
// When the callback is running, a local int UNARMED_CALLBACK will be
// set on OBJECT_SELF
void UnarmedFists(object oCreature);
/**
* Determines whether the given object is one of the PRC creature weapons based
* on it's resref and tag. Resref is tested first, then tag.
*
* @param oTest Object to test
* @return TRUE if the object is a PRC creature weapon, FALSE otherwise
*/
int GetIsPRCCreatureWeapon(object oTest);
/**
* Determines the average damage of a IP_CONST_MONSTERDAMAGE_*** constant.
* Used to compare different unarmed damages.
*
* @param iDamage IP_CONST_MONSTERDAMAGE_*** constant
* @return average damage of that constant
*/
float DamageAvg(int iDamage);
//#include "prc_alterations"
//#include "pnp_shft_poly"
//#include "prc_feat_const"
//#include "prc_ipfeat_const"
//#include "prc_class_const"
//#include "prc_racial_const"
//#include "prc_spell_const"
//#include "inc_utility"
#include "prc_inc_natweap"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
// Clean up any extras in the inventory.
void CleanExtraFists(object oCreature)
{
int nItemType;
object oItem = GetFirstItemInInventory(oCreature);
object oCWPB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oCreature);
object oCWPL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature);
object oCWPR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oCreature);
object oCSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oCreature);
while(GetIsObjectValid(oItem))
{
nItemType = GetBaseItemType(oItem);
if(nItemType == BASE_ITEM_CBLUDGWEAPON ||
nItemType == BASE_ITEM_CPIERCWEAPON ||
nItemType == BASE_ITEM_CREATUREITEM ||
nItemType == BASE_ITEM_CSLASHWEAPON ||
nItemType == BASE_ITEM_CSLSHPRCWEAP
)
{
if(oItem != oCWPB &&
oItem != oCWPL &&
oItem != oCWPR &&
oItem != oCSkin
)
MyDestroyObject(oItem);
}
oItem = GetNextItemInInventory(oCreature);
}
}
int GetIsPRCCreatureWeapon(object oTest)
{
string sTest = GetStringUpperCase(GetResRef(oTest));
return // First, test ResRef
sTest == "PRC_UNARMED_B" ||
sTest == "PRC_UNARMED_S" ||
sTest == "PRC_UNARMED_P" ||
sTest == "PRC_UNARMED_SP" ||
sTest == "NW_IT_CREWPB010" || // Legacy item, should not be used anymore
// If resref doesn't match, try tag
(sTest = GetStringUpperCase(GetTag(oTest))) == "PRC_UNARMED_B" ||
sTest == "PRC_UNARMED_S" ||
sTest == "PRC_UNARMED_P" ||
sTest == "PRC_UNARMED_SP" ||
sTest == "NW_IT_CREWPB010"
;
}
// Remove the unarmed penalty effect
void RemoveUnarmedAttackEffects(object oCreature)
{
effect e = GetFirstEffect(oCreature);
while (GetIsEffectValid(e))
{
if (GetEffectSpellId(e) == SPELL_UNARMED_ATTACK_PEN)
RemoveEffect(oCreature, e);
e = GetNextEffect(oCreature);
}
}
// Add the unarmed penalty effect -- the DR piercing property gives an unwanted
// attack bonus. This clears it up.
void ApplyUnarmedAttackEffects(object oCreature)
{
object oCastingObject = CreateObject(OBJECT_TYPE_PLACEABLE, "x0_rodwonder", GetLocation(OBJECT_SELF));
AssignCommand(oCastingObject, ActionCastSpellAtObject(SPELL_UNARMED_ATTACK_PEN, oCreature, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
DestroyObject(oCastingObject, 6.0);
}
// Determines the amount of damage a character can do.
// IoDM: +1 dice at level 4, +2 dice at level 8
// Sacred Fist: Levels add to monk levels, or stand alone as monk levels.
// Shou: 1d6 at level 1, 1d8 at level 2, 1d10 at level 3, 2d6 at level 5
// Monk: 1d6 at level 1, 1d8 at level 4, 1d10 at level 8, 2d6 at level 12, 2d8 at level 16, 2d10 at level 20
// Frostrager: 1d6 at level 1, 1d8 at level 4
int FindUnarmedDamage(object oCreature)
{
int iDamage = 0;
int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk");
int iShou = GetLevelByClass(CLASS_TYPE_SHOU, oCreature);
int iBrawler = GetLevelByClass(CLASS_TYPE_BRAWLER, oCreature);
int iSacredFist = GetLevelByClass(CLASS_TYPE_SACREDFIST, oCreature);
int iEnlightenedFist = GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCreature);
int iHenshin = GetLevelByClass(CLASS_TYPE_HENSHIN_MYSTIC, oCreature);
int iZuoken = GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature);
int iShadowSunNinja = GetLevelByClass(CLASS_TYPE_SHADOW_SUN_NINJA, oCreature);
int iFrost = GetLevelByClass(CLASS_TYPE_FROSTRAGER, oCreature);
int iAscetic = GetLevelByClass(CLASS_TYPE_NINJA, oCreature);
int iRonove;
int iMonkDamage = 1;
int iShouDamage = 1;
int iBrawlerDamage = 1;
int iFrostDamage = 1;
int iSUSDamage = 1;
int iDieIncrease = 0;
int iSize;
if (GetHasSpellEffect(VESTIGE_RONOVE, oCreature) && GetLevelByClass(CLASS_TYPE_BINDER, oCreature)) iRonove = GetLocalInt(oCreature, "RonovesFists");
// if the creature is shifted, use model size
// otherwise, we want to stick to what the feats say they "should" be.
// No making pixies with Dragon Appearance for "huge" fist damage.
if( GetIsPolyMorphedOrShifted(oCreature)
|| GetPRCSwitch(PRC_APPEARANCE_SIZE))
{
iSize = PRCGetCreatureSize(oCreature) - CREATURE_SIZE_MEDIUM + 5; // medium is size 5 for us
}
else
{
// Determine creature size by feats.
iSize = 5; // medium is size 5 for us
if (GetHasFeat(FEAT_TINY, oCreature)) iSize = 3;
if (GetHasFeat(FEAT_SMALL, oCreature)) iSize = 4;
if (GetHasFeat(FEAT_LARGE, oCreature)) iSize = 6;
if (GetHasFeat(FEAT_HUGE, oCreature)) iSize = 7;
// include size changes
iSize += PRCGetCreatureSize(oCreature) - PRCGetCreatureSize(oCreature, PRC_SIZEMASK_NONE);
// cap if needed
if (iSize < 1) iSize = 1;
if (iSize > 9) iSize = 9;
}
// Sacred Fist cannot add their levels if they've broken their code.
if (GetHasFeat(FEAT_SF_CODE, oCreature)) iSacredFist = 0;
// several classes add their levels to the monk class,
// or use monk progression if the character has no monk levels
iMonk += iSacredFist + iHenshin + iEnlightenedFist + iShou + iZuoken + iShadowSunNinja;
// Superior Unarmed Strike
if (GetHasFeat(FEAT_SUPERIOR_UNARMED_STRIKE, oCreature))
{
iMonk += 4;
int nHD = GetHitDice(oCreature);
if (nHD >= 16) iSUSDamage = IP_CONST_MONSTERDAMAGE_2d6;
else if (nHD >= 12) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d10;
else if (nHD >= 8) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d8;
else if (nHD >= 4) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d6;
else if (nHD >= 3) iSUSDamage = IP_CONST_MONSTERDAMAGE_1d4;
}
// Ascetic Stalker
if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature))
iMonk += iAscetic;
// In 3.0e, Monk progression stops after level 16:
if (iMonk > 16 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE) ) iMonk = 16;
// in 3.5e, monk progression stops at 20.
else if(iMonk > 20) iMonk = 20;
// Ronove is in place of monk, does not stack
if (iRonove > iMonk) iMonk = iRonove;
// monks damage progesses every four levels, starts at 1d6
if (iMonk > 0)
iMonkDamage = iMonk / 4 + 3;
// For medium monks in 3.0e skip 2d8 and go to 1d20
if(iSize == 5 && iMonkDamage == 7 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE) ) iMonkDamage = 8;
// Shou Disciple either adds its level to existing class or does its own damage, depending
// on which is better. Here we will determine how much damage the Shou Disciple does
// without stacking.
if (iShou > 0) iShouDamage = iShou + 2; // Lv. 1: 1d6, Lv. 2: 1d8, Lv. 3: 1d10
if (iShou > 3) iShouDamage--; // Lv. 4: 1d10, Lv. 5: 2d6
// Frostrager does not stack with other damage types
if (iFrost > 0) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d6; // Lv. 1: 1d6
if (iFrost > 3) iFrostDamage = IP_CONST_MONSTERDAMAGE_1d8; // Lv. 3: 1d8
// Brawler follows monk progression except for the last one (3d8)
if (iBrawler > 0) iBrawlerDamage = iBrawler / 6 + 3; // 1d6, 1d8, 1d10, 2d6, 2d8, 2d10
if (iBrawler >= 36) iBrawlerDamage += 2; // 3d8
// Monks and monk-like classes deal no additional damage when wearing any armor, at
// least in NWN. This is to reflect that. No shields too.
if (iMonkDamage > 1)
{
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature);
object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD ||
GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD ||
GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD;
if (GetBaseAC(oArmor) > 0 || bShieldEq)
{
iMonkDamage = 1;
}
}
// Shou Disciples can wear light armor
if (iShouDamage > 1)
{
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature);
object oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
int bShieldEq = GetBaseItemType(oShield) == BASE_ITEM_SMALLSHIELD ||
GetBaseItemType(oShield) == BASE_ITEM_LARGESHIELD ||
GetBaseItemType(oShield) == BASE_ITEM_TOWERSHIELD;
if (GetBaseAC(oArmor) > 3 || bShieldEq)
{
iShouDamage = 1;
}
}
// For Initiate of Draconic Mysteries
if (GetHasFeat(FEAT_INCREASE_DAMAGE2, oCreature)) iDieIncrease = 2;
else if (GetHasFeat(FEAT_INCREASE_DAMAGE1, oCreature)) iDieIncrease = 1;
iMonkDamage += iDieIncrease;
iShouDamage += iDieIncrease;
iBrawlerDamage += iDieIncrease;
iFrostDamage += iDieIncrease;
iSUSDamage += iDieIncrease;
// now, read the damage from the table in unarmed_dmg.2da
iMonkDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iMonkDamage));
iShouDamage = StringToInt(Get2DACache("unarmed_dmg","size" + IntToString(iSize), iShouDamage));
// Medium+ monks have some special values on the table in 3.0:
if (iSize >= 5 && !GetPRCSwitch(PRC_3_5e_FIST_DAMAGE))
{
if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d6) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d12;
if (iMonkDamage == IP_CONST_MONSTERDAMAGE_2d10) iMonkDamage = IP_CONST_MONSTERDAMAGE_1d20;
}
iDamage = iMonkDamage;
// Future unarmed classes: if you do your own damage, add in "comparisons" below here.
iDamage = (DamageAvg(iShouDamage ) > DamageAvg(iDamage)) ? iShouDamage : iDamage;
iDamage = (DamageAvg(iFrostDamage ) > DamageAvg(iDamage)) ? iFrostDamage : iDamage;
iDamage = (DamageAvg(iSUSDamage ) > DamageAvg(iDamage)) ? iSUSDamage : iDamage;
if (DEBUG) DoDebug("prc_inc_unarmed: iDamage "+IntToString(iDamage));
return iDamage;
}
// Adds appropriate feats to the skin. Stolen from SoulTaker + expanded with overwhelming/devastating critical.
void UnarmedFeats(object oCreature)
{
// If we are polymorphed/shifted, do not mess with the creature weapon.
if (GetIsPolyMorphedOrShifted(oCreature)) return;
object oSkin = GetPCSkin(oCreature);
if (!GetHasFeat(FEAT_WEAPON_PROFICIENCY_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WEAPON_PROF_CREATURE),oSkin);
//only roll unarmed feats into creature feats when not using natural weapons
if(!GetIsUsingPrimaryNaturalWeapons(oCreature))
{
if (GetHasFeat(FEAT_WEAPON_FOCUS_UNARMED_STRIKE, oCreature) && !GetHasFeat(FEAT_WEAPON_FOCUS_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature),oSkin);
if (GetHasFeat(FEAT_WEAPON_SPECIALIZATION_UNARMED_STRIKE, oCreature) && !GetHasFeat(FEAT_WEAPON_SPECIALIZATION_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapSpecCreature),oSkin);
if (GetHasFeat(FEAT_IMPROVED_CRITICAL_UNARMED_STRIKE, oCreature) && !GetHasFeat(FEAT_IMPROVED_CRITICAL_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_ImpCritCreature),oSkin);
if (GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_UNARMED, oCreature) && !GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapEpicFocCreature),oSkin);
if (GetHasFeat(FEAT_EPIC_WEAPON_SPECIALIZATION_UNARMED, oCreature) && !GetHasFeat(FEAT_EPIC_WEAPON_SPECIALIZATION_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapEpicSpecCreature),oSkin);
if (GetHasFeat(FEAT_EPIC_OVERWHELMING_CRITICAL_UNARMED, oCreature) && !GetHasFeat(FEAT_EPIC_OVERWHELMING_CRITICAL_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_OVERCRITICAL_CREATURE),oSkin);
if (GetHasFeat(FEAT_EPIC_DEVASTATING_CRITICAL_UNARMED, oCreature) && !GetHasFeat(FEAT_EPIC_DEVASTATING_CRITICAL_CREATURE, oCreature))
AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_DEVCRITICAL_CREATURE),oSkin);
}
}
// Creates/strips a creature weapon and applies bonuses. Large chunks stolen from SoulTaker.
void UnarmedFists(object oCreature)
{
// If we are polymorphed/shifted, do not mess with the creature weapon.
if (GetIsPolyMorphedOrShifted(oCreature)) return;
RemoveUnarmedAttackEffects(oCreature);
object oRighthand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCreature);
object oLefthand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oCreature);
object oWeapL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oCreature);
// Clean up the mess of extra fists made on taking first level.
DelayCommand(6.0f, CleanExtraFists(oCreature));
// Determine the character's capacity to pierce DR.
// only applies when not using natural weapons
if(!GetIsUsingPrimaryNaturalWeapons(oCreature))
{
int iRace = GetRacialType(oCreature);
int iMonk = GetLevelByClass(CLASS_TYPE_MONK, oCreature) + GetLocalInt(oCreature, "LiPengMonk");
int iShou = GetLevelByClass(CLASS_TYPE_SHOU, oCreature);
int iSacFist = GetLevelByClass(CLASS_TYPE_SACREDFIST, oCreature);
int iHenshin = GetLevelByClass(CLASS_TYPE_HENSHIN_MYSTIC, oCreature);
int iIoDM = GetLevelByClass(CLASS_TYPE_INITIATE_DRACONIC, oCreature);
int iBrawler = GetLevelByClass(CLASS_TYPE_BRAWLER, oCreature);
int iZuoken = GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature);
int iShadowSunNinja = GetLevelByClass(CLASS_TYPE_SHADOW_SUN_NINJA, oCreature);
int iAscetic = GetLevelByClass(CLASS_TYPE_NINJA, oCreature);
// Sacred Fists who break their code get no benefits.
if (GetHasFeat(FEAT_SF_CODE,oCreature)) iSacFist = 0;
// The monk adds all these classes.
int iMonkEq = iMonk + iShou + iSacFist + iHenshin + iZuoken + iShadowSunNinja;
// Ascetic Stalker
if (GetHasFeat(FEAT_ASCETIC_STALKER, oCreature))
iMonkEq += iAscetic;
// Determine the type of damage the character should do.
string sWeapType;
if (GetHasFeat(FEAT_CLAWDRAGON, oCreature))
sWeapType = "PRC_UNARMED_S";
else
sWeapType = "PRC_UNARMED_B";
// Equip the creature weapon.
if (!GetIsObjectValid(oWeapL) || GetTag(oWeapL) != sWeapType)
{
if (GetHasItem(oCreature, sWeapType))
{
oWeapL = GetItemPossessedBy(oCreature, sWeapType);
SetIdentified(oWeapL, TRUE);
AssignCommand(oCreature, ActionEquipItem(oWeapL, INVENTORY_SLOT_CWEAPON_L));
}
else
{
oWeapL = CreateItemOnObject(sWeapType, oCreature);
SetIdentified(oWeapL, TRUE);
AssignCommand(oCreature,ActionEquipItem(oWeapL, INVENTORY_SLOT_CWEAPON_L));
}
}
int iKi = (iMonkEq > 9) ? 1 : 0;
iKi = (iMonkEq > 12) ? 2 : iKi;
iKi = (iMonkEq > 15) ? 3 : iKi;
int iDragClaw = GetHasFeat(FEAT_CLAWDRAGON,oCreature) ? 1: 0;
iDragClaw = GetHasFeat(FEAT_CLAWENH2,oCreature) ? 2: iDragClaw;
iDragClaw = GetHasFeat(FEAT_CLAWENH3,oCreature) ? 3: iDragClaw;
int iBrawlEnh = iBrawler / 6;
int iEpicKi = GetHasFeat(FEAT_EPIC_IMPROVED_KI_STRIKE_4,oCreature) ? 1 : 0 ;
iEpicKi = GetHasFeat(FEAT_EPIC_IMPROVED_KI_STRIKE_5,oCreature) ? 2 : iEpicKi ;
// The total enhancement to the fist is the sum of all the enhancements above
int iEnh = iKi + iDragClaw + iBrawlEnh + iEpicKi;
// Strip the Fist.
itemproperty ip = GetFirstItemProperty(oWeapL);
while (GetIsItemPropertyValid(ip))
{
RemoveItemProperty(oWeapL, ip);
ip = GetNextItemProperty(oWeapL);
}
// Leave the fist blank if weapons are equipped. The only way a weapon will
// be equipped on the left hand is if there is a weapon in the right hand.
if (GetIsObjectValid(oRighthand)) return;
// Add glove bonuses.
object oItem = GetItemInSlot(INVENTORY_SLOT_ARMS,oCreature);
int iGloveEnh = 0;
if (GetIsObjectValid(oItem))
{
int iType = GetBaseItemType(oItem);
if (iType == BASE_ITEM_GLOVES)
{
ip = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ip))
{
iType = GetItemPropertyType(ip);
switch (iType)
{
case ITEM_PROPERTY_DAMAGE_BONUS:
case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
case ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP:
case ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT:
case ITEM_PROPERTY_ON_HIT_PROPERTIES:
case ITEM_PROPERTY_ONHITCASTSPELL:
case ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE:
case ITEM_PROPERTY_KEEN:
case ITEM_PROPERTY_MASSIVE_CRITICALS:
case ITEM_PROPERTY_POISON:
case ITEM_PROPERTY_REGENERATION_VAMPIRIC:
case ITEM_PROPERTY_WOUNDING:
case ITEM_PROPERTY_DECREASED_DAMAGE:
case ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER:
DelayCommand(0.1, AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapL));
break;
case ITEM_PROPERTY_ATTACK_BONUS:
int iCost = GetItemPropertyCostTableValue(ip);
iGloveEnh = (iCost>iGloveEnh) ? iCost:iGloveEnh;
iEnh = (iCost>iEnh) ? iCost:iEnh;
break;
}
ip = GetNextItemProperty(oItem);
}
// handles these seperately so as not to create "attack penalties vs. xxxx"
ip = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ip))
{
iType = GetItemPropertyType(ip);
switch (iType)
{
case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT:
case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP:
if (GetItemPropertyCostTableValue(ip) > iEnh)
DelayCommand(0.1, AddItemProperty(DURATION_TYPE_PERMANENT,ip,oWeapL));
break;
}
ip = GetNextItemProperty(oItem);
}
}
}
// Add damage resistance penetration.
DelayCommand(0.1, AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyAttackBonus(iEnh), oWeapL));
// Cool VFX when striking unarmed
if (iMonkEq > 9)
//DelayCommand(0.1, AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(IP_CONST_FEAT_KI_STRIKE), oWeapL));
DelayCommand(0.1, IPSafeAddItemProperty(oWeapL, PRCItemPropertyBonusFeat(IP_CONST_FEAT_KI_STRIKE), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE));
// This adds creature weapon finesse and a penalty to offset the DR penetration attack bonus.
SetLocalInt(oCreature, "UnarmedEnhancement", iEnh);
SetLocalInt(oCreature, "UnarmedEnhancementGlove", iGloveEnh);
}
// Weapon finesse or intuitive attack?
SetLocalInt(oCreature, "UsingCreature", TRUE);
ExecuteScript("prc_intuiatk", oCreature);
DelayCommand(1.0f, DeleteLocalInt(oCreature, "UsingCreature"));
ApplyUnarmedAttackEffects(oCreature);
// Add the appropriate damage to the fist.
int iMonsterDamage = FindUnarmedDamage(oCreature);
AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyMonsterDamage(iMonsterDamage),oWeapL);
// Add OnHitCast: Unique if necessary. Frostrager level 5 grants Rend too
if(GetHasFeat(FEAT_REND, oCreature) || GetLevelByClass(CLASS_TYPE_FROSTRAGER, oCreature) > 4)
IPSafeAddItemProperty(oWeapL,
ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1));
// Friendly message to remind players that certain things won't appear correct.
if (GetLocalInt(oCreature, "UnarmedSubSystemMessage") != TRUE
&& GetHasSpellEffect(SPELL_UNARMED_ATTACK_PEN, oCreature))
{
SetLocalInt(oCreature, "UnarmedSubSystemMessage", TRUE);
DelayCommand(3.001f, SendMessageToPC(oCreature, "This character uses the PRC's unarmed system. This system has been created to"));
DelayCommand(3.002f, SendMessageToPC(oCreature, "work around many Aurora engine bugs and limitations. Your attack roll may appear to be"));
DelayCommand(3.003f, SendMessageToPC(oCreature, "incorrect on the character's stats. However, the attack rolls should be correct in"));
DelayCommand(3.004f, SendMessageToPC(oCreature, "combat. Disregard any attack effects that seem extra: they are part of the workaround."));
DelayCommand(600.0f, DeleteLocalInt(oCreature, "UnarmedSubSystemMessage"));
}
}
float DamageAvg(int iDamage)
{
int iDie = StringToInt(Get2DACache("iprp_monstcost", "Die", iDamage));
int iNum = StringToInt(Get2DACache("iprp_monstcost", "NumDice", iDamage));
return IntToFloat(iNum * (iDie+1)) / 2;
}