655 lines
18 KiB
Plaintext
655 lines
18 KiB
Plaintext
/*
|
|
|
|
Henchman Inventory And Battle AI
|
|
|
|
This file contains miscellaneous functions used by
|
|
many scripts.
|
|
|
|
*/
|
|
|
|
// void main() { }
|
|
|
|
#include "nw_i0_generic"
|
|
#include "x0_i0_voice"
|
|
#include "hench_i0_strings"
|
|
#include "hench_i0_options"
|
|
#include "hench_i0_conv"
|
|
|
|
|
|
|
|
// This constant somewhat matches taking a henchmen hit dice and converting to CR rating
|
|
const float HENCH_HITDICE_TO_CR = 0.7;
|
|
|
|
// general effects on self
|
|
const int HENCH_HAS_ETHEREAL_EFFECT = 0x001;
|
|
const int HENCH_HAS_CONCEALMENT_EFFECT = 0x002;
|
|
const int HENCH_HAS_INVISIBILITY_EFFECT = 0x004;
|
|
const int HENCH_HAS_SANTUARY_EFFECT = 0x008;
|
|
const int HENCH_HAS_DAZED_EFFECT = 0x010;
|
|
const int HENCH_HAS_CONFUSED_EFFECT = 0x020;
|
|
const int HENCH_HAS_CHARMED_EFFECT = 0x040;
|
|
const int HENCH_HAS_POLYMORPH_EFFECT = 0x080;
|
|
const int HENCH_HAS_HASTE_EFFECT = 0x100;
|
|
const int HENCH_HAS_TIMESTOP_EFFECT = 0x200;
|
|
|
|
|
|
const string sHenchSummonedFamiliar = "HenchSummonedFamiliar";
|
|
const string sHenchSummonedAniComp = "HenchSummonedAniComp";
|
|
const string sHenchPseudoSummon = "HenchPseudoSummon";
|
|
|
|
|
|
const string sHenchDontAttackFlag = "DoNotAttack";
|
|
const string sHenchScoutingFlag = "Scouting";
|
|
const string sHenchScoutTarget = "ScoutTarget";
|
|
const string sHenchRunningAway = "RunningAway";
|
|
|
|
|
|
const int HENCH_HEAL_SELF_UNKNOWN = 0;
|
|
const int HENCH_HEAL_SELF_CANT = 1;
|
|
const int HENCH_HEAL_SELF_WAIT = 2;
|
|
const int HENCH_HEAL_SELF_IN_PROG = 3;
|
|
const string HENCH_HEAL_SELF_STATE = "HenchHealSelfState";
|
|
|
|
|
|
// As MyPrintString, but to screen instead of log
|
|
void Jug_Debug(string sString);
|
|
|
|
// returns TRUE if any one of the two effect types are present
|
|
int GetHasAnyEffect2(int nEffectType1, int nEffectType2, object oTarget = OBJECT_SELF);
|
|
|
|
// returns TRUE if the target is disabled
|
|
int GetIsDisabled(object oTarget);
|
|
|
|
// returns TRUE if the target is disabled or has another effect
|
|
int GetIsDisabled1(int nOtherEffect, object oTarget);
|
|
|
|
// returns TRUE if the target is disabled or has another effect
|
|
int GetIsDisabled2(int nOtherEffect1, int nOtherEffect2, object oTarget);
|
|
|
|
// returns TRUE if racial type is a humanoid
|
|
int GetIsHumanoid(int nRacial);
|
|
|
|
// returns TRUE if creature can use items from their inventory
|
|
int GetCreatureUseItems(object oCreature);
|
|
|
|
// returns TRUE if the item property is present in any one of the equipped items
|
|
int GetCreatureHasItemProperty(int nItemProperty, object oCreature = OBJECT_SELF);
|
|
|
|
// set array access for objects
|
|
void SetObjectArray(object oSource, string sName, int iElem, object oElem);
|
|
|
|
// get array access for objects
|
|
object GetObjectArray(object oSource, string sName, int iElem);
|
|
|
|
// set array access for ints
|
|
void SetIntArray(object oSource, string sName, int iElem, int iState);
|
|
|
|
// get array access for ints
|
|
int GetIntArray(object oSource, string sName, int iElem);
|
|
|
|
// set array access for floats
|
|
void SetFloatArray(object oSource, string sName, int iElem, float fVal);
|
|
|
|
// get array access for floats
|
|
float GetFloatArray(object oSource, string sName, int iElem);
|
|
|
|
// returns TRUE if object1 and object are on opposite sides of door
|
|
int IsOnOppositeSideOfDoor(object oDoor, object obj1, object obj2);
|
|
|
|
// stores the last spell cast (no timeout)
|
|
void HenchSetLastGenericSpellCast(int nSpell);
|
|
|
|
// returns the highest level master of oAssociate
|
|
// returns OBJECT_INVALID if no master
|
|
object GetRealMaster(object oAssociate = OBJECT_SELF);
|
|
|
|
// returns the highest level master of oAssociate
|
|
// returns OBJECT_SELF if no master
|
|
object GetTopMaster(object oAssociate = OBJECT_SELF);
|
|
|
|
// converts a prestige class into the best matching primary class
|
|
int HenchConvertClass(int nClass, object oCharacter);
|
|
|
|
// returns the class type that best represents oCharacter
|
|
int HenchDetermineClassToUse(object oCharacter = OBJECT_SELF);
|
|
|
|
// Cleans all temporary values used during combat
|
|
void CleanCombatVars();
|
|
|
|
|
|
|
|
// As MyPrintString, but to screen instead of log
|
|
void Jug_Debug(string sString)
|
|
{
|
|
SendMessageToPC(GetFirstPC(), sString);
|
|
}
|
|
|
|
|
|
int GetHasAnyEffect2(int nEffectType1, int nEffectType2, object oTarget = OBJECT_SELF)
|
|
{
|
|
effect eCheck = GetFirstEffect(oTarget);
|
|
while(GetIsEffectValid(eCheck))
|
|
{
|
|
int nTestEffect = GetEffectType(eCheck);
|
|
if(nTestEffect == nEffectType1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if(nTestEffect == nEffectType2)
|
|
{
|
|
return TRUE;
|
|
}
|
|
eCheck = GetNextEffect(oTarget);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int GetIsDisabled1(int nOtherEffect, object oTarget)
|
|
{
|
|
effect eCheck = GetFirstEffect(oTarget);
|
|
while(GetIsEffectValid(eCheck))
|
|
{
|
|
int nTestEffect = GetEffectType(eCheck);
|
|
switch (nTestEffect)
|
|
{
|
|
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;
|
|
}
|
|
if (nTestEffect == nOtherEffect)
|
|
{
|
|
return TRUE;
|
|
}
|
|
eCheck = GetNextEffect(oTarget);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int GetIsDisabled2(int nOtherEffect1, int nOtherEffect2, object oTarget)
|
|
{
|
|
effect eCheck = GetFirstEffect(oTarget);
|
|
while(GetIsEffectValid(eCheck))
|
|
{
|
|
int nTestEffect = GetEffectType(eCheck);
|
|
switch (nTestEffect)
|
|
{
|
|
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;
|
|
}
|
|
if (nTestEffect == nOtherEffect1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (nTestEffect == nOtherEffect2)
|
|
{
|
|
return TRUE;
|
|
}
|
|
eCheck = GetNextEffect(oTarget);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
int GetCreatureUseItems(object oCreature)
|
|
{
|
|
if (GetIsPlayableRacialType(oCreature))
|
|
{
|
|
return TRUE;
|
|
}
|
|
int nRace = GetRacialType(oCreature);
|
|
if ((nRace >= RACIAL_TYPE_HUMANOID_GOBLINOID && nRace <= RACIAL_TYPE_HUMANOID_REPTILIAN) ||
|
|
nRace == RACIAL_TYPE_FEY || nRace == RACIAL_TYPE_GIANT)
|
|
{
|
|
return TRUE;
|
|
}
|
|
int nAppearanceType = GetAppearanceType(oCreature);
|
|
if (nRace == RACIAL_TYPE_UNDEAD)
|
|
{
|
|
return nAppearanceType != APPEARANCE_TYPE_DRACOLICH &&
|
|
nAppearanceType != APPEARANCE_TYPE_SKELETAL_DEVOURER &&
|
|
nAppearanceType != APPEARANCE_TYPE_ALLIP;
|
|
}
|
|
if (nAppearanceType >= APPEARANCE_TYPE_DWARF && nAppearanceType <= APPEARANCE_TYPE_HUMAN)
|
|
{
|
|
return TRUE;
|
|
}
|
|
if (nRace == RACIAL_TYPE_ABERRATION)
|
|
{
|
|
return nAppearanceType == APPEARANCE_TYPE_MINDFLAYER ||
|
|
nAppearanceType == APPEARANCE_TYPE_MINDFLAYER_2 ||
|
|
nAppearanceType == APPEARANCE_TYPE_MINDFLAYER_ALHOON ||
|
|
nAppearanceType == APPEARANCE_TYPE_DRIDER ||
|
|
nAppearanceType == APPEARANCE_TYPE_DRIDER_CHIEF ||
|
|
nAppearanceType == APPEARANCE_TYPE_DRIDER_FEMALE ||
|
|
GetCreatureUseItemsOverride(oCreature);
|
|
}
|
|
if (nRace == RACIAL_TYPE_OUTSIDER)
|
|
{
|
|
return nAppearanceType == APPEARANCE_TYPE_SUCCUBUS ||
|
|
nAppearanceType == APPEARANCE_TYPE_AZER_MALE ||
|
|
nAppearanceType == APPEARANCE_TYPE_AZER_FEMALE ||
|
|
nAppearanceType == APPEARANCE_TYPE_RAKSHASA_TIGER_FEMALE ||
|
|
nAppearanceType == APPEARANCE_TYPE_RAKSHASA_TIGER_FEMALE ||
|
|
GetCreatureUseItemsOverride(oCreature);
|
|
}
|
|
return GetCreatureUseItemsOverride(oCreature);
|
|
}
|
|
|
|
|
|
int GetCreatureHasItemProperty(int nItemProperty, object oCreature = OBJECT_SELF)
|
|
{
|
|
int i;
|
|
for (i = 0; i < NUM_INVENTORY_SLOTS; i++)
|
|
{
|
|
object oItem = GetItemInSlot(i, oCreature);
|
|
if(GetItemHasItemProperty(oItem, nItemProperty))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
int IsOnOppositeSideOfDoor(object oDoor, object obj1, object obj2)
|
|
{
|
|
float fDoorAngle = GetFacing(oDoor);
|
|
|
|
vector vDoor = GetPositionFromLocation(GetLocation(oDoor));
|
|
vector v1 = GetPositionFromLocation(GetLocation(obj1));
|
|
vector v2 = GetPositionFromLocation(GetLocation(obj2));
|
|
|
|
float fAngle1 = VectorToAngle(v1 - vDoor);
|
|
float fAngle2 = VectorToAngle(v2 - vDoor);
|
|
|
|
fAngle1 -= fDoorAngle;
|
|
fAngle2 -= fDoorAngle;
|
|
if (fAngle1 < 0.0)
|
|
{
|
|
fAngle1 += 360.0;
|
|
}
|
|
if (fAngle2 < 0.0)
|
|
{
|
|
fAngle2 += 360.0;
|
|
}
|
|
|
|
int bSide1 = fAngle1 < 90.0 || fAngle1 > 270.0;
|
|
int bSide2 = fAngle2 < 90.0 || fAngle2 > 270.0;
|
|
|
|
return bSide1 != bSide2;
|
|
}
|
|
|
|
|
|
void HenchSetLastGenericSpellCast(int nSpell)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, "NW_GENERIC_LAST_SPELL", nSpell);
|
|
}
|
|
|
|
|
|
//69MEH69 GetRealMaster Code
|
|
object GetRealMaster(object oAssociate = OBJECT_SELF)
|
|
{
|
|
object oMaster = GetMaster(oAssociate);
|
|
if (GetIsObjectValid(oMaster))
|
|
{
|
|
while (GetIsObjectValid(GetMaster(oMaster)))
|
|
{
|
|
oMaster = GetMaster(oMaster);
|
|
}
|
|
}
|
|
return oMaster;
|
|
}
|
|
|
|
|
|
object GetTopMaster(object oAssociate = OBJECT_SELF)
|
|
{
|
|
object oRetVal = oAssociate;
|
|
object oMaster = GetMaster(oAssociate);
|
|
while (GetIsObjectValid(oMaster))
|
|
{
|
|
oRetVal = oMaster;
|
|
oMaster = GetMaster(oMaster);
|
|
}
|
|
return oRetVal;
|
|
}
|
|
|
|
|
|
object GetTopAssociate(object oAssociate = OBJECT_SELF)
|
|
{
|
|
object oRetVal = oAssociate;
|
|
object oMaster = GetMaster(oAssociate);
|
|
if (GetIsObjectValid(oMaster))
|
|
{
|
|
while (GetIsObjectValid(GetMaster(oMaster)))
|
|
{
|
|
oRetVal = oMaster;
|
|
oMaster = GetMaster(oMaster);
|
|
}
|
|
}
|
|
return oRetVal;
|
|
}
|
|
|
|
|
|
int HenchConvertClass(int nClass, object oCharacter)
|
|
{
|
|
switch(nClass)
|
|
{
|
|
case CLASS_TYPE_SHADOWDANCER:
|
|
case CLASS_TYPE_ASSASSIN:
|
|
return CLASS_TYPE_ROGUE;
|
|
case CLASS_TYPE_HARPER:
|
|
case CLASS_TYPE_ARCANE_ARCHER:
|
|
case CLASS_TYPE_DRAGON_DISCIPLE:
|
|
return CLASS_TYPE_BARD;
|
|
case CLASS_TYPE_SHIFTER:
|
|
return CLASS_TYPE_DRUID;
|
|
case CLASS_TYPE_PALE_MASTER:
|
|
return GetClassByPosition(1, oCharacter);
|
|
}
|
|
return nClass;
|
|
}
|
|
|
|
|
|
int HenchDetermineClassToUse(object oCharacter = OBJECT_SELF)
|
|
{
|
|
int nClass;
|
|
int nTotal = GetHitDice(oCharacter);
|
|
if (nTotal < 1)
|
|
{
|
|
nTotal = 1;
|
|
}
|
|
|
|
int nClassLevel1 = GetLevelByPosition(1, oCharacter);
|
|
int nClass1 = GetClassByPosition(1, oCharacter);
|
|
// quick exit
|
|
if (nClassLevel1 >= nTotal)
|
|
{
|
|
return nClass1;
|
|
}
|
|
|
|
int nClassLevel2 = GetLevelByPosition(2, oCharacter);
|
|
int nClass2 = GetClassByPosition(2, oCharacter);
|
|
int nClassLevel3 = GetLevelByPosition(3, oCharacter);
|
|
int nClass3 = GetClassByPosition(3, oCharacter);
|
|
|
|
// blackguard over everthing else
|
|
if (nClass1 == CLASS_TYPE_BLACKGUARD || nClass2 == CLASS_TYPE_BLACKGUARD ||
|
|
nClass3 == CLASS_TYPE_BLACKGUARD)
|
|
{
|
|
return CLASS_TYPE_BLACKGUARD;
|
|
}
|
|
if (nClass1 == CLASS_TYPE_DIVINE_CHAMPION || nClass2 == CLASS_TYPE_DIVINE_CHAMPION ||
|
|
nClass3 == CLASS_TYPE_DIVINE_CHAMPION)
|
|
{
|
|
return CLASS_TYPE_DIVINE_CHAMPION;
|
|
}
|
|
if (nClass1 == CLASS_TYPE_WEAPON_MASTER || nClass2 == CLASS_TYPE_WEAPON_MASTER ||
|
|
nClass3 == CLASS_TYPE_WEAPON_MASTER)
|
|
{
|
|
return CLASS_TYPE_WEAPON_MASTER;
|
|
}
|
|
if (nClass1 == CLASS_TYPE_DWARVEN_DEFENDER || nClass2 == CLASS_TYPE_DWARVEN_DEFENDER ||
|
|
nClass3 == CLASS_TYPE_DWARVEN_DEFENDER)
|
|
{
|
|
return CLASS_TYPE_DWARVEN_DEFENDER;
|
|
}
|
|
// adjust classes to remove prestige
|
|
nClass1 = HenchConvertClass(nClass1, oCharacter);
|
|
nClass2 = HenchConvertClass(nClass2, oCharacter);
|
|
nClass3 = HenchConvertClass(nClass3, oCharacter);
|
|
if (nClass1 == nClass2)
|
|
{
|
|
nClassLevel1 += nClassLevel2;
|
|
nClassLevel2 = 0;
|
|
}
|
|
if (nClass1 == nClass3)
|
|
{
|
|
nClassLevel1 += nClassLevel3;
|
|
nClassLevel3 = 0;
|
|
}
|
|
if (nClass2 == nClass3)
|
|
{
|
|
nClassLevel2 += nClassLevel3;
|
|
nClassLevel3 = 0;
|
|
}
|
|
// find top class
|
|
int nMaxClassLevel = nClassLevel1 >= nClassLevel2 ? nClassLevel1 : nClassLevel2;
|
|
nMaxClassLevel = nMaxClassLevel >= nClassLevel3 ? nMaxClassLevel : nClassLevel3;
|
|
// filter out classes less than two levels below the max
|
|
if (nMaxClassLevel - 1 > nClassLevel1)
|
|
{
|
|
nClassLevel1 = 0;
|
|
}
|
|
if (nMaxClassLevel - 1 > nClassLevel2)
|
|
{
|
|
nClassLevel2 = 0;
|
|
}
|
|
if (nMaxClassLevel - 1 > nClassLevel3)
|
|
{
|
|
nClassLevel3 = 0;
|
|
}
|
|
nTotal = nClassLevel1 + nClassLevel2 + nClassLevel3;
|
|
int nPickClass = Random(nTotal);
|
|
nPickClass -= nClassLevel1;
|
|
if (nPickClass < 0)
|
|
{
|
|
return nClass1;
|
|
}
|
|
nPickClass -= nClassLevel2;
|
|
if (nPickClass < 0)
|
|
{
|
|
return nClass2;
|
|
}
|
|
return nClass3;
|
|
}
|
|
|
|
|
|
int CheckStealth()
|
|
{
|
|
int nStealthCheck = GetLocalInt(OBJECT_SELF, "canStealth");
|
|
if (nStealthCheck == 0)
|
|
{
|
|
nStealthCheck = ((GetSkillRank(SKILL_HIDE, OBJECT_SELF, TRUE) > 0) ||
|
|
(GetSkillRank(SKILL_MOVE_SILENTLY, OBJECT_SELF, TRUE) > 0)) ? 1 : 2;
|
|
SetLocalInt(OBJECT_SELF, "canStealth", nStealthCheck);
|
|
}
|
|
return nStealthCheck == 1;
|
|
}
|
|
|
|
|
|
void SetCombatMode(int nCombatMode = -1)
|
|
{
|
|
int index;
|
|
for (index = ACTION_MODE_PARRY; index <= ACTION_MODE_DIRTY_FIGHTING; index ++)
|
|
{
|
|
int bEnable = nCombatMode == index;
|
|
if (GetActionMode(OBJECT_SELF, index) != bEnable)
|
|
{
|
|
if (bEnable)
|
|
{
|
|
ActionDoCommand(SetActionMode(OBJECT_SELF, index, TRUE));
|
|
}
|
|
else
|
|
{
|
|
SetActionMode(OBJECT_SELF, index, bEnable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
const string sHenchLastAttackLocation = "HENCH_LAST_ATTACK_LOC";
|
|
|
|
void UseCombatAttack(object oTarget, int nFeatID = -1, int nCombatMode = -1)
|
|
{
|
|
SetCombatMode(nCombatMode);
|
|
if (nFeatID < 0)
|
|
{
|
|
ActionAttack(oTarget);
|
|
}
|
|
else
|
|
{
|
|
ActionUseFeat(nFeatID, oTarget);
|
|
}
|
|
SetLocalLocation(OBJECT_SELF, sHenchLastAttackLocation, GetLocation(OBJECT_SELF));
|
|
//const string sHenchLastAttackLocation = "HENCH_LAST_ATTACK_LOC";
|
|
|
|
}
|
|
|
|
|
|
const string henchCombatRoundStr = "tkCombatRoundCount";
|
|
const string henchLastDraBrStr = "tkLastDragonBreath";
|
|
const string henchLastDispelStr = "tkLastDispel";
|
|
const string henchLastDomStr = "tkLastDominate";
|
|
const string henchLastTurnStr = "tkLastTurning";
|
|
const string henchSpellKnownFlagsStr = "HenchSpellKnownFlags";
|
|
const string henchNoAttackSpStr = "tkNoAttackSpellTalents";
|
|
const string henchNoEnhanceSpStr = "tkNoEnhanceSpellTalents";
|
|
const string henchNoCondSpStr = "tkNoConditionalSpellTalents";
|
|
const string henchNoPotionStr = "tkNoPotions";
|
|
const string henchBuffCountStr = "HenchCurBuffCount";
|
|
const string henchHealCountStr = "HenchCurHealCount";
|
|
const string sHenchLastTarget = "LastTarget";
|
|
const string sHenchShouldIAttackMessageGiven = "HenchShouldIAttackMessageGiven";
|
|
|
|
|
|
const int HENCH_MAIN_SPELL_SERIES = 0x1;
|
|
const int HENCH_CURE_COND_SPELL = 0x2;
|
|
|
|
int GetSpellUnknownFlag(int flag)
|
|
{
|
|
return GetLocalInt(OBJECT_SELF, henchSpellKnownFlagsStr) & flag;
|
|
}
|
|
|
|
|
|
void SetSpellUnknownFlag(int flag)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, henchSpellKnownFlagsStr, GetLocalInt(OBJECT_SELF, henchSpellKnownFlagsStr) | flag);
|
|
}
|
|
|
|
|
|
void CleanCombatVars()
|
|
{
|
|
DeleteLocalInt(OBJECT_SELF, henchCombatRoundStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchLastDraBrStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchLastDispelStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchLastDomStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchLastTurnStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchSpellKnownFlagsStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchNoAttackSpStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchNoEnhanceSpStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchNoCondSpStr);
|
|
DeleteLocalInt(OBJECT_SELF, henchNoPotionStr);
|
|
DeleteLocalInt(OBJECT_SELF, "CloseRangeEnhanced");
|
|
DeleteLocalObject(OBJECT_SELF, sHenchLastTarget);
|
|
DeleteLocalLocation(OBJECT_SELF, sHenchLastAttackLocation);
|
|
DeleteLocalInt(OBJECT_SELF, sHenchShouldIAttackMessageGiven);
|
|
}
|
|
|
|
|
|
void ReportUnseenAllies()
|
|
{
|
|
location testTargetLoc = GetLocation(OBJECT_SELF);
|
|
object oAllyTest = GetFirstObjectInShape(SHAPE_SPHERE, 20.0, testTargetLoc, TRUE, OBJECT_TYPE_CREATURE);
|
|
while (GetIsObjectValid(oAllyTest))
|
|
{
|
|
if (!GetObjectSeen(oAllyTest) && GetIsPC(GetTopMaster(oAllyTest)))
|
|
{
|
|
SpeakString(sHenchCantSeeTarget + GetName(oAllyTest));
|
|
}
|
|
oAllyTest = GetNextObjectInShape(SHAPE_SPHERE, 20.0, testTargetLoc, TRUE, OBJECT_TYPE_CREATURE);
|
|
}
|
|
}
|