Alaster Wolf wrote...
So, when PC attacks someone the blow is countered by the armor/shield that wears down and the damage above the resistance of the armor/shield is done to a specific body part (limbs, torso, head). Damage to the body parts will either be minor (ignored), extensive (bleeding) or severe (for example - the victim loses their left arm and drops the shield).
Here is an include file (won't run by itself and requires other includes that I created) which shows a lot of the circumstances I was factoring in when working on my system.
#include "dd_inc_craft"
// Returns the material element of the item
// Returns 0 if item is not elemental
int GetElement(object oItem);
// Gets the highest attack bonus property value
int GetHighAB(object oItem);
// Gets the highest DR enhancement value
int GetHighDR(object oItem);
// Returns FALSE if armed with non-creature weapon
// Returns TRUE if fighting unarmed
int GetIsUnarmed(object oAttacker);
// This is the main combat function for the gradual ruining of items.
// Called Shot and Disarm feats adjust the affected items to be ruined.
// Fists without gloves cause the attacker to become stunned for a flurry.
void OnHitWeaponVsArmor(object oAttacker, object oDefender = OBJECT_SELF);
// Resets quality of item when it is damaged
void ResetQualityByDamage(object oItem, int nQuality, itemproperty ipCurrentQuality);
int GetElement(object oItem)
{
int nElement = 51; //For comparative reasons only
int nPossible = 0;
itemproperty ipElement = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipElement))
{
if(GetItemPropertyType(ipElement) == ITEM_PROPERTY_MATERIAL)
{
nPossible = GetItemPropertyParam1(ipElement);
if((nPossible > 45) && (nPossible < 51)) // Checks for element
{
if(nElement > nPossible) nElement = nPossible;
}
}
}
if(nElement != 51) return nElement;
else return 0;
}
int GetHighAB(object oItem)
{
int nAB = 0;
int nPossible = 0;
int nType = 0;
itemproperty ipAB = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipAB))
{
nType = GetItemPropertyType(ipAB);
if(nType == ITEM_PROPERTY_ATTACK_BONUS || nType == ITEM_PROPERTY_ENHANCEMENT_BONUS)
{
nPossible = GetItemPropertyParam1(ipAB);
if(nAB < nPossible) nAB = nPossible;
}
ipAB = GetNextItemProperty(oItem);
}
return nAB;
}
int GetHighDR(object oItem)
{
int nDR = 0;
int nPossible = 0;
itemproperty ipDR = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipDR))
{
if(GetItemPropertyType(ipDR) == ITEM_PROPERTY_DAMAGE_REDUCTION)
{
nPossible = GetItemPropertySubType(ipDR) + 1;
if(nDR < nPossible) nDR = nPossible;
}
ipDR = GetNextItemProperty(oItem);
}
return nDR;
}
int GetIsUnarmed(object oAttacker)
{
//Does not check for last use of throwing item
if(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oAttacker) == OBJECT_INVALID)
return TRUE;
return FALSE;
}
void OnHitWeaponVsArmor(object oAttacker, object oDefender = OBJECT_SELF)
{
//Plot Flag needed to take into account creatures like Black Blade of Disaster
int bAttackerPlot = GetPlotFlag(oAttacker);
int bDefenderPlot = GetPlotFlag(oDefender);
int nExtreme = (EXTREME_CHANCE - 1 + d100())/ 100; //20% chance of extreme hit
int nAttackType = GetLastAttackType(oAttacker);
object oAttackWeapon = GetLastWeaponUsed(oAttacker);
if(oAttackWeapon == OBJECT_INVALID)
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(), oAttacker, 2.0);
oAttackWeapon = GetItemInSlot(INVENTORY_SLOT_CARMOUR);
}
struct object_struct stAttackWeapon = SetObjectUsed(oAttackWeapon);
int nAType = stAttackWeapon.nType;
int bARanged = stAttackWeapon.bRanged;
object oDefendItem = OBJECT_INVALID;
int nDefendItemType = 0;
object oProjectile = OBJECT_INVALID;
//Throwing and projectile weapons are treated differently
if(bARanged)
{
if(nAType == BASE_ITEM_SHORTBOW || nAType == BASE_ITEM_LONGBOW)
oProjectile = GetItemInSlot(INVENTORY_SLOT_ARROWS);
else if (nAType == BASE_ITEM_LIGHTCROSSBOW || nAType == BASE_ITEM_HEAVYCROSSBOW)
oProjectile = GetItemInSlot(INVENTORY_SLOT_BOLTS);
else if (nAType == BASE_ITEM_SLING)
oProjectile = GetItemInSlot(INVENTORY_SLOT_BULLETS);
}
if(nAttackType == SPECIAL_ATTACK_DISARM || nAttackType == SPECIAL_ATTACK_IMPROVED_DISARM)
{
if(nExtreme == 1)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oDefender);
nDefendItemType = GetBaseItemType(oDefendItem);
if(nDefendItemType == BASE_ITEM_SMALLSHIELD || nDefendItemType == BASE_ITEM_LARGESHIELD || nDefendItemType == BASE_ITEM_TOWERSHIELD)
oDefendItem = OBJECT_INVALID;
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L);
if(oDefendItem == OBJECT_INVALID)
nExtreme = 0;
}
if(nExtreme == 0)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oDefender);
}
}
else if(nAttackType == SPECIAL_ATTACK_CALLED_SHOT_ARM)
{
if(nExtreme == 0)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oDefender);
if(oDefendItem == OBJECT_INVALID) nExtreme = 1;
}
if(nExtreme == 1)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_ARMS, oDefender);
if(GetBaseItemType(oDefendItem) == BASE_ITEM_GLOVES || oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oDefender);
}
}
else if(nAttackType == SPECIAL_ATTACK_CALLED_SHOT_LEG)
{
if(nExtreme == 0)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oDefender);
if(oDefendItem == OBJECT_INVALID) nExtreme = 1;
}
if(nExtreme == 1)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_BOOTS, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oDefender);
}
}
else
{
if(nExtreme == 0)
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oDefender);
nDefendItemType = GetBaseItemType(oDefendItem);
if(nDefendItemType != BASE_ITEM_SMALLSHIELD && nDefendItemType != BASE_ITEM_LARGESHIELD && nDefendItemType != BASE_ITEM_TOWERSHIELD)
oDefendItem = OBJECT_INVALID;
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oDefender);
}
else
{
oDefendItem = GetItemInSlot(INVENTORY_SLOT_HEAD, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oDefender);
if(oDefendItem == OBJECT_INVALID)
oDefendItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR);
}
}
struct object_struct stDefendItem = SetObjectUsed(oDefendItem);
int nAElemental = stAttackWeapon.nElemental;
int nDElemental = stDefendItem.nElemental;
int nAttackRoll = 0;
int bDamage = FALSE;
struct object_struct stProjectile = SetObjectUsed(oProjectile);
if(bAttackerPlot)
{
nAElemental = 46;
bDamage = TRUE;
}
if(bDefenderPlot)
{
nDElemental = 46;
bDamage = TRUE;
}
object oATorch = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oAttacker);
object oDTorch = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oDefender);
if(nAElemental == 47 && nDElemental == 48) bDamage = TRUE;
if(nAElemental == 48 && nDElemental == 47) bDamage = TRUE;
if(nAElemental == 49 && nDElemental == 50) bDamage = TRUE;
if(nAElemental == 50 && nDElemental == 49) bDamage = TRUE;
if(nAElemental == 0 && nDElemental == 0) bDamage = TRUE;
if(nAElemental != 49 && nAElemental != 46 && nDElemental == 50 && GetBaseItemType(oATorch) == BASE_ITEM_TORCH && bARanged == FALSE)
{
bDamage = TRUE;
stAttackWeapon = SetObjectUsed(oATorch);
}
else if(nAElemental == 50 && nDElemental != 49 && nDElemental != 46 && GetBaseItemType(oDTorch) == BASE_ITEM_TORCH)
{
bDamage = TRUE;
if(oDefendItem != oDTorch)
stDefendItem = SetObjectUsed(oDTorch);
}
oAttackWeapon = stAttackWeapon.oObject;
nAType = stAttackWeapon.nType;
int bRanged = stAttackWeapon.bRanged;
int nAMaterialValue = stAttackWeapon.nHMaterialValue;
int nAQualityValue = stAttackWeapon.nHQuality;
int nAttackElement = nAElemental;
itemproperty ipAQuality = stAttackWeapon.ipHQuality;
int nABValue = stAttackWeapon.nHABValue;
int nPMaterialValue = stProjectile.nHMaterialValue;
int nPQualityValue = stProjectile.nHQuality;
oDefendItem = stDefendItem.oObject;
int nDType = stDefendItem.nType;
int nDMaterialValue = stDefendItem.nHMaterialValue;
int nDQualityValue = stDefendItem.nHQuality;
int nDefendElement = nDElemental;
itemproperty ipDQuality = stDefendItem.ipHQuality;
int nDRValue = stDefendItem.nHDRValue;
int nMaterialValue, nQualityValue;
int nAttackItemPoints = GetLocalInt(oAttackWeapon, "ItemPoints");
int nDefenseItemPoints = GetLocalInt(oDefendItem, "ItemPoints");
int nStrengthMod = GetAbilityModifier(ABILITY_STRENGTH, oAttacker);
int bArmor = FALSE;
if(nStrengthMod < 1) nStrengthMod = 1;
int nAttackDamage, nDefendDamage, nPossible, nTough;
if(bDamage)
{
if(nAttackElement == 0 && nDefendElement == 0)
//AttackRoll
{
if(bRanged)
{
if(oProjectile != OBJECT_INVALID)
{
nMaterialValue = nPMaterialValue;
nQualityValue = nPQualityValue - 1;
}
//Material is of projectile, Quality comes from both
else nMaterialValue = nDMaterialValue;
nQualityValue += nDQualityValue - 1;
//Arcane Archer Enchant feats add one per feat
if(nAType == BASE_ITEM_LONGBOW || nAType == BASE_ITEM_SHORTBOW)
{
int nFeat = 1059;
int bOnlyOne = FALSE;
while(nFeat > 1044 && bOnlyOne == FALSE)
{
if(GetHasFeat(nFeat, oAttacker))
{
nAttackRoll += (nFeat - 1039);
bOnlyOne == TRUE;
}
nFeat -= 1;
}
nFeat = 449;
while(nFeat > 444 && bOnlyOne == FALSE)
{
if(GetHasFeat(nFeat, oAttacker))
{
nAttackRoll += (nFeat - 444);
bOnlyOne == TRUE;
}
nFeat -= 1;
}
}
}
else
{
int bUnarmed = GetIsUnarmed(oAttacker);
if(bUnarmed)
{
if(GetHasFeat(FEAT_EPIC_IMPROVED_KI_STRIKE_5, oAttacker))
nAttackRoll += 100;
else if(GetHasFeat(FEAT_EPIC_IMPROVED_KI_STRIKE_4, oAttacker))
nAttackRoll += 80;
else if(GetHasFeat(344, oAttacker)) //Ki Strike +3
nAttackRoll += 60;
else if(GetHasFeat(343, oAttacker)) //Ki Strike +2
nAttackRoll += 40;
else if(GetHasFeat(FEAT_KI_STRIKE, oAttacker))
nAttackRoll += 20;
}
nMaterialValue = nAMaterialValue;
nQualityValue = nAQualityValue - 1;
}
nAttackRoll += (nMaterialValue + nQualityValue + nABValue);
nMaterialValue = nDMaterialValue;
nQualityValue = nDQualityValue - 1;
nAttackRoll -= (nMaterialValue + nQualityValue + nDRValue);
}
//ApplyItemDamage
if(nAttackElement == 0 && nDefendElement == 0)
{
if(nAttackRoll > -1)
{
nDefendDamage = nStrengthMod * (1 + nAttackRoll);
nAttackDamage = nStrengthMod/(1 + nAttackRoll);
}
else
{
nDefendDamage = nStrengthMod/(1 - nAttackRoll);
nAttackDamage = nStrengthMod *(1 - nAttackRoll);
}
}
else
{
if(nAttackElement != 46 && nDefendElement != 0)
nAttackDamage = nStrengthMod;
if(nDefendElement != 46 && nAttackElement != 0)
nDefendDamage = nStrengthMod;
}
if(bRanged) nDefendDamage = 0;
nTough = WEAPON_TOUGHNESS;
nPossible = ((nAttackItemPoints - nAttackDamage - 1) / nTough);
if(nPossible < 0)
{
if(nAType == BASE_ITEM_CREATUREITEM)
{
AssignCommand(oDefender, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDeath(TRUE), oAttacker));
if(GetIsPC(oAttacker)) SendMessageToPC(oAttacker, "Your body tears to shreds as you strike your opponent");
if(GetIsPC(oDefender)) SendMessageToPC(oDefender, "You feel an opponent's body tearing on your armor");
}
else
{
DestroyObject(oAttackWeapon);
if(GetIsPC(oAttacker)) SendMessageToPC(oAttacker, "Your weapon broke when striking your opponent");
if(GetIsPC(oDefender)) SendMessageToPC(oDefender, "A weapon broke when striking your armor");
}
}
else
{
if((nAttackItemPoints - 1)/ nTough > nPossible)
ResetQualityByDamage(oAttackWeapon, (nPossible + 1), ipAQuality);
SetLocalInt(oAttackWeapon, "ItemPoints", (nAttackItemPoints - nAttackDamage));
}
bArmor = GetIsArmor(nDType);
if(bArmor)
nTough = 10 * ARMOR_TOUGHNESS;
else nTough = 10 * WEAPON_TOUGHNESS;
nPossible = ((nDefenseItemPoints - nDefendDamage - 1)/nTough);
if(nPossible < 0)
{
if(nDType == BASE_ITEM_CREATUREITEM)
{
AssignCommand(oAttacker, ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectDeath(TRUE), oDefender));
if(GetIsPC(oAttacker)) SendMessageToPC(oAttacker, "Your blow tatters your opponent");
if(GetIsPC(oDefender)) SendMessageToPC(oDefender, "Your body is tattered from one too many blows");
}
else
{
DestroyObject(oDefendItem);
if(GetIsPC(oAttacker)) SendMessageToPC(oAttacker, "You have broken an item of your opponent");
if(GetIsPC(oDefender)) SendMessageToPC(oDefender, "Something broke from that last blow");
}
}
else
{
if((nDefenseItemPoints - 1)/nTough > nPossible)
ResetQualityByDamage(oDefendItem, (nPossible + 1), ipDQuality);
SetLocalInt(oDefendItem, "ItemPoints", (nDefenseItemPoints - nDefendDamage));
}
}
}
void ResetQualityByDamage(object oItem, int nQuality, itemproperty ipCurrentQuality)
{
RemoveItemProperty(oItem, ipCurrentQuality);
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyQuality(nQuality), oItem);
if(nQuality = 1)
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyNoDamage(), oItem);
}