Amon_PRC8/_module/nss/x2_inc_behcommon.nss
Jaysyn904 c5cffc37af Initial Commit
Initial Commit [v1.01]
2025-04-03 19:00:46 -04:00

451 lines
14 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Beholder common functions
//:: x2_inc_behcommon
//:: Copyright (c) 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
Contains functions taken from the Companion and Monster AI
*/
//:://////////////////////////////////////////////
//:: Created By: Tony K
//:: Created On: May, 2008
//:://////////////////////////////////////////////
#include "x0_i0_spells"
// As MyPrintString, but to screen instead of log
void Jug_Debug2(string sString)
{
SendMessageToPC(GetFactionLeader(GetFirstPC()), sString);
}
void SetObjectArray(object oSource, string sName, int iElem, object oElem)
{
string sFull = sName+IntToString(iElem);
SetLocalObject(oSource,sFull,oElem);
}
object GetObjectArray(object oSource, string sName, int iElem)
{
string sFull = sName+IntToString(iElem);
return GetLocalObject(oSource,sFull);
}
void SetIntArray(object oSource, string sName, int iElem, int iState)
{
string sFull = sName+IntToString(iElem);
SetLocalInt(oSource,sFull,iState);
}
int GetIntArray(object oSource, string sName, int iElem)
{
string sFull = sName+IntToString(iElem);
return GetLocalInt(oSource,sFull);
}
void SetFloatArray(object oSource, string sName, int iElem, float fVal)
{
string sFull = sName+IntToString(iElem);
SetLocalFloat(oSource,sFull,fVal);
}
float GetFloatArray(object oSource, string sName, int iElem)
{
string sFull = sName+IntToString(iElem);
return GetLocalFloat(oSource,sFull);
}
// returns TRUE if a humanoid
int GetIsHumanoid(int nRacial)
{
return
(nRacial == RACIAL_TYPE_DWARF) ||
(nRacial == RACIAL_TYPE_ELF) ||
(nRacial == RACIAL_TYPE_GNOME) ||
(nRacial == RACIAL_TYPE_HUMANOID_GOBLINOID) ||
(nRacial == RACIAL_TYPE_HALFLING) ||
(nRacial == RACIAL_TYPE_HUMAN) ||
(nRacial == RACIAL_TYPE_HALFELF) ||
(nRacial == RACIAL_TYPE_HALFORC) ||
(nRacial == RACIAL_TYPE_HUMANOID_MONSTROUS) ||
(nRacial == RACIAL_TYPE_HUMANOID_ORC) ||
(nRacial == RACIAL_TYPE_HUMANOID_REPTILIAN);
}
// check if target has a disabling effect
int GetIsDisabled(object oTarget)
{
effect eCheck = GetFirstEffect(oTarget);
while(GetIsEffectValid(eCheck))
{
switch (GetEffectType(eCheck))
{
case EFFECT_TYPE_PARALYZE:
case EFFECT_TYPE_STUNNED:
case EFFECT_TYPE_FRIGHTENED:
case EFFECT_TYPE_SLEEP:
case EFFECT_TYPE_DAZED:
case EFFECT_TYPE_CONFUSED:
case EFFECT_TYPE_TURNED:
case EFFECT_TYPE_PETRIFY:
return TRUE;
}
eCheck = GetNextEffect(oTarget);
}
return FALSE;
}
// This constant somewhat matches taking a henchmen hit dice and converting to CR rating
const float HENCH_HITDICE_TO_CR = 0.7;
const string sThreatRating = "HenchThreatRating";
// get threat rating of target, scale by hit dice
float GetRawThreatRating(object oTarget)
{
int lastTestHitDice = GetLocalInt(oTarget, sThreatRating);
int hitDice = GetHitDice(oTarget);
float fThreat;
if (GetHitDice(oTarget) == lastTestHitDice)
{
fThreat = GetLocalFloat(oTarget, sThreatRating);
}
else
{
fThreat = IntToFloat(GetHitDice(oTarget));
fThreat = pow(1.5, fThreat * HENCH_HITDICE_TO_CR);
int iAssocType = GetAssociateType(oTarget);
if (iAssocType == ASSOCIATE_TYPE_FAMILIAR)
{
fThreat *= 0.1;
}
else if (iAssocType != ASSOCIATE_TYPE_NONE && iAssocType != ASSOCIATE_TYPE_HENCHMAN)
{
fThreat *= 0.8;
}
if ((GetLevelByClass(CLASS_TYPE_WIZARD, oTarget) >= 5) || (GetLevelByClass(CLASS_TYPE_SORCERER, oTarget) >= 6))
{
fThreat *= 1.3;
}
else if ((GetLevelByClass(CLASS_TYPE_DRAGON, oTarget) >= 11))
{
// dragons are extra tough
fThreat *= 1.5;
}
if (fThreat < 0.001)
{
fThreat = 0.001;
}
SetLocalFloat(oTarget, sThreatRating, fThreat);
SetLocalInt(oTarget, sThreatRating, hitDice);
}
return fThreat;
}
int gHenchSpellTargetObjects;
const string BEHOLDER_SPELL_TARGET_OBJECTS = "BeholderSpellTarget";
// gets list of possible targets that are seen or heard
void HenchInitSpellTargetObjects(object oIntruder)
{
if (gHenchSpellTargetObjects != 0)
{
return;
}
int iMaxNumberToFind = GetAbilityScore(OBJECT_SELF, ABILITY_INTELLIGENCE) - 5;
if (iMaxNumberToFind > 15)
{
iMaxNumberToFind = 15;
}
else if (iMaxNumberToFind < 2)
{
iMaxNumberToFind = 2;
}
int bIntruderFound = !GetIsObjectValid(oIntruder);;
object oLastTarget = OBJECT_SELF;
int iCurSeenIndex = 1;
while (gHenchSpellTargetObjects <= iMaxNumberToFind)
{
object oCurSeen = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
OBJECT_SELF, iCurSeenIndex++, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN,
CREATURE_TYPE_IS_ALIVE, TRUE);
if (!GetIsObjectValid(oCurSeen))
{
break;
}
SetLocalObject(oLastTarget, BEHOLDER_SPELL_TARGET_OBJECTS, oCurSeen);
// Jug_Debug(GetName(OBJECT_SELF) + " adding seen target " + GetName(oCurSeen));
oLastTarget = oCurSeen;
gHenchSpellTargetObjects ++;
if (oCurSeen == oIntruder)
{
bIntruderFound = TRUE;
}
}
// limit the max number of heard targets to find
iMaxNumberToFind /= 2;
int iCurHeardIndex = 1;
while ((gHenchSpellTargetObjects <= iMaxNumberToFind) && (iCurHeardIndex < 3))
{
object oCurHeard = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
OBJECT_SELF, iCurHeardIndex++, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN,
CREATURE_TYPE_IS_ALIVE, TRUE);
if (!GetIsObjectValid(oCurHeard))
{
break;
}
if (LineOfSightObject(OBJECT_SELF, oCurHeard))
{
SetLocalObject(oLastTarget, BEHOLDER_SPELL_TARGET_OBJECTS, oCurHeard);
// Jug_Debug(GetName(OBJECT_SELF) + " adding heard target " + GetName(oCurHeard));
oLastTarget = oCurHeard;
gHenchSpellTargetObjects ++;
if (oCurHeard == oIntruder)
{
bIntruderFound = TRUE;
}
}
}
if (!bIntruderFound)
{
SetLocalObject(oLastTarget, BEHOLDER_SPELL_TARGET_OBJECTS, oIntruder);
// Jug_Debug(GetName(OBJECT_SELF) + " adding intruder " + GetName(oIntruder));
oLastTarget = oIntruder;
}
DeleteLocalObject(oLastTarget, BEHOLDER_SPELL_TARGET_OBJECTS);
}
// returns chance 0.0 to 1.0 for d20 roll
float Getd20Chance(int limit)
{
limit += 21;
if (limit >= 20)
{
return 1.0;
}
if (limit <= 0)
{
return 0.0;
}
return IntToFloat(limit) / 20.0;
}
// returns chance 0.0 to 1.0 for d20 roll 1, fail 20 success
float Getd20ChanceLimited(int limit)
{
if (limit <= 1)
{
return 0.05;
}
if (limit >= 19)
{
return 0.95;
}
return IntToFloat(limit) / 20.0;
}
const int HENCH_BLEED_NEGHPS = -10;
// returns damage amount on target 0.0 (none) to 1.0 (lethal damage)
float CalculateDamageWeight(float damageAmount, object oTarget)
{
//Jug_Debug(GetName(oTarget) + " HP " + IntToString(GetCurrentHitPoints(oTarget)));
int currentHitPoints = GetCurrentHitPoints(oTarget);
if (currentHitPoints < 1)
{
// assume a bleed system is used (HENCH_BLEED_NEGHPS is a negative number)
currentHitPoints -= HENCH_BLEED_NEGHPS;
if (currentHitPoints < 1)
{
currentHitPoints = 1;
}
}
damageAmount /= IntToFloat(currentHitPoints);
if (damageAmount > 1.0)
{
damageAmount = 1.0;
}
return damageAmount;
}
struct sEnhancementLevel
{
float breach;
float dispel;
};
int giBestDispelCastingLevel;
// chance that dispel will work
float GetDispelChance(object oCreator)
{
if (GetIsObjectValid(oCreator))
{
int nCasterLevel = GetCasterLevel(oCreator); // this isn't always accurate (reset every spell)
if (nCasterLevel <= 0)
{
nCasterLevel = GetHitDice(oCreator);
}
return Getd20Chance(giBestDispelCastingLevel - nCasterLevel - 11);
}
return Getd20Chance(giBestDispelCastingLevel - 21 /* 10 - 11 */);
}
const float fMaxEnhancementWeight = 0.5;
// Jugalator Script Additions
// Return 1 if target is enhanced with a beneficial
// spell that can be dispelled (= from a spell script), 2 if the
// effects can be breached, 0 otherwise.
// TK changed to not look for magical effects only
struct sEnhancementLevel Jug_GetHasBeneficialEnhancement(object oTarget)
{
struct sEnhancementLevel result;
effect eCheck = GetFirstEffect(oTarget);
int lastSpellId = -1;
int bCheckDispel = TRUE;
while (GetIsEffectValid(eCheck))
{
int iType = GetEffectType(eCheck);
if ((iType != EFFECT_TYPE_VISUALEFFECT) && (GetEffectSubType(eCheck) == SUBTYPE_MAGICAL))
{
if (bCheckDispel)
{
// Found an effect applied by a spell script - check the effect type
switch(iType)
{
case EFFECT_TYPE_VISUALEFFECT: // this effect is very common, don't check everything
break;
case EFFECT_TYPE_REGENERATE:
case EFFECT_TYPE_SANCTUARY:
case EFFECT_TYPE_IMMUNITY:
case EFFECT_TYPE_INVULNERABLE:
case EFFECT_TYPE_HASTE:
case EFFECT_TYPE_ELEMENTALSHIELD:
case EFFECT_TYPE_SPELL_IMMUNITY:
case EFFECT_TYPE_SPELLLEVELABSORPTION:
case EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE:
case EFFECT_TYPE_DAMAGE_INCREASE:
case EFFECT_TYPE_DAMAGE_REDUCTION:
case EFFECT_TYPE_DAMAGE_RESISTANCE:
case EFFECT_TYPE_POLYMORPH:
case EFFECT_TYPE_ETHEREAL:
case EFFECT_TYPE_INVISIBILITY:
if (result.dispel < fMaxEnhancementWeight)
{
result.dispel += 0.5 * GetDispelChance(GetEffectCreator(eCheck));
if (result.dispel >= fMaxEnhancementWeight)
{
result.dispel = fMaxEnhancementWeight;
bCheckDispel = FALSE;
}
}
break;
case EFFECT_TYPE_ABILITY_INCREASE:
case EFFECT_TYPE_AC_INCREASE:
case EFFECT_TYPE_ATTACK_INCREASE:
case EFFECT_TYPE_CONCEALMENT:
case EFFECT_TYPE_ENEMY_ATTACK_BONUS:
case EFFECT_TYPE_MOVEMENT_SPEED_INCREASE:
case EFFECT_TYPE_SAVING_THROW_INCREASE:
case EFFECT_TYPE_SEEINVISIBLE:
case EFFECT_TYPE_SKILL_INCREASE:
case EFFECT_TYPE_SPELL_RESISTANCE_INCREASE:
case EFFECT_TYPE_TEMPORARY_HITPOINTS:
case EFFECT_TYPE_TRUESEEING:
case EFFECT_TYPE_ULTRAVISION:
if (result.dispel < fMaxEnhancementWeight)
{
result.dispel += 0.1 * GetDispelChance(GetEffectCreator(eCheck));
if (result.dispel >= fMaxEnhancementWeight)
{
result.dispel = fMaxEnhancementWeight;
bCheckDispel = FALSE;
}
}
break;
/* case EFFECT_TYPE_PARALYZE:
case EFFECT_TYPE_STUNNED:
case EFFECT_TYPE_FRIGHTENED:
case EFFECT_TYPE_SLEEP:
case EFFECT_TYPE_DAZED:
case EFFECT_TYPE_CONFUSED:
case EFFECT_TYPE_TURNED:
case EFFECT_TYPE_PETRIFY:
case EFFECT_TYPE_CUTSCENEIMMOBILIZE:
case EFFECT_TYPE_MESMERIZE:
{
// if disabled don't dispel
struct sEnhancementLevel noResult;
return noResult;
} */
}
}
}
eCheck = GetNextEffect(oTarget);
}
// float targetWeight = GetThreatRating(oTarget);
// result.breach *= targetWeight;
// result.dispel *= targetWeight;
if (bCheckDispel)
{
// check if target has summons
object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oTarget);
if (GetIsObjectValid(oSummon))
{
// if (GetTag(oSummon) != "X2_S_DRGRED001" && GetTag(oSummon) != "X2_S_MUMMYWARR")
{
result.dispel += GetDispelChance(oTarget) * GetRawThreatRating(oSummon);
// if (result.dispel >= fMaxEnhancementWeight * targetWeight)
// {
// result.dispel = fMaxEnhancementWeight * targetWeight;
// }
}
}
}
return result;
}
// gets creature size adjusted for enlarge effects
int GetAdjustedCreatureSize(object oTarget)
{
int nSize = GetCreatureSize(oTarget);
return nSize;
}
const int SAVING_THROW_CHECK_FAILED = 0;
const int SAVING_THROW_CHECK_SUCCEEDED = 1;
const int SAVING_THROW_CHECK_IMMUNE = 2;
const int TOUCH_ATTACK_RESULT_MISS = 0;
const int TOUCH_ATTACK_RESULT_HIT = 1;
const int TOUCH_ATTACK_RESULT_CRITICAL = 2;