Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
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;
|
|
}
|