Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
575 lines
25 KiB
Plaintext
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;
|
|
}
|