Added PnP Dire Rat.
Added PnP Dire Rat.
This commit is contained in:
995
nwn_dark_sun/hench_i0_ai.nss
Normal file
995
nwn_dark_sun/hench_i0_ai.nss
Normal file
@@ -0,0 +1,995 @@
|
||||
/*
|
||||
|
||||
Henchman Inventory And Battle AI
|
||||
|
||||
This file contains functions used in the default On* scripts
|
||||
for combat. It acts as filter preventing the main hench_o0_ai
|
||||
from being called more than it needs to. (Usually only to start
|
||||
combat, heartbeat, or end combat round.)
|
||||
|
||||
*/
|
||||
|
||||
#include "hench_i0_generic"
|
||||
#include "hench_i0_melee"
|
||||
|
||||
|
||||
// void main() { }
|
||||
|
||||
|
||||
// Sets the location of an unheard or unseen enemy
|
||||
// Either moved out of range or did attack while not detected
|
||||
void SetEnemyLocation(object oEnemy);
|
||||
|
||||
// Clears the last unheard, unseen enemy location
|
||||
void ClearEnemyLocation();
|
||||
|
||||
// Moves to the last perceived enemy location
|
||||
void MoveToLastSeenOrHeard(int bDoSearch = TRUE);
|
||||
|
||||
// New determinecombatround call. Determines if call should cause
|
||||
// main AI script to run
|
||||
void HenchDetermineCombatRound(object oIntruder = OBJECT_INVALID, int bForceInterrupt = FALSE);
|
||||
|
||||
// Simplified combat start, used by commoners
|
||||
void HenchStartAttack(object oIntruder);
|
||||
|
||||
// modified TalentFlee routine
|
||||
int HenchTalentFlee(object oIntruder = OBJECT_INVALID);
|
||||
|
||||
// modified GetNearestSeenOrHeardEnemy to not get dead creatures
|
||||
object GetNearestSeenOrHeardEnemyNotDead(int bCheckIsPC = FALSE);
|
||||
|
||||
// modified DetermineSpecialBehavior, calls HenchDetermineCombatRound instead
|
||||
void HenchDetermineSpecialBehavior(object oIntruder = OBJECT_INVALID);
|
||||
|
||||
// used to attack non creature items (placeables and doors)
|
||||
void HenchAttackObject(object oTarget);
|
||||
|
||||
// associate (henchman, etc.) determines if enemy is perceived or not
|
||||
int HenchGetIsEnemyPerceived();
|
||||
|
||||
// modified TalentAdvancedBuff routine
|
||||
int HenchTalentAdvancedBuff(float fDistance);
|
||||
|
||||
// get nearest ally that is higher in hit dice
|
||||
object GetNearestTougherFriend(object oSelf, object oPC);
|
||||
|
||||
// main stealth and wandering code
|
||||
int DoStealthAndWander();
|
||||
|
||||
// checks if stealth should be removed because you or nearby friend has been detected
|
||||
void CheckRemoveStealth();
|
||||
|
||||
// code for bashing placeables
|
||||
int HenchBashDoorCheck(int bPolymorphed);
|
||||
|
||||
|
||||
const int HENCH_AI_SCRIPT_NOT_RUN = 0;
|
||||
const int HENCH_AI_SCRIPT_IN_PROGRESS = 1;
|
||||
const int HENCH_AI_SCRIPT_ALREADY_RUN = 2;
|
||||
|
||||
const string HENCH_AI_SCRIPT_RUN_STATE = "AIIntruder";
|
||||
const string HENCH_AI_SCRIPT_FORCE = "AIIntruderForce";
|
||||
const string HENCH_AI_SCRIPT_INTRUDER_OBJ = "AIIntruderObj";
|
||||
|
||||
const string sHenchLastHeardOrSeen = "LastSeenOrHeard";
|
||||
|
||||
|
||||
void SetEnemyLocation(object oEnemy)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, sHenchLastHeardOrSeen, TRUE);
|
||||
|
||||
location enemyLocation = GetLocation(oEnemy);
|
||||
SetLocalLocation(OBJECT_SELF, sHenchLastHeardOrSeen, enemyLocation);
|
||||
|
||||
// Get the area, position and facing
|
||||
object oArea = GetAreaFromLocation (enemyLocation);
|
||||
vector vPosition = GetPositionFromLocation (enemyLocation);
|
||||
float fFacing = GetFacingFromLocation (enemyLocation);
|
||||
|
||||
vPosition.z += 100.0;
|
||||
|
||||
// Build a new location, which faces in the opposite direction
|
||||
enemyLocation = Location (oArea, vPosition, fFacing);
|
||||
// make sure old position is gone
|
||||
object oInvisTarget = GetLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
if (GetIsObjectValid(oInvisTarget))
|
||||
{
|
||||
DestroyObject(oInvisTarget);
|
||||
DeleteLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
}
|
||||
|
||||
oInvisTarget = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_invisobj", enemyLocation);
|
||||
SetLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen, oInvisTarget);
|
||||
}
|
||||
|
||||
|
||||
void ClearEnemyLocation()
|
||||
{
|
||||
DeleteLocalInt(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
DeleteLocalLocation(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
|
||||
object oInvisTarget = GetLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
if (GetIsObjectValid(oInvisTarget))
|
||||
{
|
||||
DestroyObject(oInvisTarget);
|
||||
DeleteLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MoveToLastSeenOrHeard(int bDoSearch = TRUE)
|
||||
{
|
||||
location moveToLoc = GetLocalLocation(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
if (GetDistanceBetweenLocations(GetLocation(OBJECT_SELF), moveToLoc) <= 5.0)
|
||||
{
|
||||
ClearEnemyLocation();
|
||||
// go to search
|
||||
// TODO add spells to help search
|
||||
DeleteLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_RUN_STATE);
|
||||
if (bDoSearch)
|
||||
{
|
||||
// search around for awhile
|
||||
ActionDoCommand(SetActionMode(OBJECT_SELF, ACTION_MODE_DETECT, TRUE));
|
||||
ActionRandomWalk();
|
||||
DelayCommand(10.0, HenchDetermineCombatRound());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
object oInvisTarget = GetLocalObject(OBJECT_SELF, sHenchLastHeardOrSeen);
|
||||
ActionMoveToObject(oInvisTarget, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HenchDetermineCombatRound(object oIntruder = OBJECT_INVALID, int bForceInterrupt = FALSE)
|
||||
{
|
||||
// Jug_Debug(GetName(OBJECT_SELF) + " det com round called with " + GetName(oIntruder) + " force = " + IntToString(bForceInterrupt));
|
||||
|
||||
if(GetAssociateState(NW_ASC_IS_BUSY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string sAIScript = GetLocalString(OBJECT_SELF, "AIScript");
|
||||
if (sAIScript == "")
|
||||
{
|
||||
sAIScript = "hench_o0_ai";
|
||||
}
|
||||
|
||||
SetLocalObject(OBJECT_SELF, HENCH_AI_SCRIPT_INTRUDER_OBJ, oIntruder);
|
||||
SetLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_FORCE, bForceInterrupt);
|
||||
|
||||
if (bForceInterrupt)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_RUN_STATE, HENCH_AI_SCRIPT_IN_PROGRESS);
|
||||
ExecuteScript(sAIScript, OBJECT_SELF);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we have to actually determine to rerun ai
|
||||
int iAIIntruderLevel = GetLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_RUN_STATE);
|
||||
|
||||
if (iAIIntruderLevel == HENCH_AI_SCRIPT_NOT_RUN)
|
||||
{
|
||||
// first run of HenchDetermineCombatRound
|
||||
SetLocalInt(OBJECT_SELF, HENCH_AI_SCRIPT_RUN_STATE, HENCH_AI_SCRIPT_IN_PROGRESS);
|
||||
ExecuteScript(sAIScript, OBJECT_SELF);
|
||||
return;
|
||||
}
|
||||
object oLastTarget = GetLocalObject(OBJECT_SELF, sHenchLastTarget);
|
||||
|
||||
if(!GetIsObjectValid(oLastTarget) || GetIsDead(oLastTarget) || !GetIsEnemy(oLastTarget) || GetLocalInt(oLastTarget, sHenchRunningAway))
|
||||
{
|
||||
oLastTarget = OBJECT_INVALID;
|
||||
}
|
||||
else if (!GetObjectSeen(oLastTarget) && !GetObjectHeard(oLastTarget))
|
||||
{
|
||||
oLastTarget = OBJECT_INVALID;
|
||||
}
|
||||
if (!GetIsObjectValid(oLastTarget))
|
||||
{
|
||||
// prevent too many calls to main script if already moving to an unseen and
|
||||
// unheard monster
|
||||
if (!GetLocalInt(OBJECT_SELF, sHenchLastHeardOrSeen) || GetObjectSeen(oIntruder) || GetObjectHeard(oIntruder))
|
||||
{
|
||||
ExecuteScript(sAIScript, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
else if (GetIsObjectValid(oIntruder))
|
||||
{
|
||||
if (GetDistanceToObject(oIntruder) <= 5.0 && GetDistanceToObject(oLastTarget) > 5.0)
|
||||
{
|
||||
ExecuteScript(sAIScript, OBJECT_SELF);
|
||||
}
|
||||
else if (GetObjectSeen(oIntruder) && !GetObjectSeen(oLastTarget))
|
||||
{
|
||||
ExecuteScript(sAIScript, OBJECT_SELF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HenchStartAttack(object oIntruder)
|
||||
{
|
||||
SetLocalObject(OBJECT_SELF, HENCH_AI_SCRIPT_INTRUDER_OBJ, oIntruder);
|
||||
ExecuteScript("hench_o0_att", OBJECT_SELF);
|
||||
}
|
||||
|
||||
|
||||
// FLEE COMBAT AND HOSTILES
|
||||
int HenchTalentFlee(object oIntruder = OBJECT_INVALID)
|
||||
{
|
||||
object oTarget = oIntruder;
|
||||
if(!GetIsObjectValid(oIntruder))
|
||||
{
|
||||
oTarget = GetLastHostileActor();
|
||||
if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget))
|
||||
{
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
|
||||
float fDist = GetDistanceBetween(OBJECT_SELF, oTarget);
|
||||
if(!GetIsObjectValid(oTarget))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
ClearAllActions();
|
||||
//Look at this to remove the delay
|
||||
ActionMoveAwayFromObject(oTarget, TRUE, 10.0f);
|
||||
DelayCommand(4.0, ClearAllActions());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
object GetNearestSeenOrHeardEnemyNotDead(int bCheckIsPC = FALSE)
|
||||
{
|
||||
int curCount = 1;
|
||||
object oTarget;
|
||||
while (1)
|
||||
{
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, curCount, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if (!GetIsObjectValid(oTarget))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!GetPlotFlag(oTarget))
|
||||
{
|
||||
return oTarget;
|
||||
}
|
||||
curCount ++;
|
||||
}
|
||||
curCount = 1;
|
||||
while (1)
|
||||
{
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, curCount, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if (!GetIsObjectValid(oTarget))
|
||||
{
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
if (!GetPlotFlag(oTarget) && !(bCheckIsPC && GetIsPC(GetTopMaster(oTarget))))
|
||||
{
|
||||
return oTarget;
|
||||
}
|
||||
curCount++;
|
||||
}
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Determine Special Behavior
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Determines the special behavior used by the NPC.
|
||||
Generally all NPCs who you want to behave differently
|
||||
than the default behavior.
|
||||
For these behaviors, passing in a valid object will
|
||||
cause the creature to become hostile the the attacker.
|
||||
|
||||
MODIFIED February 7 2003:
|
||||
- Rearranged logic order a little so that the creatures
|
||||
will actually randomwalk when not fighting
|
||||
|
||||
- Modified by Tony K to call HenchDetermineCombatRound
|
||||
|
||||
- Modified by LoCash (Jan 12-Mar 06 2004):
|
||||
BW's original function was completely broken, it needed
|
||||
to be re-written. original code by "fendis_khan".
|
||||
many enhancements made. herbivores now work
|
||||
"out of the box" as they should, omnivores need faction
|
||||
changed to a non-Hostile. Check "Animals" in the Toolset's
|
||||
Monster palette for various examples of creatures using
|
||||
omnivore, herbivore spawn scripts.
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
//:: Created On: Dec 14, 2001
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
void HenchDetermineSpecialBehavior(object oIntruder = OBJECT_INVALID)
|
||||
{
|
||||
object oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, 1,
|
||||
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
||||
|
||||
// Omnivore behavior routine
|
||||
if(GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE))
|
||||
{
|
||||
// no current attacker and not currently in combat
|
||||
if(!GetIsObjectValid(oIntruder) && !GetIsInCombat())
|
||||
{
|
||||
// does not have a current target
|
||||
if(!GetIsObjectValid(GetAttemptedAttackTarget()) &&
|
||||
!GetIsObjectValid(GetAttemptedSpellTarget()) &&
|
||||
!GetIsObjectValid(GetAttackTarget()))
|
||||
{
|
||||
// enemy creature nearby
|
||||
if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 13.0)
|
||||
{
|
||||
ClearAllActions();
|
||||
HenchDetermineCombatRound(oTarget);
|
||||
return;
|
||||
}
|
||||
int nTarget = 1;
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, nTarget,
|
||||
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL);
|
||||
|
||||
// neutral creature, too close
|
||||
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 7.0)
|
||||
{
|
||||
if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0 && GetAssociateType(oTarget) != ASSOCIATE_TYPE_ANIMALCOMPANION)
|
||||
{
|
||||
// oTarget has neutral reputation, and is NOT a druid or ranger or an "Animal Companion"
|
||||
SetLocalInt(OBJECT_SELF, "lcTempEnemy", 8);
|
||||
SetIsTemporaryEnemy(oTarget);
|
||||
ClearAllActions();
|
||||
HenchDetermineCombatRound(oTarget);
|
||||
return;
|
||||
}
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, ++nTarget,
|
||||
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL);
|
||||
}
|
||||
|
||||
// non friend creature, too close
|
||||
nTarget = 1;
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN, OBJECT_SELF, nTarget);
|
||||
|
||||
// heard neutral or enemy creature, too close
|
||||
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 7.0)
|
||||
{
|
||||
if(!GetIsFriend(oTarget) && GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0 && GetAssociateType(oTarget) != ASSOCIATE_TYPE_ANIMALCOMPANION)
|
||||
{
|
||||
// oTarget has neutral reputation, and is NOT a druid or ranger or an "Animal Companion"
|
||||
SetLocalInt(OBJECT_SELF, "lcTempEnemy", 8);
|
||||
SetIsTemporaryEnemy(oTarget);
|
||||
ClearAllActions();
|
||||
HenchDetermineCombatRound(oTarget);
|
||||
return;
|
||||
}
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN, OBJECT_SELF, ++nTarget);
|
||||
}
|
||||
|
||||
if(!IsInConversation(OBJECT_SELF))
|
||||
{
|
||||
// 25% chance of just standing around instead of constantly
|
||||
// randWalking; i thought it looked odd seeing the animal(s)
|
||||
// in a constant state of movement, was not realistic,
|
||||
// at least according to my Nat'l Geographic videos
|
||||
if ( (d4() != 1) && (GetCurrentAction() == ACTION_RANDOMWALK) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ( (d4() == 1) && (GetCurrentAction() == ACTION_RANDOMWALK) )
|
||||
{
|
||||
ClearAllActions();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearAllActions();
|
||||
ActionRandomWalk();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!IsInConversation(OBJECT_SELF)) // enter combat when attacked
|
||||
{
|
||||
// after a while (20-25 seconds), omnivore (boar) "gives up"
|
||||
// chasing someone who didn't hurt it. but if the person fought back
|
||||
// this condition won't run and the boar will fight to death
|
||||
if(GetLocalInt(OBJECT_SELF, "lcTempEnemy") != FALSE && (GetLastDamager() == OBJECT_INVALID || GetLastDamager() != oTarget) )
|
||||
{
|
||||
int nPatience = GetLocalInt(OBJECT_SELF, "lcTempEnemy");
|
||||
if (nPatience <= 1)
|
||||
{
|
||||
ClearAllActions();
|
||||
ClearPersonalReputation(oTarget); // reset reputation
|
||||
DeleteLocalInt(OBJECT_SELF, "lcTempEnemy");
|
||||
return;
|
||||
}
|
||||
SetLocalInt(OBJECT_SELF, "lcTempEnemy", --nPatience);
|
||||
}
|
||||
ClearAllActions();
|
||||
HenchDetermineCombatRound(oIntruder);
|
||||
}
|
||||
}
|
||||
|
||||
// Herbivore behavior routine
|
||||
else if(GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
|
||||
{
|
||||
// no current attacker & not currently in combat
|
||||
if(!GetIsObjectValid(oIntruder) && (GetIsInCombat() == FALSE))
|
||||
{
|
||||
if(!GetIsObjectValid(GetAttemptedAttackTarget()) && // does not have a current target
|
||||
!GetIsObjectValid(GetAttemptedSpellTarget()) &&
|
||||
!GetIsObjectValid(GetAttackTarget()))
|
||||
{
|
||||
if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 13.0) // enemy creature, too close
|
||||
{
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromObject(oTarget, TRUE, 16.0); // flee from enemy
|
||||
return;
|
||||
}
|
||||
int nTarget = 1;
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, nTarget,
|
||||
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL);
|
||||
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 7.0) // only consider close creatures
|
||||
{
|
||||
if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0 && GetAssociateType(oTarget) != ASSOCIATE_TYPE_ANIMALCOMPANION)
|
||||
{
|
||||
// oTarget has neutral reputation, and is NOT a druid or ranger or Animal Companion
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromObject(oTarget, TRUE, 16.0); // run away
|
||||
return;
|
||||
}
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, OBJECT_SELF, ++nTarget,
|
||||
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_NEUTRAL);
|
||||
}
|
||||
nTarget = 1;
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN, OBJECT_SELF, nTarget);
|
||||
while(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 7.0) // only consider close creatures
|
||||
{
|
||||
if(!GetIsFriend(oTarget) && GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0 && GetAssociateType(oTarget) != ASSOCIATE_TYPE_ANIMALCOMPANION)
|
||||
{
|
||||
// oTarget has neutral reputation, and is NOT a druid or ranger or Animal Companion
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromObject(oTarget, TRUE, 16.0); // run away
|
||||
return;
|
||||
}
|
||||
oTarget = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN, OBJECT_SELF, ++nTarget);
|
||||
}
|
||||
if(!IsInConversation(OBJECT_SELF))
|
||||
{
|
||||
|
||||
// 75% chance of randomWalking around, 25% chance of just standing there. more realistic
|
||||
if ( (d4() != 1) && (GetCurrentAction() == ACTION_RANDOMWALK) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ( (d4() == 1) && (GetCurrentAction() == ACTION_RANDOMWALK) )
|
||||
{
|
||||
ClearAllActions();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearAllActions();
|
||||
ActionRandomWalk();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!IsInConversation(OBJECT_SELF)) // NEW BEHAVIOR - run away when attacked
|
||||
{
|
||||
ClearAllActions();
|
||||
ActionMoveAwayFromLocation(GetLocation(OBJECT_SELF), TRUE, 16.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HenchAttackObject(object oTarget)
|
||||
{
|
||||
if (GetWeaponRanged(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND)))
|
||||
{
|
||||
UseCombatAttack(oTarget);
|
||||
}
|
||||
else if(GetHasFeat(FEAT_IMPROVED_POWER_ATTACK))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_IMPROVED_POWER_ATTACK);
|
||||
}
|
||||
else if(GetHasFeat(FEAT_POWER_ATTACK))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_POWER_ATTACK);
|
||||
}
|
||||
else if(GetHasFeat(FEAT_DIRTY_FIGHTING))
|
||||
{
|
||||
UseCombatAttack(oTarget, FEAT_DIRTY_FIGHTING);
|
||||
}
|
||||
else
|
||||
{
|
||||
UseCombatAttack(oTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int HenchGetIsEnemyPerceived()
|
||||
{
|
||||
object oClosestSeen = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
|
||||
OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN,
|
||||
CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
|
||||
if (GetIsObjectValid(oClosestSeen))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
object oClosestHeard = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
|
||||
OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD_AND_NOT_SEEN,
|
||||
CREATURE_TYPE_IS_ALIVE, TRUE);
|
||||
if (GetIsObjectValid(oClosestHeard))
|
||||
{
|
||||
if (GetDistanceToObject(oClosestHeard) <= fHenchHearingDistance)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
object oRealMaster = GetRealMaster();
|
||||
if (GetIsObjectValid(oRealMaster))
|
||||
{
|
||||
if (GetDistanceBetween(oRealMaster, oClosestHeard) <= fHenchMasterHearingDistance)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// FAST BUFF SELF
|
||||
int HenchTalentAdvancedBuff(float fDistance)
|
||||
{
|
||||
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
||||
if(GetIsObjectValid(oPC) && GetDistanceToObject(oPC) <= fDistance)
|
||||
{
|
||||
if(!GetIsFighting(OBJECT_SELF))
|
||||
{
|
||||
ClearAllActions();
|
||||
//Combat Protections
|
||||
if(GetHasSpell(SPELL_PREMONITION))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_PREMONITION, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_GREATER_STONESKIN))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_GREATER_STONESKIN, OBJECT_SELF, METAMAGIC_NONE, 0, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_STONESKIN))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_STONESKIN, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
//Visage Protections
|
||||
if(GetHasSpell(SPELL_SHADOW_SHIELD))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_SHADOW_SHIELD, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_ETHEREAL_VISAGE))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_ETHEREAL_VISAGE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_GHOSTLY_VISAGE))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_GHOSTLY_VISAGE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
//Mantle Protections
|
||||
if(GetHasSpell(SPELL_GREATER_SPELL_MANTLE))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_GREATER_SPELL_MANTLE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SPELL_MANTLE))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_SPELL_MANTLE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_LESSER_SPELL_BREACH))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_LESSER_SPELL_BREACH, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
// Globes
|
||||
if(GetHasSpell(SPELL_GLOBE_OF_INVULNERABILITY))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
|
||||
//Misc Protections
|
||||
if(GetHasSpell(SPELL_ELEMENTAL_SHIELD))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_ELEMENTAL_SHIELD, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if (GetHasSpell(SPELL_MESTILS_ACID_SHEATH)&& !GetHasSpellEffect(SPELL_MESTILS_ACID_SHEATH))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_MESTILS_ACID_SHEATH, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if (GetHasSpell(SPELL_DEATH_ARMOR)&& !GetHasSpellEffect(SPELL_DEATH_ARMOR))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_DEATH_ARMOR, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
|
||||
//Elemental Protections
|
||||
if(GetHasSpell(SPELL_PROTECTION_FROM_ELEMENTS))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_PROTECTION_FROM_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_RESIST_ELEMENTS))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_RESIST_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_ENDURE_ELEMENTS))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_ENDURE_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
|
||||
//Mental Protections
|
||||
if(GetHasSpell(SPELL_MIND_BLANK))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_MIND_BLANK, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_LESSER_MIND_BLANK))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_LESSER_MIND_BLANK, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_CLARITY))
|
||||
{
|
||||
ActionCastSpellAtObject(SPELL_CLARITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
//Summon Ally
|
||||
// TODO add gate!!!!
|
||||
if(GetHasSpell(SPELL_BLACK_BLADE_OF_DISASTER))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_BLACK_BLADE_OF_DISASTER, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_ELEMENTAL_SWARM))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_ELEMENTAL_SWARM, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_IX))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_IX, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_CREATE_GREATER_UNDEAD))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_CREATE_GREATER_UNDEAD, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_GREATER_PLANAR_BINDING))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_GREATER_PLANAR_BINDING, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VIII))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VIII, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_MORDENKAINENS_SWORD))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_MORDENKAINENS_SWORD, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VII))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VII, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_CREATE_UNDEAD))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_CREATE_UNDEAD, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_PLANAR_BINDING))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_PLANAR_BINDING, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VI))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VI, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_V))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_V, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELLABILITY_SUMMON_SLAAD))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELLABILITY_SUMMON_SLAAD, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELLABILITY_SUMMON_TANARRI))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELLABILITY_SUMMON_TANARRI, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELLABILITY_SUMMON_MEPHIT))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELLABILITY_SUMMON_MEPHIT, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELLABILITY_SUMMON_CELESTIAL))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELLABILITY_SUMMON_CELESTIAL, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_ANIMATE_DEAD))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_ANIMATE_DEAD, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_IV))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_IV, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_III))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_III, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_II))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_II, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
else if(GetHasSpell(SPELL_SUMMON_CREATURE_I))
|
||||
{
|
||||
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_I, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
object GetNearestTougherFriend(object oSelf, object oPC)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
object oFriend = oSelf;
|
||||
|
||||
int nEqual = 0;
|
||||
int nNear = 0;
|
||||
while (GetIsObjectValid(oFriend))
|
||||
{
|
||||
if (GetDistanceBetween(oSelf, oFriend) < 40.0 && oFriend != oSelf)
|
||||
{
|
||||
++nNear;
|
||||
if (GetHitDice(oFriend) > GetHitDice(oSelf))
|
||||
return oFriend;
|
||||
if (GetHitDice(oFriend) == GetHitDice(oSelf))
|
||||
++nEqual;
|
||||
}
|
||||
++i;
|
||||
oFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,
|
||||
oSelf, i);
|
||||
}
|
||||
|
||||
SetLocalInt(OBJECT_SELF,"LocalBoss",FALSE);
|
||||
if (nEqual == 0)
|
||||
if (nNear > 0 || GetHitDice(oPC) - GetHitDice(OBJECT_SELF) < 2)
|
||||
{
|
||||
SetLocalInt(OBJECT_SELF,"LocalBoss",TRUE);
|
||||
}
|
||||
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
|
||||
// Auldar: Configurable distance at which to "hide", if the PC, or PC's Associate is within that distance.
|
||||
// TK 40 doesn't seem to be far enough
|
||||
const float stealthDistThresh = 80.0;
|
||||
|
||||
// Pausanias: monsters try to find you.
|
||||
int DoStealthAndWander()
|
||||
{
|
||||
if (GetPlotFlag(OBJECT_SELF))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
int nStealthAndWander = GetMonsterOptions(HENCH_MONAI_STEALTH | HENCH_MONAI_WANDER);
|
||||
if (!nStealthAndWander)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Auldar: and they now stealth if they have some skill points (and not marked with plot flag)
|
||||
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
|
||||
object oNearestHostile = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
|
||||
|
||||
if (!(GetIsObjectValid(oNearestHostile) && GetIsObjectValid(oPC) && GetIsEnemy(oPC)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int bActionsCleared = FALSE;
|
||||
if ((nStealthAndWander & HENCH_MONAI_STEALTH) && !GetPlotFlag(OBJECT_SELF) &&
|
||||
!GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH))
|
||||
{
|
||||
// Auldar: Checking if the NPC is hostile to the PC and has skill points in Hide
|
||||
// or move silently, and it not marked Plot. If so, go stealthy even if not flagged
|
||||
// by the module creator as Stealth on spawn, as long as the PC or associate is hostile and close.
|
||||
if (CheckStealth())
|
||||
{
|
||||
// Auldar: Check how far away the nearest hostile Creature is
|
||||
float enemyDistance = GetDistanceToObject(oNearestHostile);
|
||||
|
||||
// Auldar: and check if it's a PC, or a PC's associate.
|
||||
object oRealHostileMaster = GetRealMaster(oNearestHostile);
|
||||
if (((oPC == oNearestHostile) || (GetIsObjectValid(oRealHostileMaster)
|
||||
&& GetIsPC(oRealHostileMaster) && GetIsEnemy(oRealHostileMaster)))
|
||||
&& (enemyDistance <= stealthDistThresh) && (enemyDistance != -1.0))
|
||||
{
|
||||
ClearAllActions();
|
||||
bActionsCleared = TRUE;
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
|
||||
}
|
||||
}
|
||||
// Auldar: here ends Auldar's NPC stealth code. Back to Paus' work :)
|
||||
}
|
||||
// Auldar: Reducing the distance from 40.0 to 25.0 to reduce the "bloodbath" effect
|
||||
// requested by FoxBat.
|
||||
if ((nStealthAndWander & HENCH_MONAI_WANDER) && GetDistanceToObject(oPC) < 25.0)
|
||||
{
|
||||
int ScoutMode = GetLocalInt(OBJECT_SELF,"ScoutMode");
|
||||
if (ScoutMode == 0)
|
||||
{
|
||||
ScoutMode = d2();
|
||||
SetLocalInt(OBJECT_SELF,"ScoutMode",ScoutMode);
|
||||
}
|
||||
object oTarget = GetNearestTougherFriend(OBJECT_SELF,oPC);
|
||||
if (!GetLocalInt(OBJECT_SELF,"LocalBoss"))
|
||||
{
|
||||
int fDist = 15;
|
||||
if (!GetIsObjectValid(oTarget) || ScoutMode == 1)
|
||||
{
|
||||
fDist = 10;
|
||||
oTarget = oPC;
|
||||
if (d10() > 5) fDist = 25;
|
||||
}
|
||||
|
||||
location lNew;
|
||||
if (GetLocalInt(OBJECT_SELF,"OpenedDoor"))
|
||||
{
|
||||
lNew = GetLocalLocation(OBJECT_SELF,"ScoutZone");
|
||||
SetLocalInt(OBJECT_SELF,"OpenedDoor",FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
vector vLoc = GetPosition(oTarget);
|
||||
vLoc.x += fDist-IntToFloat(Random(2*fDist+1));
|
||||
vLoc.y += fDist-IntToFloat(Random(2*fDist+1));
|
||||
vLoc.z += fDist-IntToFloat(Random(2*fDist+1));
|
||||
lNew = Location(GetArea(oTarget),vLoc,0.);
|
||||
SetLocalLocation(OBJECT_SELF,"ScoutZone",lNew);
|
||||
}
|
||||
if (!bActionsCleared)
|
||||
{
|
||||
ClearAllActions();
|
||||
}
|
||||
ActionMoveToLocation(lNew);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void CheckRemoveStealth()
|
||||
{
|
||||
if (GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH))
|
||||
{
|
||||
int iCheckStealthAmount = GetSkillRank(SKILL_HIDE) + GetSkillRank(SKILL_MOVE_SILENTLY) + 5;
|
||||
|
||||
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, FALSE);
|
||||
|
||||
location testLocation = GetLocation(OBJECT_SELF);
|
||||
|
||||
object oCreature = GetFirstObjectInShape(SHAPE_SPHERE, 15.0, testLocation, TRUE);
|
||||
while(GetIsObjectValid(oCreature))
|
||||
{
|
||||
if (GetActionMode(oCreature, ACTION_MODE_STEALTH) &&
|
||||
GetIsFriend(oCreature) &&
|
||||
!GetIsPC(oCreature))
|
||||
{
|
||||
if (GetSkillRank(SKILL_HIDE, oCreature) + GetSkillRank(SKILL_MOVE_SILENTLY, oCreature) <= iCheckStealthAmount)
|
||||
{
|
||||
// Jug_Debug(GetName(OBJECT_SELF) + " turning off stealth for + " + GetName(oCreature));
|
||||
SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE);
|
||||
}
|
||||
}
|
||||
oCreature = GetNextObjectInShape(SHAPE_SPHERE, 15.0, testLocation, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Pausanias's version of the last: float GetEnemyChallenge()
|
||||
// My forumla: Total Challenge of Enemy = log ( Sum (2**challenge) )
|
||||
// Auldar: Changed to 1.5 at Paus' request to better mirror the 3E DMG
|
||||
float GetEnemyChallenge(object oRelativeTo=OBJECT_SELF)
|
||||
{
|
||||
float fChallenge = 0.;
|
||||
|
||||
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 20.0, GetLocation(OBJECT_SELF), TRUE);
|
||||
while(GetIsObjectValid(oTarget))
|
||||
{
|
||||
if (GetIsEnemy(oTarget))
|
||||
{
|
||||
if (GetObjectSeen(oTarget) || GetObjectHeard(oTarget))
|
||||
{
|
||||
// if (!GetIsDisabled(oTarget))
|
||||
{
|
||||
fChallenge += pow(1.5, GetChallengeRating(oTarget));
|
||||
}
|
||||
}
|
||||
}
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 20.0, GetLocation(OBJECT_SELF), TRUE);
|
||||
}
|
||||
return (log(fChallenge)/log(1.5)) - (IntToFloat(GetHitDice(oRelativeTo)) * HENCH_HITDICE_TO_CR);
|
||||
}
|
||||
|
||||
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Bash Doors
|
||||
//:: Copyright (c) 2002 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Used in DetermineCombatRound to keep a
|
||||
henchmen bashing doors.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
//:: Created On: April 4, 2002
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
int HenchBashDoorCheck(int bPolymorphed)
|
||||
{
|
||||
int bDoor = FALSE;
|
||||
//This code is here to make sure that henchmen keep bashing doors and placeables.
|
||||
object oDoor = GetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH");
|
||||
|
||||
if(GetIsObjectValid(oDoor))
|
||||
{
|
||||
int nDoorMax = GetMaxHitPoints(oDoor);
|
||||
int nDoorNow = GetCurrentHitPoints(oDoor);
|
||||
int nCnt = GetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP");
|
||||
if(GetLocked(oDoor) || GetIsTrapped(oDoor))
|
||||
{
|
||||
if(nDoorMax == nDoorNow)
|
||||
{
|
||||
nCnt++;
|
||||
SetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP", nCnt);
|
||||
}
|
||||
if(nCnt <= 2)
|
||||
{
|
||||
bDoor = TRUE;
|
||||
HenchAttackObject(oDoor);
|
||||
}
|
||||
}
|
||||
if(!bDoor)
|
||||
{
|
||||
DeleteLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH");
|
||||
DeleteLocalInt(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH_HP");
|
||||
VoiceCuss();
|
||||
ActionDoCommand(HenchEquipDefaultWeapons());
|
||||
}
|
||||
}
|
||||
return bDoor;
|
||||
}
|
||||
|
||||
|
||||
void HenchStartRangedBashDoor(object oDoor)
|
||||
{
|
||||
ActionEquipMostDamagingRanged(oDoor);
|
||||
if (GetDistanceToObject(oDoor) < 5.0)
|
||||
{
|
||||
ActionMoveAwayFromObject(oDoor, FALSE, 5.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ActionWait(0.5);
|
||||
}
|
||||
ActionAttack(oDoor);
|
||||
SetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH", oDoor);
|
||||
}
|
Reference in New Issue
Block a user