PRC8/nwn/nwnprc/trunk/include/prc_inc_damage.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
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.
2024-02-11 14:01:05 -05:00

398 lines
18 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Ability Damage application
//:: prc_inc_damage
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* Internal constants */
//////////////////////////////////////////////////
const string VIRTUAL_ABILITY_SCORE = "PRC_Virtual_Ability_Score_";
const string UbHealable_ABILITY_DAMAGE = "PRC_UbHealableAbilityDamage_";
const string ABILITY_DAMAGE_SPECIALS = "PRC_Ability_Damage_Special_Effects_Flags";
const string ABILITY_DAMAGE_MONITOR = "PRC_Ability_Monitor";
const int ABILITY_DAMAGE_EFFECT_PARALYZE = 1;
const int ABILITY_DAMAGE_EFFECT_KNOCKDOWN = 2;
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets the amount of ubHealable ability damage suffered by the creature to given ability
*
* @param oTarget The creature whose ubHealable ability damage to examine
* @param nAbility One of the ABILITY_* constants
*/
int GetUnHealableAbilityDamage(object oTarget, int nAbility);
/**
* Removes the specified amount of normally unHealable ability damage from the target
*
* @param oTarget The creature to restore
* @param nAbility Ability to restore, one of the ABILITY_* constants
* @param nAmount Amount to restore the ability by, should be > 0 for the function
* to have any effect
*/
void RecoverUnHealableAbilityDamage(object oTarget, int nAbility, int nAmount);
/**
* Applies the ability damage to the given target. Handles the virtual loss of
* ability scores below 3 and the effects of reaching 0 and making the damage
* ubHealable by standard means if requested.
*
*
* @param oTarget The creature about to take ability damage
* @param nAbility One of the ABILITY_* constants
* @param nAmount How much to reduce the ability score by
* @param nDurationType One of the DURATION_TYPE_* contants
* @param bHealable Whether the damage is healable by normal means or not.
* Implemented by applying the damage as an iprop on the hide
*
* The following are passed to SPApplyEffectToObject:
* @param fDuration If temporary, the duration. If this is -1.0, the damage
* will be applied so that it wears off at the rate of 1 point
* per ingame day.
* @param bDispellable Is the effect dispellable? If FALSE, the system will delay
* the application of the effect a short moment (10ms) to break
* spellID association. This will make effects from the same
* source stack with themselves.
* @param oSource Object causing the ability damage
*/
void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDurationType, int bHealable = TRUE,
float fDuration = 0.0f, int bDispellable = FALSE, object oSource = OBJECT_SELF);
// Similar funcionality to ApplyAbilityDamage() but used only for alcohol effects
// If you add new Alcohol effects or modify ApplyAbilityDamage() function, you
// should update this function as well.
void ApplyAlcoholEffect(object oTarget, int nAmount, float fDuration);
/**
* Sets the values of ability decrease on target's hide to be the same as the value
* tracked on the target object itself. This is called with delay from ScrubPCSkin()
* in order to synchronise the tracked value of ubHealable damage with that actually
* present on the hide.
* Please call this if you do similar operations on the hide.
*
* @param oTarget The creature whose hide and tracked value to synchronise.
*/
void ReApplyUnhealableAbilityDamage(object oTarget);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
//#include "prc_inc_racial"
#include "prc_effect_inc"
#include "inc_item_props"
//////////////////////////////////////////////////
/* Function defintions */
//////////////////////////////////////////////////
void ApplyAbilityDamage(object oTarget, int nAbility, int nAmount, int nDurationType, int bHealable = TRUE,
float fDuration = 0.0f, int bDispellable = FALSE, object oSource = OBJECT_SELF)
{
// Immunity check
if(GetIsImmune(oTarget, IMMUNITY_TYPE_ABILITY_DECREASE, oSource))
return;
if (GetLocalInt(oTarget, "IncarnumDefenseCE") && nAbility == ABILITY_STRENGTH)
return;
if (GetIsMeldBound(oTarget, MELD_VITALITY_BELT) == CHAKRA_WAIST && nAbility == ABILITY_CONSTITUTION)
return;
if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oTarget) && nAbility == ABILITY_WISDOM && GetLocalInt(oTarget, "ExploitVestige") != VESTIGE_DAHLVERNAR_MAD_SOUL)
return;
// Strongheart Vest reduces by Essentia amount + 1. If it's bound, reduces ability drain as well
if (GetHasSpellEffect(MELD_STRONGHEART_VEST, oTarget) && bHealable)
{
int nEssentia = GetEssentiaInvested(oTarget, MELD_STRONGHEART_VEST);
nAmount = nAmount - (nEssentia + 1);
// If there's no damage, jump out.
if (0 >= nAmount) return;
}
else if (GetIsMeldBound(oTarget, MELD_STRONGHEART_VEST) == CHAKRA_WAIST && !bHealable)
{
int nEssentia = GetEssentiaInvested(oTarget, MELD_STRONGHEART_VEST);
nAmount = nAmount - (nEssentia + 1);
// If there's no damage, jump out.
if (0 >= nAmount) return;
}
// Get the value of the stat before anything is done
int nStartingValue = GetAbilityScore(oTarget, nAbility);
// First, apply the whole damage as an effect
//SendMessageToPC(GetFirstPC(), "Applying " + IntToString(nAmount) + " damage to stat " + IntToString(nAbility));
if(bHealable)
{
// Is the damage temporary and specified to heal at the PnP rate
if(nDurationType == DURATION_TYPE_TEMPORARY && fDuration == -1.0f)
{
int i;
for(i = 1; i <= nAmount; i++)
DelayCommand(0.01f, ApplyEffectToObject(nDurationType, bDispellable ? TagEffect(EffectAbilityDecrease(nAbility, 1), IntToString(nAbility)+IntToString(1)) : TagEffect(SupernaturalEffect(EffectAbilityDecrease(nAbility, 1)), IntToString(nAbility)+IntToString(1)), oTarget, HoursToSeconds(24) * i));
}
else if(!bDispellable)
{
DelayCommand(0.01f, ApplyEffectToObject(nDurationType, TagEffect(SupernaturalEffect(EffectAbilityDecrease(nAbility, nAmount)), IntToString(nAbility)+IntToString(nAmount)), oTarget, fDuration));
}
else
{
ApplyEffectToObject(nDurationType, TagEffect(EffectAbilityDecrease(nAbility, nAmount), IntToString(nAbility)+IntToString(nAmount)), oTarget, fDuration);
}
}
// Non-healable damage
else
{
int nIPType;
int nTotalAmount;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: nIPType = IP_CONST_ABILITY_STR; sVarName += "STR"; break;
case ABILITY_DEXTERITY: nIPType = IP_CONST_ABILITY_DEX; sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: nIPType = IP_CONST_ABILITY_CON; sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: nIPType = IP_CONST_ABILITY_INT; sVarName += "INT"; break;
case ABILITY_WISDOM: nIPType = IP_CONST_ABILITY_WIS; sVarName += "WIS"; break;
case ABILITY_CHARISMA: nIPType = IP_CONST_ABILITY_CHA; sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
// Sum the damage being added with damage that was present previously
nTotalAmount = GetLocalInt(oTarget, sVarName) + nAmount;
// Apply the damage
SetCompositeBonus(GetPCSkin(oTarget), sVarName, nTotalAmount, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, nIPType);
// Also store the amount of damage on the PC itself so it can be restored at a later date.
SetLocalInt(oTarget, sVarName, nTotalAmount);
// Schedule recovering if the damage is temporary
if(nDurationType == DURATION_TYPE_TEMPORARY)
{
// If the damage is specified to heal at the PnP rate, schedule one point to heal per day
if(fDuration == -1.0f)
{
int i;
for(i = 1; i <= nAmount; i++)
DelayCommand(HoursToSeconds(24) * i, RecoverUnHealableAbilityDamage(oTarget, nAbility, 1));
}
// Schedule everything to heal at once
else
DelayCommand(fDuration, RecoverUnHealableAbilityDamage(oTarget, nAbility, nAmount));
}
}
// The system is off by default
if(!GetPRCSwitch(PRC_PNP_ABILITY_DAMAGE_EFFECTS))
return;
// If the target is at the minimum supported by NWN, check if they have had their ability score reduced below already
if(nStartingValue == 3)
nStartingValue = GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility)) ?
GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility)) - 1 :
nStartingValue;
// See if any of the damage goes into the virtual area of score < 3
if(nStartingValue - nAmount < 3)
{
int nVirtual = nStartingValue - nAmount;
if(nVirtual < 0) nVirtual = 0;
// Mark the virtual value
SetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(nAbility), nVirtual + 1);
// Cause effects for being at 0
if(nVirtual == 0)
{
// Apply the effects
switch(nAbility)
{
// Lying down
case ABILITY_STRENGTH:
case ABILITY_INTELLIGENCE:
case ABILITY_WISDOM:
case ABILITY_CHARISMA:
// Do not apply duplicate effects
/*if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);*/
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_KNOCKDOWN))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 9999.0f);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_KNOCKDOWN);
}
//break;
// Paralysis
case ABILITY_DEXTERITY:
// Do not apply duplicate effects
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
{
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_PARALYZE);
}
break;
// Death
case ABILITY_CONSTITUTION:
// Non-constitution score critters avoid this one
if(!(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD ||
MyPRCGetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT
) )
{
DeathlessFrenzyCheck(oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath()), oTarget);
}
break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
// Start the monitor HB if it is not active yet
if(GetThreadState(ABILITY_DAMAGE_MONITOR, oTarget) == THREAD_STATE_DEAD)
SpawnNewThread(ABILITY_DAMAGE_MONITOR, "prc_abil_monitor", 1.0f, oTarget);
// Note the ability score for monitoring
SetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR, GetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR) | (1 << nAbility));
}
}
}
void ApplyAlcoholEffect(object oTarget, int nAmount, float fDuration)
{
// Immunity check
if(GetIsImmune(oTarget, IMMUNITY_TYPE_ABILITY_DECREASE))
return;
// Get the value of the stat before anything is done
int nStartingValue = GetAbilityScore(oTarget, ABILITY_INTELLIGENCE);
// First, apply the whole damage as an effect
DelayCommand(0.01f, AssignCommand(GetPCSkin(oTarget), ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectAbilityDecrease(ABILITY_INTELLIGENCE, nAmount)), oTarget, fDuration)));
// The system is off by default
if(!GetPRCSwitch(PRC_PNP_ABILITY_DAMAGE_EFFECTS))
return;
// If the target is at the minimum supported by NWN, check if they have had their ability score reduced below already
if(nStartingValue == 3)
nStartingValue = GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE)) ?
GetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE)) - 1 :
nStartingValue;
// See if any of the damage goes into the virtual area of score < 3
if(nStartingValue - nAmount < 3)
{
int nVirtual = nStartingValue - nAmount;
if(nVirtual < 0) nVirtual = 0;
// Mark the virtual value
SetLocalInt(oTarget, VIRTUAL_ABILITY_SCORE + IntToString(ABILITY_INTELLIGENCE), nVirtual + 1);
// Cause effects for being at 0
if(!nVirtual)
{
// Do not apply duplicate effects
/*if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_PARALYZE))
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneParalyze(), oTarget);*/
if(!(GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) & ABILITY_DAMAGE_EFFECT_KNOCKDOWN))
{
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 9999.0f);
SetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS, GetLocalInt(oTarget, ABILITY_DAMAGE_SPECIALS) | ABILITY_DAMAGE_EFFECT_KNOCKDOWN);
}
// Start the monitor HB if it is not active yet
if(GetThreadState(ABILITY_DAMAGE_MONITOR, oTarget) == THREAD_STATE_DEAD)
SpawnNewThread(ABILITY_DAMAGE_MONITOR, "prc_abil_monitor", 1.0f, oTarget);
// Note the ability score for monitoring
SetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR, GetLocalInt(oTarget, ABILITY_DAMAGE_MONITOR) | (1 << ABILITY_INTELLIGENCE));
}
}
}
void ReApplyUnhealableAbilityDamage(object oTarget)
{
object oSkin = GetPCSkin(oTarget);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_STR",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_STR"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_STR);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_DEX",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_DEX"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_DEX);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_CON",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_CON"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_CON);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_INT",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_INT"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_INT);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_WIS",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_WIS"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_WIS);
SetCompositeBonus(oSkin, "PRC_UbHealableAbilityDamage_CHA",
GetLocalInt(oTarget, "PRC_UbHealableAbilityDamage_CHA"),
ITEM_PROPERTY_DECREASED_ABILITY_SCORE, IP_CONST_ABILITY_CHA);
}
int GetUnHealableAbilityDamage(object oTarget, int nAbility)
{
int nIPType;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: sVarName += "STR"; break;
case ABILITY_DEXTERITY: sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: sVarName += "INT"; break;
case ABILITY_WISDOM: sVarName += "WIS"; break;
case ABILITY_CHARISMA: sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to GetUnHealableAbilityDamage: " + IntToString(nAbility));
return FALSE;
}
return GetLocalInt(oTarget, sVarName);
}
void RecoverUnHealableAbilityDamage(object oTarget, int nAbility, int nAmount)
{
// Sanity check, one should not be able to cause more damage via this function, ApplyAbilityDamage() is for that.
if(nAmount < 0) return;
int nIPType, nNewVal;
string sVarName = "PRC_UbHealableAbilityDamage_";
switch(nAbility)
{
case ABILITY_STRENGTH: nIPType = IP_CONST_ABILITY_STR; sVarName += "STR"; break;
case ABILITY_DEXTERITY: nIPType = IP_CONST_ABILITY_DEX; sVarName += "DEX"; break;
case ABILITY_CONSTITUTION: nIPType = IP_CONST_ABILITY_CON; sVarName += "CON"; break;
case ABILITY_INTELLIGENCE: nIPType = IP_CONST_ABILITY_INT; sVarName += "INT"; break;
case ABILITY_WISDOM: nIPType = IP_CONST_ABILITY_WIS; sVarName += "WIS"; break;
case ABILITY_CHARISMA: nIPType = IP_CONST_ABILITY_CHA; sVarName += "CHA"; break;
default:
WriteTimestampedLogEntry("Unknown nAbility passed to ApplyAbilityDamage: " + IntToString(nAbility));
return;
}
nNewVal = GetLocalInt(oTarget, sVarName) - nAmount;
if(nNewVal < 0) nNewVal = 0;
SetCompositeBonus(GetPCSkin(oTarget), sVarName, nNewVal, ITEM_PROPERTY_DECREASED_ABILITY_SCORE, nIPType);
SetLocalInt(oTarget, sVarName, nNewVal);
}