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

428 lines
15 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Associate: Heartbeat
//:: NW_CH_AC1.nss
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Move towards master or wait for him
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Nov 21, 2001
//:://////////////////////////////////////////////
#include "hench_i0_act"
#include "hench_i0_ai"
#include "hench_i0_assoc"
#include "x2_inc_summscale"
#include "x2_inc_spellhook"
#include "x0_inc_henai"
void TestItemProperties()
{
Jug_Debug(GetName(OBJECT_SELF) + " checking properties");
int i;
itemproperty oProp;
for (i = 0; i < NUM_INVENTORY_SLOTS; i++)
{
object oItem = GetItemInSlot(i, OBJECT_SELF);
if (GetIsObjectValid(oItem))
{
Jug_Debug("Checking item slot " + IntToString(i));
oProp = GetFirstItemProperty(oItem);
while (GetIsItemPropertyValid(oProp))
{
Jug_Debug("prop type " + IntToString(GetItemPropertyType(oProp)) + " duration " + IntToString(GetItemPropertyDurationType(oProp)) + " sub type " + IntToString(GetItemPropertySubType(oProp)) + " cost table " + IntToString(GetItemPropertyCostTable(oProp)) + " cost table value " + IntToString(GetItemPropertyCostTableValue(oProp)));
oProp = GetNextItemProperty(oItem);
}
}
}
}
int FindCategoryBest(object oTarget, int nCategory, int nCurSpellCount)
{
// really want arrays
int spell1, spell2, spell3;
int spell1Repeat, spell2Repeat, spell3Repeat;
int spell1Feat, spell2Feat, spell3Feat;
int spellsFound;
Jug_Debug(GetName(OBJECT_SELF) + " searching category " + IntToString(nCategory));
int nTry;
while (nTry < 10)
{
talent tBest = GetCreatureTalentRandom(nCategory, oTarget);
if(!GetIsTalentValid(tBest))
{
break;
}
int nNewSpellID = GetIdFromTalent(tBest);
int nType = GetTypeFromTalent(tBest);
// Jug_Debug(GetName(OBJECT_SELF) + " test talent " + IntToString(nType) + " " + IntToString(nNewSpellID));
if (spellsFound == 0)
{
Jug_Debug(GetName(OBJECT_SELF) + " found talent " + IntToString(nType) + " " + IntToString(nNewSpellID));
spell1 = nNewSpellID;
spell1Feat = nType;
spellsFound ++;
}
else if (spellsFound == 1)
{
if (spell1 == nNewSpellID && spell1Feat == nType)
{
spell1Repeat ++;
if (spell1Repeat > 2)
{
break;
}
}
else
{
Jug_Debug(GetName(OBJECT_SELF) + " found talent " + IntToString(nType) + " " + IntToString(nNewSpellID));
spell2 = nNewSpellID;
spell2Feat = nType;
spellsFound ++;
}
}
else if (spellsFound == 2)
{
if (spell1 == nNewSpellID && spell1Feat == nType)
{
spell1Repeat ++;
if (spell1Repeat > 2)
{
break;
}
}
else if (spell2 == nNewSpellID && spell2Feat == nType)
{
spell2Repeat ++;
if (spell2Repeat > 2)
{
break;
}
}
else
{
Jug_Debug(GetName(OBJECT_SELF) + " found talent " + IntToString(nType) + " " + IntToString(nNewSpellID));
spell3 = nNewSpellID;
spell3Feat = nType;
spellsFound ++;
}
// at most three
break;
}
nTry ++;
}
return spellsFound;
}
void TestSpells()
{
// if (!GetHasEffect(EFFECT_TYPE_ABILITY_DECREASE))
// {
// effect eDrain = EffectAbilityDecrease(ABILITY_CHARISMA, 10);
// ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDrain, OBJECT_SELF);
// }
// RemoveEffects(OBJECT_SELF);
Jug_Debug(GetName(OBJECT_SELF) + " has 6 spell " + IntToString(GetHasSpell(SPELL_CHAIN_LIGHTNING)));
Jug_Debug(GetName(OBJECT_SELF) + " has 5 spell " + IntToString(GetHasSpell(SPELL_CONE_OF_COLD)));
Jug_Debug(GetName(OBJECT_SELF) + " has 4 spell " + IntToString(GetHasSpell(SPELL_ICE_STORM)));
Jug_Debug(GetName(OBJECT_SELF) + " has 3 spell " + IntToString(GetHasSpell(SPELL_FIREBALL)));
Jug_Debug(GetName(OBJECT_SELF) + " has 2 spell " + IntToString(GetHasSpell(SPELL_BULLS_STRENGTH)));
Jug_Debug(GetName(OBJECT_SELF) + " has 1 spell " + IntToString(GetHasSpell(SPELL_BURNING_HANDS)));
Jug_Debug(GetName(OBJECT_SELF) + " has 0 spell " + IntToString(GetHasSpell(SPELL_DAZE)));
}
void TestSpells2()
{
Jug_Debug(GetName(OBJECT_SELF) + " has 4 spell " + IntToString(GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS)) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_CURE_CRITICAL_WOUNDS))));
Jug_Debug(GetName(OBJECT_SELF) + " has 3 spell " + IntToString(GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS)) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_CURE_SERIOUS_WOUNDS))));
Jug_Debug(GetName(OBJECT_SELF) + " has 2 spell " + IntToString(GetHasSpell(SPELL_CURE_MODERATE_WOUNDS)) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_CURE_MODERATE_WOUNDS))));
Jug_Debug(GetName(OBJECT_SELF) + " has 1 spell " + IntToString(GetHasSpell(SPELL_CURE_LIGHT_WOUNDS)) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_CURE_LIGHT_WOUNDS))));
Jug_Debug(GetName(OBJECT_SELF) + " has 0 spell " + IntToString(GetHasSpell(SPELL_CURE_MINOR_WOUNDS)) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_CURE_MINOR_WOUNDS))));
}
void TestSpells3()
{
Jug_Debug(GetName(OBJECT_SELF) + " has prot vs evil " + IntToString(GetHasSpell(SPELL_PROTECTION_FROM_EVIL)));
Jug_Debug(GetName(OBJECT_SELF) + " has prot vs good " + IntToString(GetHasSpell(SPELL_PROTECTION_FROM_GOOD)));
Jug_Debug(GetName(OBJECT_SELF) + " has propt vs align " + IntToString(GetHasSpell(321)));
Jug_Debug(GetName(OBJECT_SELF) + " has gate " + IntToString(GetHasSpell(SPELL_GATE)));
Jug_Debug(GetName(OBJECT_SELF) + " check spell id " + IntToString(GetCreatureHasTalent(TalentSpell(SPELL_PROTECTION_FROM_EVIL))));
Jug_Debug(GetName(OBJECT_SELF) + " check main spell id " + IntToString(GetCreatureHasTalent(TalentSpell(321))));
}
void GetBestItemSpells()
{
object oTarget = GetMaster();
if (!GetIsObjectValid(oTarget))
{
return;
}
oTarget = OBJECT_SELF;
// check if already silenced
int nAlreadySilenced = GetHasEffect(EFFECT_TYPE_SILENCE);
if (!nAlreadySilenced)
{
// ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectSilence(), oTarget);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneImmobilize(), oTarget);
// ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectParalyze(), OBJECT_SELF);
}
int nStep;
for (nStep = 0; nStep <= 22; nStep++)
{
FindCategoryBest(oTarget, nStep, 0);
}
if (!nAlreadySilenced)
{
effect eSilence = GetFirstEffect(oTarget);
while(GetIsEffectValid(eSilence))
{
if(GetEffectType(eSilence) == EFFECT_TYPE_CUTSCENEIMMOBILIZE)
{
RemoveEffect(oTarget, eSilence);
// break;
}
eSilence = GetNextEffect(oTarget);
}
}
}
void main()
{
// GetBestItemSpells();
// if (GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD)))
// {
// Jug_Debug("*****" + GetName(OBJECT_SELF) + " heartbeat action " + IntToString(GetCurrentAction()));
// }
// if (GetIsObjectValid(GetMaster()))
// {
// TestItemProperties();
// Jug_Debug(GetName(OBJECT_SELF) + " challenge rating is " + FloatToString(GetChallengeRating(OBJECT_SELF)));
// Jug_Debug(GetName(GetMaster()) + " challenge rating is " + FloatToString(GetChallengeRating(GetMaster())));
// }
// TestSpells();
// TestSpells2();
// TestSpells3();
DeleteLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_RUN_STATE);
object oRealMaster = GetRealMaster();
// destory self if pseudo summons and master not valid
if (GetLocalInt(OBJECT_SELF, sHenchPseudoSummon))
{
oRealMaster = GetLocalObject(OBJECT_SELF, sHenchPseudoSummon);
if (!GetIsObjectValid(oRealMaster))
{
DestroyObject(OBJECT_SELF, 0.1);
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_UNSUMMON), GetLocation(OBJECT_SELF));
return;
}
}
// GZ: Fallback for timing issue sometimes preventing epic summoned creatures from leveling up to their master's level.
// There is a timing issue with the GetMaster() function not returning the fof a creature
// immediately after spawn. Some code which might appear to make no sense has been added
// to the nw_ch_ac1 and x2_inc_summon files to work around this
// This code is only run at the first hearbeat
int nLevel = SSMGetSummonFailedLevelUp(OBJECT_SELF);
if (nLevel != 0)
{
int nRet;
if (nLevel == -1) // special shadowlord treatment
{
SSMScaleEpicShadowLord(OBJECT_SELF);
}
else if (nLevel == -2)
{
SSMScaleEpicFiendishServant(OBJECT_SELF);
}
else
{
nRet = SSMLevelUpCreature(OBJECT_SELF, nLevel, CLASS_TYPE_INVALID);
if (nRet == FALSE)
{
WriteTimestampedLogEntry("WARNING - nw_ch_ac1:: could not level up " + GetTag(OBJECT_SELF) + "!");
}
}
// regardless if the actual levelup worked, we give up here, because we do not
// want to run through this script more than once.
SSMSetSummonLevelUpOK(OBJECT_SELF);
}
// Check if concentration is required to maintain this creature
X2DoBreakConcentrationCheck();
// * if I am dominated, ask for some help
// TK removed SendForHelp
// if (GetHasEffect(EFFECT_TYPE_DOMINATED, OBJECT_SELF) == TRUE && GetIsEncounterCreature(OBJECT_SELF) == FALSE)
// {
// SendForHelp();
// }
// restore associate settings
HenchGetDefSettings();
if(GetAssociateState(NW_ASC_IS_BUSY))
{
return;
}
int iAmNotDoingAnything = GetIAmNotDoingAnything();
if (!iAmNotDoingAnything)
{
return;
}
if (!GetIsObjectValid(oRealMaster))
{
return;
}
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
{
if (HenchGetIsEnemyPerceived())
{
HenchDetermineCombatRound();
return;
}
if (GetLocalInt(OBJECT_SELF, sHenchLastHeardOrSeen))
{
// continue to move to target
MoveToLastSeenOrHeard(FALSE);
return;
}
}
if ((GetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER") != OBJECT_INVALID)
&& (GetLocalInt(OBJECT_SELF, "haveCheckedFM") != 1))
{
// Auldar: For a little OnHeartbeat efficiency, I'll set a localint so we don't
// keep checking stealth mode etc. This will be cleared in NW_CH_JOIN, as will
// the LocalObject for NW_L_FORMERMASTER.
// A little quirk with this behaviour - the ActionUseSkill's do not execute until the henchman rejoins
// however if the player re-loads, or leaves the area and returns, the henchman will no longer be in stealth etc.
// I couldn't find any way around that odd behaviour, but this works for the most part.
SetLocalInt(OBJECT_SELF, "haveCheckedFM", 1);
SetAssociateState(NW_ASC_AGGRESSIVE_SEARCH, FALSE);
SetLocalInt(OBJECT_SELF, sHenchStealthMode, 0);
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE);
SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, FALSE);
}
// Check to see if should re-enter stealth mode
int nStealth = GetLocalInt(GetTopAssociate(), sHenchStealthMode);
if (nStealth == 1 || nStealth == 2)
{
if(!GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH))
{
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
}
}
else
{
if(!GetActionMode(oRealMaster, ACTION_MODE_STEALTH))
{
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE);
}
}
CleanCombatVars();
if (GetLocalInt(OBJECT_SELF, henchHealCountStr))
{
ExecuteScript("hench_o0_heal", OBJECT_SELF);
return;
}
if (GetLocalInt(OBJECT_SELF, henchBuffCountStr))
{
ActionDoCommand(ActionWait(2.0));
ActionDoCommand(ExecuteScript("hench_o0_enhanc", OBJECT_SELF));
return;
}
if (HenchCheckArea())
{
return;
}
// Pausanias: Hench tends to get stuck on follow.
if (GetCurrentAction(OBJECT_SELF) == ACTION_FOLLOW)
{
if (GetDistanceToObject(oRealMaster) >= 2.2 &&
GetAssociateState(NW_ASC_DISTANCE_2_METERS)) return;
if (GetDistanceToObject(oRealMaster) >= 4.2 &&
GetAssociateState(NW_ASC_DISTANCE_4_METERS)) return;
if (GetDistanceToObject(oRealMaster) >= 6.2 &&
GetAssociateState(NW_ASC_DISTANCE_6_METERS)) return;
ClearAllActions();
}
if (GetLocalInt(OBJECT_SELF,"SwitchedToMelee") &&
GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
{
ClearAllActions();
ClearWeaponStates();
HenchEquipDefaultWeapons(OBJECT_SELF, TRUE);
return;
}
int bIsScouting = GetLocalInt(OBJECT_SELF, sHenchScoutingFlag);
if (bIsScouting)
{
if (GetDistanceToObject(oRealMaster) < 6.0)
{
SpeakString(sHenchGetOutofWay);
}
object oScoutTarget = GetLocalObject(OBJECT_SELF, sHenchScoutTarget);
if (GetDistanceBetween(oScoutTarget, oRealMaster) > henchMaxScoutDistance)
{
DeleteLocalInt(OBJECT_SELF, sHenchScoutingFlag);
bIsScouting = FALSE;
}
else
{
if (CheckStealth() && !GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH))
{
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
}
ActionMoveToObject(oScoutTarget, FALSE, 1.0);
}
}
if(!bIsScouting && !GetAssociateState(NW_ASC_MODE_STAND_GROUND) &&
(GetAssociateState(NW_ASC_HAVE_MASTER) && !GetIsFighting(OBJECT_SELF) &&
GetDistanceToObject(oRealMaster) > GetFollowDistance()))
{
ClearAllActions();
ActionForceFollowObject(oRealMaster, GetFollowDistance());
}
if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
{
SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_HEARTBEAT));
}
}