TheHordeOrcs_PRC8/_module/nss/0i_associates.nss
Jaysyn904 0e9e2c6950 2025/07/18 Update
Added PEPS.
Full compile.
2025-07-18 12:13:13 -04:00

2193 lines
108 KiB
Plaintext

/*//////////////////////////////////////////////////////////////////////////////
Script: 0i_associates
Programmer: Philos
////////////////////////////////////////////////////////////////////////////////
Scripts used for Associates.
*///////////////////////////////////////////////////////////////////////////////
#include "0i_actions"
#include "nw_inc_gff"
// Return TRUE if oCreature can attack based on current modes and actions.
int ai_CanIAttack(object oCreature);
// Returns the nearest locked object from oMaster.
object ai_GetNearestLockedObject(object oCreature);
// Will look for the oTarget or go to the oSpeaker depending on the situation.
void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMonster);
// Selects the correct response base on nCommand from oCommander.
// These are given from either a radial menu option or voice command.
void ai_SelectAssociateCommand(object oCreature, object oCommander, int nCommand);
// Set nAction for the caller to pass to their associates. i.e. For henchmans summons.
void ai_PassActionToAssociates(object oCreature, int nAction, int bStatus = TRUE);
// Set Set the AI Mode to oAssociate and their associates.
void ai_PassAIModeToAssociates(object oAssociate, int nAIMode, int bStatus = TRUE);
// Set oCreature's ai scripts based on its first class or the variable "AI_DEFAULT_SCRIPT".
// bSetBasicAIScript set to TRUE will skip defensive and ambush tactic type scripts.
void ai_SetAssociateAIScript(object oCreature, int bCheckTacticScripts = TRUE);
// Returns TRUE if oCreature can speak.
int ai_CanISpeak(object oCreature);
// Cleansup any henchman actions and then removes them from the PC's faction.
void ai_FireHenchman(object oPC, object oHenchman);
// Will cast defensive spells (Buffs) on oPC's party from oCreature.
void ai_HenchmanCastDefensiveSpells(object oCreature, object oPC);
// Returns TRUE if we are starting combat due to an enemy being near.
// This should be checked after any "is in combat" checks.
int ai_CheckForCombat(object oCreature, int bMonster);
// Checks all perceived creatures to see if we should calculate a combat round
// or start combat for Associates.
void ai_AssociateEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception);
// Checks all perceived creatures to see if we should calculate a combat round
// or start combat for Monsters.
void ai_MonsterEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception);
// Copies all int, float, and string variables from oOldObject to oNewObject.
void ai_CopyObjectVariables(object oOldObject, object oNewObject);
//******************************************************************************
//********************* Creature event scripts *********************************
//******************************************************************************
// Add to nw_ch_aca OnRested event script of henchman.
void ai_OnRested(object oCreature);
//******************************************************************************
//******************* Associate AI option scripts ******************************
//******************************************************************************
// Increments/Decrements the following distance of associates.
void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Turns on/off Ranged combat for oAssociate.
void ai_Ranged(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Ignore enemy associates for oAssociate.
void ai_Ignore_Associates(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Ignore floor traps for oAssociate.
void ai_Ignore_Traps(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Search for oAssociate.
void ai_Search(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Stealth for oAssociate.
void ai_Stealth(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Open Doors for oAssociate.
void ai_OpenDoor(object oPC, object oAssociate, string sAssociateType);
// Turns on/off Picking/Bashing locks for oAssociate.
void ai_Locks(object oPC, object oAssociate, string sAssociateType, int nMode);
// Turns on/off Disarming of Traps for oAssociate.
void ai_Traps(object oPC, object oAssociate, string sAssociateType);
// Turns on/off the amount of speaking for oAssociate.
void ai_ReduceSpeech(object oPC, object oAssociate, string sAssociateType);
// Turns on/off use of offensive/defensive spells.
void ai_UseOffensiveMagic(object oPC, object oAssociate, int bDefensive, int bOffensive, string sAssociateType);
// Turns on/off magic use.
void ai_UseMagic(object oPC, object oAssociate, string sAssociateType);
// Turn Magic Item use on/off for oAssociates.
void ai_UseMagicItems(object oPC, object oAssociate, string sAssociateType);
// Adjusts loot options for oAssociate
void ai_Loot(object oPC, object oAssociate, string sAssociateType);
// Adjust loot options for oAssociate
void ai_Spontaneous(object oPC, object oAssociate, string sAssociateType);
// Increments/Decrements the magic use variable for the AI.
void ai_MagicIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType);
// Increments/Decrements the Loot Range use variable for the AI.
void ai_LootRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Increments/Decrements the Lock Range use variable for the AI.
void ai_LockRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Increments/Decrements the Trap Range use variable for the AI.
void ai_TrapRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Increments/Decrements the Open Door Range use variable for the AI.
void ai_OpenDoorIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType);
// Saves a new AI script for oAssociate.
void ai_SaveAIScript(object oPC, object oAssociate, int nToken);
// Button action for buffing a PC.
void ai_Buff_Button(object oPC, object oAssociate, int nOption, string sAssociateType);
// Button action for setting healing ranges.
void ai_Heal_Button(object oPC, object oAssociate, int nIncrement, string sVar, string sAssociateType);
// Button action for turning healing on/off.
void ai_Heal_OnOff(object oPC, object oAssociate, string sAssociateType, int nMode);
// Button action for selecting a target to follow.
void ai_FollowTarget(object oPC, object oAssociate);
// Code to make oCreature guard oMaster.
void ai_Philos_Guard(object oMaster, object oCreature);
// Code to make OBJECT_SELF follow oMaster.
void ai_Philos_Follow(object oMaster);
// Code to make OBJECT_SELF hold at their location.
void ai_Philos_StandGround(object oMaster);
// Code to make oCreature attack the nearest enemy.
void ai_Philos_AttackNearest(object oMaster, object oCreature);
// Code to make oCreature turn search mode on.
void ai_Philos_SetSearch(object oMaster, object oCreature, string sAssociateType, int bTurnOn);
// Code to make oCreature turn stealth mode on.
void ai_Philos_SetStealth(object oMaster, object oCreature, string sAssociateType, int bTurnOn);
// Button action for giving commands to associates.
void ai_DoCommand(object oPC, object oAssociate, int nCommand);
// Button action to have associate do an action based on the target via OnPlayer Target event.
void ai_Action(object oPC, object oAssociate);
// Toggles between normal ai script and special tactic ai scripts.
void ai_AIScript(object oPC, object oAssociate, string sAssociate, int nToken);
// Has the PC select a Trap and then place it on the ground from an associate.
void ai_HavePCPlaceTrap(object oPC, object oAssociate);
// Jumps oAssociate to oPC, if oPC == oAssociate it jumps all oAssocites to oPC.
void ai_JumpToPC(object oPC, object oAssociate);
// Allow oAssociate to use no clipping.
void ai_GhostMode(object oPC, object oAssociate, int nToken, string sAssociateType);
// Changes the camera view from either the player to the associate or back.
void ai_ChangeCameraView(object oPC, object oAssociate);
// Checks that the oAssociate is within sight and then opens the inventory.
void ai_OpenInventory(object oAssociate, object oPC);
// Executes an installed plugin.
void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0);
int ai_CanIAttack(object oCreature)
{
if(AI_DEBUG) ai_Debug("0i_associate", "122", "Can I attack? Hold mode: " +
IntToString(ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND)) +
" Follow mode: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_FOLLOW)) +
" Action (19/4): " + IntToString(GetCurrentAction(oCreature)));
if(ai_GetIsCharacter(oCreature)) return TRUE;
int nAction = GetCurrentAction(oCreature);
return (!ai_GetAIMode(oCreature, AI_MODE_STAND_GROUND) &&
!ai_GetAIMode(oCreature, AI_MODE_FOLLOW) &&
nAction != ACTION_ITEMCASTSPELL &&
nAction != ACTION_CASTSPELL);
}
object ai_GetNearestLockedObject(object oCreature)
{
int nCnt = 1;
object oMaster = GetMaster(oCreature);
float fRange = GetLocalFloat(oCreature, AI_TRAP_CHECK_RANGE);
location lCreature = GetLocation(oCreature);
object oObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, lCreature, nCnt);
while (oObject != OBJECT_INVALID || GetDistanceBetween(oMaster, oObject) > fRange)
{
if(GetLocked(oObject) && ai_GetIsInLineOfSight(oMaster, oObject)) return oObject;
oObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, lCreature, ++nCnt);
}
return OBJECT_INVALID;
}
void ai_FindTheEnemy(object oCreature, object oSpeaker, object oTarget, int bMonster)
{
if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) return;
if(oSpeaker == oTarget && d100() < 34)
{
// Let them know we heard something in the distance!.
if(!ai_GetAIMode(oCreature, AI_MODE_DO_NOT_SPEAK))
{
string sSpeak = "I heard something!";
int nRoll = d8();
if(nRoll == 1) sSpeak = "Did you hear that?";
if(nRoll == 2) sSpeak = "What was that noise?";
if(nRoll == 3) sSpeak = "Something is moving.";
if(nRoll == 4) sSpeak = "Lookout! I heard a noise.";
if(nRoll == 5) sSpeak = "Listen! We have company.";
AssignCommand(oCreature, ai_HaveCreatureSpeak(oCreature, 0, sSpeak));
}
ai_HaveCreatureSpeak(oCreature, 8, ":43:6:9:10:23:42:");
}
if(GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_a_peaceful" ||
GetLocalString(oCreature, AI_COMBAT_SCRIPT) == "ai_coward") return;
float fDistance, fPerceptionDistance;
if(bMonster)
{
// Check distance from the creature hearing this and the target.
fDistance = GetDistanceBetween(oCreature, oTarget);
fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE);
}
else
{
// We want to use the distance between the PC and target not us.
fDistance = GetDistanceBetween(GetMaster(), oTarget);
fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE);
}
if(AI_DEBUG) ai_Debug("0i_associates", "175", " fDistance: " + FloatToString(fDistance, 0, 2) +
" fPerceptionDistance: " + FloatToString(fPerceptionDistance, 0, 2) +
" Hiding? " + IntToString(GetStealthMode(oTarget)));
if(fDistance <= fPerceptionDistance)
{
SetLocalInt(oCreature, AI_AM_I_SEARCHING, TRUE);
if(LineOfSightObject(oCreature, oTarget))
{
if(fDistance > AI_RANGE_CLOSE)
{
int bMoveForward = TRUE;
// We check this because if the enemy is moving or has not
// started acting then we don't want to move up on them as they
// might move towards us! Just attack! Only sneak attack if they are busy.
int nAction = GetCurrentAction(oTarget);
if(AI_DEBUG) ai_Debug("0i_associates", "189", GetName(oTarget) + " current action: " + IntToString(nAction));
if(nAction == ACTION_MOVETOPOINT ||
nAction == ACTION_INVALID ||
nAction == ACTION_RANDOMWALK) bMoveForward = FALSE;
// If they are attacking make sure it is in melee?
// If not then don't move since they might be moving toward us.
if(nAction == ACTION_ATTACKOBJECT)
{
if(!ai_GetNumOfEnemiesInRange(oTarget)) bMoveForward = FALSE;
}
if(bMoveForward)
{
if(AI_DEBUG) ai_Debug("0i_associates", "201", "Running towards combat to engage " + GetName(oTarget));
ActionMoveToObject(oTarget, TRUE, AI_RANGE_CLOSE);
AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)));
return;
}
if(AI_DEBUG) ai_Debug("0i_associates", "207", "Searching for " + GetName(oTarget) + " while moving towards " + GetName(oSpeaker));
SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE);
ActionMoveToObject(oSpeaker);
return;
}
if(AI_DEBUG) ai_Debug("0i_associates", "176", "Moving and searching for " + GetName(oTarget));
SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE);
ActionMoveToLocation(GetLocation(oTarget), FALSE);
//ActionMoveToObject(oTarget, FALSE, AI_RANGE_MELEE);
AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)));
return;
}
if(AI_DEBUG) ai_Debug("0i_associates", "218", "No line of sight for " + GetName(oTarget) + ". Moving towards " + GetName(oSpeaker));
ActionMoveToObject(oSpeaker, TRUE);
AssignCommand(oCreature, ActionDoCommand(DeleteLocalInt(oCreature, AI_AM_I_SEARCHING)));
}
}
void ai_ReactToAssociate(object oCreature, object oCommander, int bMonster)
{
object oTarget = GetLocalObject(oCommander, AI_MY_TARGET);
if (oTarget == OBJECT_INVALID) return;
if(ai_GetIsInCombat(oCreature))
{
if(oCommander == GetMaster(oCreature) && ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER))
{
ai_DoAssociateCombatRound(oCreature, oTarget);
}
else ai_DoAssociateCombatRound(oCreature);
return;
}
ai_FindTheEnemy(oCreature, oCommander, oTarget, bMonster);
}
void ai_SelectAssociateCommand(object oCreature, object oCommander, int nCommand)
{
object oMaster = GetMaster(oCreature);
// These nCommands can be issued even when the caller is busy.
switch(nCommand)
{
// Master is being attacked by the enemy.
case ASSOCIATE_COMMAND_MASTERGOINGTOBEATTACKED:
{
object oAttacker = GetGoingToBeAttackedBy(oMaster);
if(AI_DEBUG) ai_Debug("0i_associate", "120", GetName(oMaster) + " has been attack by " +
GetName(GetGoingToBeAttackedBy(oMaster)) + "!");
// Used to set who monsters are attacking.
int nAction = GetCurrentAction(oAttacker);
if(nAction == ACTION_ATTACKOBJECT) SetLocalObject(oAttacker, AI_ATTACKED_PHYSICAL, oMaster);
else if(nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL)
{
SetLocalObject(oAttacker, AI_ATTACKED_SPELL, oMaster);
}
if(!ai_GetIsBusy(oCreature) && ai_CanIAttack(oCreature))
{
if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound(oCreature);
else ai_FindTheEnemy(oCreature, oCommander, oAttacker, FALSE);
}
return;
}
// Menu used by a player to have the henchman follow them.
case ASSOCIATE_COMMAND_FOLLOWMASTER:
{
if(AI_DEBUG) ai_Debug("0i_associate", "135", GetName(oMaster) + " has commanded " +
GetName(oCreature) + " to FOLLOW.");
AssignCommand(oCreature, ai_Philos_Follow(oMaster));
return;
}
// Menu used by a player to have the henchman go into NORMAL MODE.
// We also attack the nearest, this keeps henchman going into combat quickly.
case ASSOCIATE_COMMAND_ATTACKNEAREST:
{
if(AI_DEBUG) ai_Debug("0i_associates", "158", GetName(oMaster) + " has commanded " +
GetName(oCreature) + " to attack nearest(NORMAL MODE).");
ai_Philos_AttackNearest(oMaster, oCreature);
return;
}
// Menu used by a player to have the henchman stay where they are standing.
case ASSOCIATE_COMMAND_STANDGROUND:
{
if(AI_DEBUG) ai_Debug("0i_associate", "189", GetName(oMaster) + " has commanded " +
GetName(OBJECT_SELF) + " to STANDGROUND.");
AssignCommand(oCreature, ai_Philos_StandGround(oMaster));
return;
}
// Menu used by a player to have the henchman attack anyone who attacks them.
case ASSOCIATE_COMMAND_GUARDMASTER:
{
if(AI_DEBUG) ai_Debug("0i_associate", "211", GetName(oMaster) + " has commanded " +
GetName(oCreature) + " to GAURDMASTER.");
ai_Philos_Guard(oMaster, oCreature);
return;
}
// Menu used by a player to have the henchman heal them as soon as possible.
case ASSOCIATE_COMMAND_HEALMASTER:
{
// Player will be stuck with this variable if they are not using the AI.
DeleteLocalInt(oCommander, "AI_I_AM_BEING_HEALED");
if(ai_GetIsInCombat(oCreature)) ai_TryHealingTalent(oCreature, ai_GetNumOfEnemiesInRange(oCreature), oCommander);
else AssignCommand(oCreature, ai_ActionTryHealing(oCreature, oCommander));
return;
}
// Menu used by a player to toggle a henchmans casting options.
case ASSOCIATE_COMMAND_TOGGLECASTING:
{
if(ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC))
{
ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, TRUE);
ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE);
ai_SendMessages(GetName(oCreature) + " will now cast defensive spells only.", AI_COLOR_GRAY, oCommander);
}
else if(ai_GetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING))
{
ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, TRUE);
ai_SendMessages(GetName(oCreature) + " will now cast offensive spells only.", AI_COLOR_GRAY, oCommander);
}
else if(ai_GetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING))
{
ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE);
ai_SendMessages(GetName(oCreature) + " will now cast any spell.", AI_COLOR_GRAY, oCommander);
}
else
{
ai_SetMagicMode(oCreature, AI_MAGIC_NO_MAGIC, TRUE);
ai_SetMagicMode(oCreature, AI_MAGIC_DEFENSIVE_CASTING, FALSE);
ai_SetMagicMode(oCreature, AI_MAGIC_OFFENSIVE_CASTING, FALSE);
ai_SendMessages(GetName(oCreature) + " will not use any magic.", AI_COLOR_GRAY, oCommander);
}
aiSaveAssociateModesToDb(oMaster, oCreature);
return;
}
}
// If we are busy then these nCommands are ignored.
if(!ai_GetIsBusy(oCreature))
{
// Respond to shouts from friendly non-PCs only.
if (ai_CanIAttack(oCreature))
{
if(nCommand == AI_ALLY_IS_WOUNDED)
{
if(ai_TryHealing(oCreature, oCommander)) return;
}
else if(nCommand == AI_ALLY_IS_DISEASED ||
nCommand == AI_ALLY_IS_POISONED ||
nCommand == AI_ALLY_IS_WEAK)
{
if(ai_HealSickness(oCreature, oCommander, oMaster, nCommand)) return;
}
// A friend sees an enemy. If we are not in combat lets seek them out too!
else if(nCommand == AI_ALLY_SEES_AN_ENEMY ||
nCommand == AI_ALLY_HEARD_AN_ENEMY)
{
if(AI_DEBUG) ai_Debug("0i_associates", "282", GetName(oCreature) + " receives notice that " +
GetName(oCommander) + " has seen1/heard2(" + IntToString(nCommand) + " an enemy: " +
GetName(GetLocalObject(oCommander, AI_MY_TARGET)) + "!");
ai_ReactToAssociate(oCreature, oCommander, FALSE);
return;
}
// A friend is in combat. Make some checks to see if we should help.
else if(nCommand == AI_ALLY_ATKED_BY_WEAPON ||
nCommand == AI_ALLY_ATKED_BY_SPELL)
{
if(AI_DEBUG) ai_Debug("0i_associates", "291", GetName(oCreature) + " receives notice that " +
GetName(oCommander) + " was attacked by an enemy!" +
GetName(GetLocalObject(oCommander, AI_MY_TARGET)) + "!");
ai_ReactToAssociate(oCreature, oCommander, FALSE);
return;
}
else if(nCommand == AI_ALLY_IS_DEAD)
{ // Nothing at the moment.
if(AI_DEBUG) ai_Debug("0i_associates", "298", GetName(oCreature) + " receives notice that " +
GetName(oCommander) + " has died!");
return;
}
}
switch(nCommand)
{
case ASSOCIATE_COMMAND_MASTERATTACKEDOTHER:
{
if(AI_DEBUG) ai_Debug("0i_associate", "307", GetName(oMaster) + " has attacked!");
if(ai_CanIAttack(oCreature))
{
if(ai_GetIsInCombat(oCreature)) ai_DoAssociateCombatRound(oCreature);
else ai_FindTheEnemy(oCreature, oCommander, ai_GetAttackedTarget(oCommander, TRUE, TRUE), FALSE);
}
return;
}
// Master tried to open a door or chest that is locked.
case ASSOCIATE_COMMAND_MASTERFAILEDLOCKPICK:
{
// In command mode we let the player tell us what to do.
if(ai_CanIAttack(oCreature))
{
object oLock = ai_GetNearestLockedObject(oMaster);
//Check and see if our master want's us to open locks.
if(ai_GetAIMode(oCreature, AI_MODE_PICK_LOCKS) ||
ai_GetAIMode(oCreature, AI_MODE_BASH_LOCKS))
{
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_AttemptToByPassLock(oCreature, oLock);
}
}
return;
}
// Master saw a trap.
case ASSOCIATE_COMMAND_MASTERSAWTRAP:
{
// In command mode we let the player tell us what to do.
if(ai_CanIAttack(oCreature))
{
object oTrap = GetLastTrapDetected(oMaster);
// Sometimes GetLastTrapDetected seems to fail.
if(oTrap == OBJECT_INVALID) oTrap = GetNearestTrapToObject(oMaster, TRUE);
//Check and see if our master want's us to disarm the trap.
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE);
SetTrapDetectedBy(oTrap, oCreature);
ai_ReactToTrap(oCreature, oTrap);
}
return;
}
// Menu used by a player to toggle henchmans search on and off.
case ASSOCIATE_COMMAND_TOGGLESEARCH:
{
int bTurnOn = !ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH);
string sAssociateType = ai_GetAssociateType(oMaster, oCreature);
ai_Philos_SetSearch(oMaster, oCreature, sAssociateType, bTurnOn);
return;
}
// Menu used by a player to toggle henchmans stealth on and off.
case ASSOCIATE_COMMAND_TOGGLESTEALTH:
{
int bTurnOn = !ai_GetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH);
string sAssociateType = ai_GetAssociateType(oMaster, oCreature);
ai_Philos_SetStealth(oMaster, oCreature, sAssociateType, bTurnOn);
return;
}
// Menu used by a player to have the henchman try to bypass the nearest lock.
case ASSOCIATE_COMMAND_PICKLOCK:
{
ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE);
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_SetAIMode(oCreature, AI_MODE_FOLLOW, FALSE);
object oLock = ai_GetNearestLockedObject(oMaster);
// Clear locked variable incase we tried already.
string sID = ObjectToString(oCreature);
SetLocalInt(oLock, "AI_LOCKED_" + sID, FALSE);
ai_AttemptToByPassLock(oCreature, oLock);
aiSaveAssociateModesToDb(oMaster, oCreature);
return;
}
// Menu used by a player to have the henchman try to disarm the nearest trap.
case ASSOCIATE_COMMAND_DISARMTRAP:
{
ai_SetAIMode(oCreature, AI_MODE_DEFEND_MASTER, FALSE);
ai_SetAIMode(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_SetAIMode(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_SetAIMode(oCreature, AI_MODE_FOLLOW, FALSE);
object oTrap = GetNearestTrapToObject(oMaster);
// Clear trapped variable incase we tried already.
string sID = ObjectToString(oCreature);
ai_ReactToTrap(oCreature, oTrap, TRUE);
aiSaveAssociateModesToDb(oMaster, oCreature);
return;
}
// Menu used by a player to open a henchmans inventory to give, move, or take.
case ASSOCIATE_COMMAND_INVENTORY:
{
if(AI_OPEN_INVENTORY)
{
ai_HaveCreatureSpeak(oCreature, 4, ":29:46:35:");
OpenInventory(oCreature, oCommander);
}
// Can't look at an associate's inventory.
else
{
ai_HaveCreatureSpeak(oCreature, 6, ":47:30:36:8:48:");
ai_SendMessages("You cannot open " + GetName(oCreature) + "'s inventory.", AI_COLOR_GRAY, oMaster);
}
return;
}
case ASSOCIATE_COMMAND_LEAVEPARTY:
{
if(AI_REMOVE_HENCHMAN_ON)
{
ai_ClearCreatureActions();
ai_FireHenchman (GetPCSpeaker(), oCreature);
PlayVoiceChat (VOICE_CHAT_GOODBYE, oCreature);
}
}
}
}
}
void ai_PassActionToAssociates(object oCreature, int nAction, int bStatus = TRUE)
{
int nAssociateType;
object oAssociate;
for(nAssociateType = 2; nAssociateType < 6; nAssociateType ++)
{
oAssociate = GetAssociate(nAssociateType);
if(oAssociate != OBJECT_INVALID) SetActionMode(oAssociate, nAction, bStatus);
}
}
void ai_PassToAssociate(object oAssociate, int nAIMode, int bStatus)
{
ai_ClearCreatureActions(TRUE);
ai_SetAIMode(oAssociate, nAIMode, bStatus);
}
void ai_PassAIModeToAssociates(object oAssociate, int nAIMode, int bStatus = TRUE)
{
ai_SetAIMode(oAssociate, nAIMode, bStatus);
int nAssociateType;
object oAssoc;
for(nAssociateType = 2; nAssociateType < 6; nAssociateType ++)
{
oAssoc = GetAssociate(nAssociateType, oAssociate);
if(oAssoc != OBJECT_INVALID) AssignCommand(oAssoc, ai_PassToAssociate(oAssoc, nAIMode, bStatus));
}
}
void ai_SetAssociateAIScript(object oCreature, int bCheckTacticScripts = TRUE)
{
string sCombatAI;
object oMaster = GetMaster();
if(ai_GetIsCharacter(oMaster))
{
string sAssociateType = ai_GetAssociateType(oMaster, oCreature);
json jAIData = ai_GetAssociateDbJson(oMaster, sAssociateType, "aidata");
sCombatAI = JsonGetString(JsonArrayGet(jAIData, 8));
}
else sCombatAI = GetLocalString(oCreature, AI_DEFAULT_SCRIPT);
int nAssociateType = GetAssociateType(oCreature);
if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR && sCombatAI == "")
{
sCombatAI = "ai_a_default";
}
else if(sCombatAI == "ai_coward")
{
SetLocalString(oCreature, AI_COMBAT_SCRIPT, sCombatAI);
return;
}
else if(bCheckTacticScripts && GetLocalInt(GetModule(), AI_RULE_AMBUSH))
{
// They should have a skill ranks equal to their level + 1 to use a special AI.
int nSkillNeeded = GetHitDice(oCreature) + 1;
if(sCombatAI == "" || sCombatAI == "ai_a_ambusher")
{
// Ambusher: requires either Improved Invisibility or Invisibility.
if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oCreature) ||
GetHasSpell(SPELL_INVISIBILITY, oCreature))
{
int bCast = ai_TryToCastSpell(oCreature, SPELL_IMPROVED_INVISIBILITY, oCreature);
if(!bCast) bCast = ai_TryToCastSpell(oCreature, SPELL_INVISIBILITY, oCreature);
if(bCast)
{
SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_ambusher");
return;
}
}
// Ambusher: Requires a Hide and Move silently skill equal to your level + 1.
else if(GetSkillRank(SKILL_HIDE, oCreature) >= nSkillNeeded &&
GetSkillRank(SKILL_MOVE_SILENTLY, oCreature) >= nSkillNeeded)
{
SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_ambusher");
return;
}
}
// Defensive : requires Parry skill equal to your level or Expertise.
else if(sCombatAI == "ai_a_defensive" ||
(sCombatAI == "" &&
(GetSkillRank(SKILL_PARRY, oCreature) >= nSkillNeeded ||
GetHasFeat(FEAT_EXPERTISE, oCreature) ||
GetHasFeat(FEAT_IMPROVED_EXPERTISE, oCreature))))
{
SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_a_defensive");
return;
}
else if(sCombatAI == "ai_cntrspell" || GetHasSpell(SPELL_LESSER_DISPEL, oCreature) ||
GetHasSpell(SPELL_DISPEL_MAGIC, oCreature) || GetHasSpell(SPELL_GREATER_DISPELLING, oCreature))
{
SetLocalString(oCreature, AI_COMBAT_SCRIPT, "ai_cntrspell");
return;
}
}
if(sCombatAI == "")
{
// Select the best ai for this henchmen based on class.
int nClass = GetClassByPosition(1, oCreature);
// If they have more than one class use the default ai.
if(GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID) sCombatAI = "ai_a_default";
else if(nClass == CLASS_TYPE_BARBARIAN) sCombatAI = "ai_a_barbarian";
else if(nClass == CLASS_TYPE_BARD) sCombatAI = "ai_a_bard";
else if(nClass == CLASS_TYPE_CLERIC) sCombatAI = "ai_a_cleric";
else if(nClass == CLASS_TYPE_DRUID) sCombatAI = "ai_a_druid";
else if(nClass == CLASS_TYPE_FIGHTER) sCombatAI = "ai_a_fighter";
else if(nClass == CLASS_TYPE_MONK) sCombatAI = "ai_a_monk";
else if(nClass == CLASS_TYPE_PALADIN) sCombatAI = "ai_a_paladin";
else if(nClass == CLASS_TYPE_RANGER) sCombatAI = "ai_a_ranger";
else if(nClass == CLASS_TYPE_ROGUE) sCombatAI = "ai_a_rogue";
else if(nClass == CLASS_TYPE_SORCERER) sCombatAI = "ai_a_sorcerer";
else if(nClass == CLASS_TYPE_WIZARD) sCombatAI = "ai_a_wizard";
//else if(nClass == CLASS_TYPE_ABERRATION) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_ANIMAL) sCombatAI = "ai_a_animal";
//else if(nClass == CLASS_TYPE_CONSTRUCT) sCombatAI = "ai_a_animal";
//else if(nClass == CLASS_TYPE_DRAGON) sCombatAI = "ai_a_dragon";
//else if(nClass == CLASS_TYPE_ELEMENTAL) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_FEY) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_GIANT) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_HUMANOID) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_MAGICAL_BEAST) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_MONSTROUS) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_OOZE) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_OUTSIDER) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_UNDEAD) sCombatAI = "ai_a_default";
//else if(nClass == CLASS_TYPE_VERMIN) sCombatAI = "ai_a_animal";
else sCombatAI = "ai_a_default";
}
if(AI_DEBUG) ai_Debug("0i_associates", "530", GetName(oCreature) + " is setting AI to " + sCombatAI);
SetLocalString(oCreature, AI_COMBAT_SCRIPT, sCombatAI);
SetLocalString(oCreature, AI_DEFAULT_SCRIPT, sCombatAI);
}
int ai_CanISpeak (object oCreature)
{
int nRace = GetRacialType (oCreature);
if (nRace == RACIAL_TYPE_ANIMAL || nRace == RACIAL_TYPE_BEAST ||
nRace == RACIAL_TYPE_CONSTRUCT || nRace == RACIAL_TYPE_OOZE) return FALSE;
return (GetAbilityScore (oCreature, ABILITY_INTELLIGENCE) > 7);
}
void ai_FireHenchman(object oPC, object oHenchman)
{
if(oPC == OBJECT_INVALID || oHenchman == OBJECT_INVALID) return;
// Now double-check that this is actually our master
if(GetMaster(oHenchman) != oPC) return;
// Turn off stealth mode
SetActionMode(oHenchman, ACTION_MODE_STEALTH, FALSE);
// Remove the henchman
RemoveHenchman (oPC, oHenchman);
ChangeToStandardFaction(oHenchman, STANDARD_FACTION_DEFENDER);
}
void ai_HenchmanCastDefensiveSpells (object oCreature, object oPC)
{
ai_CastBuffs(oCreature, 3, 0, oPC);
}
int ai_CheckForCombat(object oCreature, int bMonster)
{
object oEnemy = ai_GetNearestEnemy(oCreature, 1, 7, 7, 7, 5, TRUE);
//object oEnemy = ai_GetNearestEnemy(oCreature, 1, -1, -1, -1, -1, TRUE);
if(AI_DEBUG) ai_Debug("0i_associate", "586", "Checking for Combat: oEnemy is " + GetName(oEnemy) +
" Distance: " + FloatToString(GetDistanceBetween(oEnemy, oCreature), 0, 2));
if(oEnemy != OBJECT_INVALID)
{
float fPerceptionDistance, fDistance;
if(bMonster)
{
fDistance = GetDistanceBetween(oCreature, oEnemy);
fPerceptionDistance = GetLocalFloat(GetModule(), AI_RULE_PERCEPTION_DISTANCE);
}
else
{
// We want to use the distance between the PC and target not us.
object oMaster = GetMaster();
if(oMaster != OBJECT_INVALID) fDistance = GetDistanceBetween(oMaster, oEnemy);
else fDistance = GetDistanceBetween(oCreature, oEnemy);
fPerceptionDistance = GetLocalFloat(oCreature, AI_ASSOC_PERCEPTION_DISTANCE);
if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0;
}
if(fDistance < fPerceptionDistance)
{
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
SetLocalObject (oCreature, AI_MY_TARGET, oEnemy);
SpeakString(AI_I_SEE_AN_ENEMY, TALKVOLUME_SILENT_TALK);
if(bMonster) ai_StartMonsterCombat(oCreature);
else if(ai_CanIAttack(oCreature)) ai_StartAssociateCombat(oCreature);
return TRUE;
}
}
return FALSE;
}
void ai_AssociateEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception)
{
if(!ai_CanIAttack(oCreature)) return;
int nAction = GetCurrentAction(oCreature);
if(AI_DEBUG) ai_Debug("0i_associates", "775", "Our current action: " + IntToString(nAction));
switch(nAction)
{
// These actions are uninteruptable.
case ACTION_CASTSPELL :
case ACTION_ITEMCASTSPELL :
case ACTION_COUNTERSPELL : return;
// Might be doing a special action that is not a defined action.
case ACTION_INVALID :
{
int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
if(AI_DEBUG) ai_Debug("0i_associate", "761", "Doing a special action (nCombatWait): " + IntToString(nCombatWait));
if(nCombatWait)
{
if(ai_IsInCombatRound(oCreature, nCombatWait)) return;
DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
}
}
// We need to reevaluate combat during these actions when we see a new enemy.
//case ACTION_ATTACKOBJECT :
//case ACTION_MOVETOPOINT :
}
if(ai_GetIsInCombat(oCreature))
{
object oTarget = ai_GetAttackedTarget(oCreature);
if(AI_DEBUG) ai_Debug("0i_associates", "775", "Should we recalculate our combat round? oTarget: " + GetName(oTarget) +
" oTarget Distance: " + FloatToString(GetDistanceBetween(oCreature, oTarget), 0, 2) +
" oLastPerceived Distance: " + FloatToString(GetDistanceBetween(oCreature, oLastPerceived), 0, 2));
// If the LastPerceived is our target then don't recalculate.
if(oTarget == oLastPerceived) return;
// If we don't have a target or the lastperceived is closer than our
// target then recalculate.
if(oTarget == OBJECT_INVALID ||
GetDistanceBetween(oCreature, oTarget) > GetDistanceBetween(oCreature, oLastPerceived))
{
// We should clear any skill cooldowns that are at at max since that means they were skipped.
if(GetLocalInt(oCreature, "AI_EMPATHY_COOLDOWN") == AI_EMPATHY_COOLDOWN)
{ DeleteLocalInt(oCreature, "AI_EMPATHY_COOLDOWN"); }
else if (GetLocalInt(oCreature, "AI_TAUNT_COOLDOWN") == AI_TAUNT_COOLDOWN)
{ DeleteLocalInt(oCreature, "AI_EMPATHY_COOLDOWN"); }
ai_DoAssociateCombatRound(oCreature);
return;
}
// Lets only reevaluate combat if the new enemy is more powerful
// than the average enemies we already know about.
int nPower = ai_GetCharacterLevels(oLastPerceived) / 2;
int nEnemyPower = GetLocalInt(oCreature, AI_ENEMY_POWER) / (GetLocalInt(oCreature, AI_ENEMY_NUMBERS) + 1);
if(AI_DEBUG) ai_Debug("0i_associates", "797", " Is the new opponent more powerful? " +
GetName(oLastPerceived) + " nPower: " + IntToString(nPower) +
" nEnemyPower: " + IntToString(nEnemyPower));
if(nEnemyPower < nPower) ai_DoAssociateCombatRound(oCreature);
return;
}
// Heard fires first, but Heard and Seen are both set at the same time.
// So lets skip the hearing code if they are also seen.
if(sPerception == AI_I_SEE_AN_ENEMY || GetObjectSeen(oLastPerceived, oCreature))
{
// We are not in combat and we see the enemy so alert our allies!
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
SetLocalObject (oCreature, AI_MY_TARGET, oLastPerceived);
SpeakString(sPerception, TALKVOLUME_SILENT_TALK);
ai_StartAssociateCombat(oCreature);
}
else ai_FindTheEnemy(oCreature, oLastPerceived, oLastPerceived, FALSE);
}
void ai_MonsterEvaluateNewThreat(object oCreature, object oLastPerceived, string sPerception)
{
if(!ai_CanIAttack(oCreature)) return;
int nAction = GetCurrentAction(oCreature);
if(AI_DEBUG) ai_Debug("0i_associates", "672", "nAction: " + IntToString(nAction));
switch(nAction)
{
// These actions are uninteruptable.
case ACTION_CASTSPELL :
case ACTION_ITEMCASTSPELL :
case ACTION_COUNTERSPELL : return;
// Might be doing a special action that is not a defined action.
case ACTION_INVALID :
{
int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
if(AI_DEBUG) ai_Debug("0i_associates", "683", "nCombatWait: " + IntToString(nCombatWait));
if(nCombatWait)
{
if(ai_IsInCombatRound(oCreature, nCombatWait)) return;
DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
}
}
// We need to reevaluate combat during these actions when we see a new enemy.
//case ACTION_ATTACKOBJECT :
//case ACTION_MOVETOPOINT :
}
if(ai_GetIsInCombat(oCreature))
{
object oTarget = ai_GetAttackedTarget(oCreature);
if(AI_DEBUG) ai_Debug("0i_associates", "697", "oTarget: " + GetName(oTarget) +
" oTarget Distance: " + FloatToString(GetDistanceBetween(oCreature, oTarget), 0, 2) +
" oLastPerceived Distance: " + FloatToString(GetDistanceBetween(oCreature, oLastPerceived), 0, 2));
// If the LastPerceived is our target then don't recalculate.
if(oTarget == oLastPerceived) return;
// If we don't have a target or the lastperceived is closer than our
// target then recalculate.
if(oTarget == OBJECT_INVALID ||
GetDistanceBetween(oCreature, oTarget) > GetDistanceBetween(oCreature, oLastPerceived))
{
ai_DoMonsterCombatRound(oCreature);
return;
}
// Now only reevaluate combat if the new enemy is more powerful
// than the average enemies we already know about.
int nPower = ai_GetCharacterLevels(oLastPerceived) / 2;
int nEnemyPower = GetLocalInt(oCreature, AI_ENEMY_POWER) / (GetLocalInt(oCreature, AI_ENEMY_NUMBERS) + 1);
if(AI_DEBUG) ai_Debug("0i_associates", "714", GetName(oLastPerceived) + " nPower: " + IntToString(nPower) +
" nEnemyPower: " + IntToString(nEnemyPower));
if(nEnemyPower < nPower) ai_DoMonsterCombatRound(oCreature);
return;
}
if(sPerception == AI_I_SEE_AN_ENEMY)
{
if(d100() < 34)
{
// We are not in combat so alert our allies!
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
}
SetLocalObject(oCreature, AI_MY_TARGET, oLastPerceived);
SpeakString(sPerception, TALKVOLUME_SILENT_TALK);
ai_StartMonsterCombat(oCreature);
}
else ai_FindTheEnemy(oCreature, oLastPerceived, oLastPerceived, TRUE);
}
void ai_CopyObjectVariables(object oOldObject, object oNewObject)
{
json jObject = ObjectToJson(oOldObject, TRUE);
json jVarTable = GffGetList(jObject, "VarTable");
string sVariable, sName;
int nIndex, nVarType;
json jVar = JsonArrayGet(jVarTable, nIndex);
while(JsonGetType(jVar) != JSON_TYPE_NULL)
{
sName = JsonGetString(GffGetString(jVar, "Name"));
nVarType = JsonGetInt(GffGetDword(jVar, "Type"));
if(nVarType == 1) SetLocalInt(oNewObject, sName, JsonGetInt(GffGetInt(jVar, "Value")));
else if(nVarType == 2) SetLocalFloat(oNewObject, sName, JsonGetFloat(GffGetFloat(jVar, "Value")));
else if(nVarType == 3) SetLocalString(oNewObject, sName, JsonGetString(GffGetString(jVar, "Value")));
jVar = JsonArrayGet(jVarTable, ++nIndex);
}
}
//******************************************************************************
//********************* Creature event scripts *********************************
//******************************************************************************
void ai_OnRested(object oCreature)
{
if(ai_GetMagicMode(oCreature, AI_MAGIC_BUFF_AFTER_REST))
{
int nLevel = ai_GetCharacterLevels(oCreature);
float fDelay = StringToFloat(Get2DAString("restduration", "DURATION", nLevel));
fDelay = (fDelay / 1000.0f) + 2.0f;
DelayCommand(fDelay, ai_HenchmanCastDefensiveSpells(oCreature, GetMaster()));
}
}
//******************************************************************************
//******************* Associate AI option scripts ******************************
//******************************************************************************
void ai_UpdateToolTipUI(object oPC, string sWindowID1, string sWindowID2, string sToolTipBind, string sText)
{
int nMenuToken = NuiFindWindow(oPC, sWindowID1);
if(nMenuToken) NuiSetBind (oPC, nMenuToken, sToolTipBind, JsonString (sText));
if(sWindowID2 != "")
{
int nWidgetToken = NuiFindWindow(oPC, sWindowID2);
if(nWidgetToken) NuiSetBind (oPC, nWidgetToken, sToolTipBind, JsonString (sText));
}
}
void ai_FollowIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_FOLLOW_RANGE) + fIncrement;
if(fAdjustment > 10.0) fAdjustment = 10.0;
else if(fAdjustment < 1.0) fAdjustment = 1.0;
SetLocalFloat(oAssociate, AI_FOLLOW_RANGE, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 6, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sName;
object oTarget = GetLocalObject(oAssociate, AI_FOLLOW_TARGET);
string sTarget;
if(oTarget != OBJECT_INVALID) sTarget = GetName(oTarget);
else
{
if(ai_GetIsCharacter(oAssociate)) sTarget = "nobody";
else sTarget = GetName(oPC);
}
float fRange = fAdjustment +
StringToFloat(Get2DAString("appearance", "PREFATCKDIST", GetAppearanceType(oAssociate)));
string sRange = FloatToString(fRange, 0, 0);
if(oPC == oAssociate)
{
sName = " All associates";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_follow_tooltip", sName + " enter follow mode ");
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]");
}
else
{
sName = " " + GetName(oAssociate);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_follow_tooltip", sName + " enter follow mode [" + sRange + " meters]");
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_follow_target_tooltip", " " + GetName(oAssociate) + " following " + sTarget + " [" + sRange + " meters]");
}
}
void ai_Ranged(object oPC, object oAssociate, string sAssociateType)
{
//ai_ClearCreatureActions();
if(ai_GetAIMode(oAssociate, AI_MODE_STOP_RANGED))
{
ai_SendMessages(GetName(oAssociate) + " is using ranged combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ranged_tooltip", " Ranged On");
ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, FALSE);
ai_EquipBestRangedWeapon(oAssociate);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is using melee combat only.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ranged_tooltip", " Ranged Off");
ai_SetAIMode(oAssociate, AI_MODE_STOP_RANGED, TRUE);
ai_EquipBestMeleeWeapon(oAssociate);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_EquipWeapons(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF))
{
ai_SendMessages(GetName(oAssociate) + " will be equiping their best weapons.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_equip_weapon_tooltip", " Equiping Best Weapons On");
ai_SetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will not equip their best weapons.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_equip_weapon_tooltip", " Equiping Best Weapons Off");
ai_SetAIMode(oAssociate, AI_MODE_EQUIP_WEAPON_OFF, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Search(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH))
{
ai_SendMessages(GetName(oAssociate) + " is turning search off.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode Off");
SetActionMode(oAssociate, ACTION_MODE_DETECT, FALSE);
ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is turning search on.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode On");
SetActionMode(oAssociate, ACTION_MODE_DETECT, TRUE);
ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_SEARCH, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Stealth(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH))
{
ai_SendMessages(GetName(oAssociate) + " is turning stealth off.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode Off");
SetActionMode(oAssociate, ACTION_MODE_STEALTH, FALSE);
ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is turning stealth on.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode On");
SetActionMode(oAssociate, ACTION_MODE_STEALTH, TRUE);
ai_SetAIMode(oAssociate, AI_MODE_AGGRESSIVE_STEALTH, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_OpenDoor(object oPC, object oAssociate, string sAssociateType)
{
string sRange = FloatToString(GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE), 0, 0);
if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS))
{
ai_SendMessages(GetName(oAssociate) + " is turning open doors off.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", " Open Doors Off [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_OPEN_DOORS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is turning open doors on.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", " Open Doors On [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_OPEN_DOORS, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Locks(object oPC, object oAssociate, string sAssociateType, int nMode)
{
string sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE), 0, 0);
if(nMode == 1)
{
if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS))
{
ai_SendMessages(GetName(oAssociate) + " will stop picking locks.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", " Pick Locks Off [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_PICK_LOCKS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will now pick locks.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", " Pick Locks On [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_PICK_LOCKS, TRUE);
}
}
else if(nMode == 2)
{
if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS))
{
ai_SendMessages(GetName(oAssociate) + " will stop bashing.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", " Bash Locks Off [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_BASH_LOCKS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will now bash things.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", " Bash Locks On [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_BASH_LOCKS, TRUE);
}
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Traps(object oPC, object oAssociate, string sAssociateType)
{
string sRange = FloatToString(GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE), 0, 0);
if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS))
{
ai_SendMessages(GetName(oAssociate) + " will stop disarming traps.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", " Disable Traps Off [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_DISARM_TRAPS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will now disarm traps.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", " Disable Traps On [" + sRange + " meters]");
ai_SetAIMode(oAssociate, AI_MODE_DISARM_TRAPS, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_ReduceSpeech(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK))
{
ai_SendMessages(GetName(oAssociate) + " will increase speech.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_quiet_tooltip", " Reduced Speech Off");
ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will reduce speech.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_quiet_tooltip", " Reduced Speech On");
ai_SetAIMode(oAssociate, AI_MODE_DO_NOT_SPEAK, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_UseOffensiveMagic(object oPC, object oAssociate, int bDefensive, int bOffensive, string sAssociateType)
{
if(bOffensive)
{
if(ai_GetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING))
{
ai_SendMessages(GetName(oAssociate) + " has stopped using offensive magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is now using offensive magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic On");
ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, TRUE);
}
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, FALSE);
}
else if(bDefensive)
{
if(ai_GetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING))
{
ai_SendMessages(GetName(oAssociate) + " has stopped using defensive magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " is now using defensive magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_def_magic_tooltip", " Defensive Magic On");
ai_SetMagicMode(oAssociate, AI_MAGIC_DEFENSIVE_CASTING, TRUE);
}
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_off_magic_tooltip", " Offensive Magic Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_OFFENSIVE_CASTING, FALSE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_UseMagic(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC))
{
ai_SendMessages(GetName(oAssociate) + " is now using magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_tooltip", " Magic On");
ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " has stopped using magic in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_tooltip", " Magic Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_UseMagicItems(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS))
{
ai_SendMessages(GetName(oAssociate) + " is now using magic items in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_items_tooltip", " Magic Items On");
ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " has stopped using magic items in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_items_tooltip", " Magic Items Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_NO_MAGIC_ITEMS, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Loot(object oPC, object oAssociate, string sAssociateType)
{
int bLooting = !ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS);
string sRange = FloatToString(GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE), 0, 0);
string sMessage, sText;
if(bLooting)
{
sMessage = " is picking up items.";
sText = " Looting On [" + sRange + " meters]";
}
else
{
sMessage = " is not picking up items.";
sText = " Looting Off [" + sRange + " meters]";
}
ai_SendMessages(GetName(oAssociate) + sMessage, AI_COLOR_YELLOW, oPC);
ai_SetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS, bLooting);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_loot_tooltip", sText);
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Spontaneous(object oPC, object oAssociate, string sAssociateType)
{
int bSpontaneous = !ai_GetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE);
string sMessage, sText;
if(bSpontaneous)
{
sMessage = " has stop casting spontaneous healing spells.";
sText = " Spontaneous casting Off";
}
else
{
sMessage = " will now cast spontaneous healing spells.";
sText = " Spontaneous casting On";
}
ai_SendMessages(GetName(oAssociate) + sMessage, AI_COLOR_YELLOW, oPC);
ai_SetMagicMode(oAssociate, AI_MAGIC_NO_SPONTANEOUS_CURE, bSpontaneous);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_spontaneous_tooltip", sText);
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_MagicIncrement(object oPC, object oAssociate, int nIncrement, string sAssociateType)
{
int nAdjustment = GetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT) + nIncrement;
if(nAdjustment > 100) nAdjustment = 100;
else if(nAdjustment < -100) nAdjustment = -100;
SetLocalInt(oAssociate, AI_DIFFICULTY_ADJUSTMENT, nAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 0, JsonInt(nAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sMagic = IntToString(nAdjustment);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_magic_level_tooltip", " Magic Level [" + sMagic + "]");
}
void ai_LootRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE) + fIncrement;
if(fAdjustment > 40.0) fAdjustment = 40.0;
else if(fAdjustment < 0.0) fAdjustment = 0.0;
SetLocalFloat(oAssociate, AI_LOOT_CHECK_RANGE, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 3, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sRange = FloatToString(fAdjustment, 0, 0);
string sLoot = " Looting Off [" + sRange + " meters]";
if(ai_GetAIMode(oAssociate, AI_MODE_PICKUP_ITEMS)) sLoot = " Looting On [" + sRange + " meters]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_loot_tooltip", sLoot);
}
void ai_LockRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE) + fIncrement;
if(fAdjustment > 40.0) fAdjustment = 40.0;
else if(fAdjustment < 0.0) fAdjustment = 0.0;
SetLocalFloat(oAssociate, AI_LOCK_CHECK_RANGE, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 4, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sRange = FloatToString(fAdjustment, 0, 0);
string sPick = " Pick Locks Off [" + sRange + " meters]";
string sBash = " Bash Off [" + sRange + " meters]";
if(ai_GetAIMode(oAssociate, AI_MODE_PICK_LOCKS)) sPick = " Pick Locks On [" + sRange + " meters]";
if(ai_GetAIMode(oAssociate, AI_MODE_BASH_LOCKS)) sBash = " Bash On [" + sRange + " meters]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_pick_locks_tooltip", sPick);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_bash_locks_tooltip", sBash);
}
void ai_TrapRangeIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE) + fIncrement;
if(fAdjustment > 40.0) fAdjustment = 40.0;
else if(fAdjustment < 0.0) fAdjustment = 0.0;
SetLocalFloat(oAssociate, AI_TRAP_CHECK_RANGE, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 5, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sRange = FloatToString(fAdjustment, 0, 0);
string sText = " Disable Traps Off [" + sRange + " meters]";
if(ai_GetAIMode(oAssociate, AI_MODE_DISARM_TRAPS)) sText = " Disable Traps On [" + sRange + " meters]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_traps_tooltip", sText);
}
void ai_OpenDoorIncrement(object oPC, object oAssociate, float fIncrement, string sAssociateType)
{
float fAdjustment = GetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE) + fIncrement;
if(fAdjustment > 40.0) fAdjustment = 40.0;
else if(fAdjustment < 0.0) fAdjustment = 0.0;
SetLocalFloat(oAssociate, AI_OPEN_DOORS_RANGE, fAdjustment);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
jAIData = JsonArraySet(jAIData, 9, JsonFloat(fAdjustment));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
string sRange = FloatToString(fAdjustment, 0, 0);
string sText = " Open Doors Off [" + sRange + " meters]";
if(ai_GetAIMode(oAssociate, AI_MODE_OPEN_DOORS)) sText = " Open Doors On [" + sRange + " meters]";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_open_door_tooltip", sText);
}
void ai_SaveAIScript(object oPC, object oAssociate, int nToken)
{
string sScript = JsonGetString(NuiGetBind(oPC, nToken, "txt_ai_script"));
string sOldScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT);
if(GetStringLeft(sScript, 5) != "ai_a_") ai_SendMessages(sScript + " does not have correct prefix it must have ai_a_ for associates! Did not change AI script.", AI_COLOR_RED, oPC);
else if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "")
{
ai_SendMessages(sScript + " not found by ResMan! This is not a valid AI script.", AI_COLOR_RED, oPC);
}
else if(sScript != sOldScript)
{
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
string sAssociateType = ai_GetAssociateType(oPC, oAssociate);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
if(JsonGetType(JsonArrayGet(jAIData, 8)) == JSON_TYPE_NULL) jAIData = JsonArrayInsert(jAIData, JsonString(sScript));
else jAIData = JsonArraySet(jAIData, 8, JsonString(sScript));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
ai_SendMessages(GetName(oAssociate) + " is now using " + sScript + " AI script!", AI_COLOR_GREEN, oPC);
}
else ai_SendMessages(GetName(oAssociate) + " is already using this script! Did not change AI script.", AI_COLOR_RED, oPC);
}
void ai_Buff_Button(object oPC, object oAssociate, int nOption, string sAssociateType)
{
if(nOption == 0)
{
int bRestBuff = !ai_GetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST);
ai_SetMagicMode(oAssociate, AI_MAGIC_BUFF_AFTER_REST, bRestBuff);
if(bRestBuff)
{
ai_SendMessages(GetName(oAssociate) + " will cast long buffs after resting.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_buff_rest_tooltip", " [On] Turn buffing after resting off.");
}
else
{
ai_SendMessages(GetName(oAssociate) + " will not cast long buffs after resting.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_buff_rest_tooltip", " [Off] Turn buffing after resting on.");
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
else
{
if(!GetIsPossessedFamiliar(oAssociate))
{
object oEnemy = GetNearestEnemy(oAssociate);
//ai_Debug("0e_nui", "865", "oEnemy: " + GetName(oEnemy) + " fDistance: " +
// FloatToString(GetDistanceBetween(oAssociate, oEnemy), 0, 2));
if(GetDistanceBetween(oAssociate, oEnemy) > 30.0 ||
oEnemy == OBJECT_INVALID)
{
ai_CastBuffs(oAssociate, nOption, 0, oPC);
}
else ai_SendMessages("You cannot buff while there are enemies nearby.", AI_COLOR_RED, oPC);
}
else ai_SendMessages("You cannot buff while possessing your familiar.", AI_COLOR_RED, oPC);
}
}
void ai_Heal_Button(object oPC, object oAssociate, int nIncrement, string sVar, string sAssociateType)
{
int nHeal = GetLocalInt(oAssociate, sVar);
if(nIncrement > 0 && nHeal > 100 - nIncrement) nHeal = 100 - nIncrement;
if(nIncrement < 0 && nHeal < abs(nIncrement)) nHeal = abs(nIncrement);
nHeal += nIncrement;
SetLocalInt(oAssociate, sVar, nHeal);
string sHeal = IntToString(nHeal);
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
if(sVar == AI_HEAL_OUT_OF_COMBAT_LIMIT)
{
string sText = " Will heal at or below [" + sHeal + "%] health out of combat";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heal_out_tooltip", sText);
jAIData = JsonArraySet(jAIData, 1, JsonInt(nHeal));
}
else if(sVar == AI_HEAL_IN_COMBAT_LIMIT)
{
string sText = " Will heal at or below [" + sHeal + "%] health in combat";
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heal_in_tooltip", sText);
jAIData = JsonArraySet(jAIData, 2, JsonInt(nHeal));
}
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
}
void ai_Heal_OnOff(object oPC, object oAssociate, string sAssociateType, int nMode)
{
string sText, sText2;
if(nMode == 1)
{
if(ai_GetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF))
{
ai_SetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF, FALSE);
sText = " Self healing On";
sText2 = " will now use healing on themselves.";
}
else
{
ai_SetAIMode(oAssociate, AI_MODE_SELF_HEALING_OFF, TRUE);
sText = " Self healing Off";
sText2 = " will stop using healing on themselves.";
}
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_heals_onoff_tooltip", sText);
}
else
{
if(ai_GetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF))
{
ai_SetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF, FALSE);
sText = " Party healing On";
sText2 = " will now use healing on party members.";
}
else
{
ai_SetAIMode(oAssociate, AI_MODE_PARTY_HEALING_OFF, TRUE);
sText = " Party healing Off";
sText2 = " will stop using healing on party members.";
}
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_healp_onoff_tooltip", sText);
}
ai_SendMessages(GetName(oAssociate) + sText2, AI_COLOR_YELLOW, oPC);
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Cure_OnOff(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF))
{
ai_SendMessages(GetName(oAssociate) + " will now cast cure spells.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cure_onoff_tooltip", " Cast Cure Spells On");
ai_SetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will stop casting cure spells.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cure_onoff_tooltip", " Cast Cure Spells Off");
ai_SetMagicMode(oAssociate, AI_MAGIC_CURE_SPELLS_OFF, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Ignore_Associates(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES))
{
ai_SendMessages(GetName(oAssociate) + " will stop ignoring henchman's associates and enemy associates.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_assoc_tooltip", " Ignore Enemy Associates Off");
ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will now ignore henchman's associates and enemy associates.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_assoc_tooltip", " Ignore Enemy Associates On");
ai_SetAIMode(oAssociate, AI_MODE_IGNORE_ASSOCIATES, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_Ignore_Traps(object oPC, object oAssociate, string sAssociateType)
{
if(ai_GetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS))
{
ai_SendMessages(GetName(oAssociate) + " will stop ignoring traps on the floor and will stop moving when one is seen.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_traps_tooltip", " Ignore Floor Traps Off");
ai_SetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS, FALSE);
}
else
{
ai_SendMessages(GetName(oAssociate) + " will now ignore traps on the floor and will continue with their actions.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ignore_traps_tooltip", " Ignore Floor Traps On");
ai_SetAIMode(oAssociate, AI_MODE_IGNORE_TRAPS, TRUE);
}
aiSaveAssociateModesToDb(oPC, oAssociate);
}
void ai_FollowTarget(object oPC, object oAssociate)
{
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_FOLLOW_TARGET");
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
}
void ai_Original_Guard()
{
ResetHenchmenState();
//Companions will only attack the Masters Last Attacker
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER);
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
object oMaster = GetMaster();
object oLastAttacker = GetLastHostileActor(oMaster);
// * for some reason this is too often invalid. still the routine
// * works corrrectly
SetLocalInt(OBJECT_SELF, "X0_BATTLEJOINEDMASTER", TRUE);
HenchmenCombatRound(oLastAttacker);
ai_SendMessages(GetName(OBJECT_SELF) + " is now guarding you!", AI_COLOR_YELLOW, oMaster);
}
void ai_Original_Follow()
{
ResetHenchmenState();
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
DelayCommand(2.5, VoiceCanDo());
object oMaster = GetMaster();
ActionForceFollowObject(oMaster, GetFollowDistance());
SetAssociateState(NW_ASC_IS_BUSY);
DelayCommand(5.0, SetAssociateState(NW_ASC_IS_BUSY, FALSE));
ai_SendMessages(GetName(OBJECT_SELF) + " is now following You!", AI_COLOR_YELLOW, oMaster);
}
void ai_Original_StandGround()
{
SetAssociateState(NW_ASC_MODE_STAND_GROUND);
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
DelayCommand(2.0, VoiceCanDo());
ActionAttack(OBJECT_INVALID);
ClearActions(CLEAR_X0_INC_HENAI_RespondToShout1);
ai_SendMessages(GetName(OBJECT_SELF) + " is now standing their ground!", AI_COLOR_YELLOW, GetMaster());
}
void ai_Original_AttackNearest()
{
ResetHenchmenState();
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
DetermineCombatRound();
// * bonus feature. If master is attacking a door or container, issues VWE Attack Nearest
// * will make henchman join in on the fun
object oMaster = GetMaster();
object oTarget = GetAttackTarget(oMaster);
if (GetIsObjectValid(oTarget) == TRUE)
{
if (GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE || GetObjectType(oTarget) == OBJECT_TYPE_DOOR)
{
ActionAttack(oTarget);
}
}
ai_SendMessages(GetName(OBJECT_SELF) + " is now in normal mode!", AI_COLOR_YELLOW, oMaster);
}
void ai_Original_SetSearch(object oAssociate, int bTurnOn)
{
if(GetRacialType(oAssociate) != RACIAL_TYPE_ELF) SetActionMode(oAssociate, ACTION_MODE_DETECT, bTurnOn);
}
void ai_Original_SetStealth(object oAssociate, int bTurnOn)
{
SetActionMode(oAssociate, ACTION_MODE_STEALTH, bTurnOn);
}
void ai_Philos_Guard(object oMaster, object oCreature)
{
ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, TRUE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE);
ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE);
int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI);
ai_HighlightWidgetMode(oMaster, oCreature, nToken);
if(!ai_GetIsBusy(oCreature) && ai_GetIsInCombat(oCreature))
{
object oLastAttacker = GetLastHostileActor(oMaster);
if(oLastAttacker != OBJECT_INVALID) ai_DoAssociateCombatRound(oCreature, oLastAttacker);
else AssignCommand(oCreature, ActionMoveToObject(oMaster, TRUE));
}
ai_SendMessages(GetName(oCreature) + " is now guarding you!", AI_COLOR_YELLOW, oMaster);
aiSaveAssociateModesToDb(oMaster, oCreature);
}
void ai_Philos_Follow(object oMaster)
{
object oCreature = OBJECT_SELF;
ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, TRUE);
ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE);
int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI);
ai_HighlightWidgetMode(oMaster, oCreature, nToken);
aiSaveAssociateModesToDb(oMaster, oCreature);
// To follow we probably should be running and not searching or hiding.
if(GetDetectMode(oCreature) && !GetHasFeat(FEAT_KEEN_SENSE, oCreature)) SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE);
if(GetStealthMode(oCreature)) SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE);
ai_PassActionToAssociates(oCreature, ACTION_FOLLOW);
if(ai_IsInCombatRound(oCreature)) ai_ClearCombatState(oCreature);
ai_ClearCreatureActions(TRUE);
object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET);
if(oTarget == OBJECT_INVALID) oTarget = oMaster;
ActionMoveToObject(oTarget, TRUE, ai_GetFollowDistance(oCreature));
ai_SendMessages(GetName(oCreature) + " is now following " + GetName(oTarget) + "!", AI_COLOR_YELLOW, oMaster);
}
void ai_Philos_StandGround(object oMaster)
{
object oCreature = OBJECT_SELF;
ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, TRUE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE);
ai_PassActionToAssociates(oCreature, ACTION_FOLLOW, FALSE);
ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE);
int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI);
ai_HighlightWidgetMode(oMaster, oCreature, nToken);
if(ai_IsInCombatRound(oCreature))
{
ai_ClearCombatState(oCreature);
DeleteLocalObject(oCreature, AI_ATTACKED_PHYSICAL);
DeleteLocalObject(oCreature, AI_ATTACKED_SPELL);
}
ai_ClearCreatureActions(TRUE);
ai_SendMessages(GetName(oCreature) + " is now standing their ground!", AI_COLOR_YELLOW, oMaster);
aiSaveAssociateModesToDb(oMaster, oCreature);
}
void ai_Philos_AttackNearest(object oMaster, object oCreature)
{
ai_PassAIModeToAssociates(oCreature, AI_MODE_SCOUT_AHEAD, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_STAND_GROUND, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_DEFEND_MASTER, FALSE);
ai_PassAIModeToAssociates(oCreature, AI_MODE_FOLLOW, FALSE);
ai_PassActionToAssociates(oCreature, ACTION_FOLLOW, FALSE);
ai_SetAIMode(oCreature, AI_MODE_COMMANDED, FALSE);
int nToken = NuiFindWindow(oMaster, ai_GetAssociateType(oMaster, oCreature) + AI_WIDGET_NUI);
ai_HighlightWidgetMode(oMaster, oCreature, nToken);
// Removes any targets the PC may have given the associate.
DeleteLocalObject(oCreature, AI_PC_LOCKED_TARGET);
// This resets a henchmens failed Moral save in combat.
string sScript = GetLocalString(oCreature, AI_COMBAT_SCRIPT);
if(sScript == "ai_coward")
{
sScript = GetLocalString(oCreature, AI_DEFAULT_SCRIPT);
SetLocalString(oCreature, AI_COMBAT_SCRIPT, sScript);
}
if(!ai_GetIsBusy(oCreature))
{
object oEnemy = ai_GetNearestEnemy(oCreature, 1, 7, 7);
if(oEnemy != OBJECT_INVALID && GetDistanceBetween(oCreature, oEnemy) < AI_RANGE_BATTLEFIELD)
{
ai_HaveCreatureSpeak(oCreature, 5, ":0:1:2:3:6:");
// If master is attacking a target we will attack them too!
if(!ai_GetIsInCombat(oCreature)) ai_StartAssociateCombat(oCreature);
object oTarget = ai_GetAttackedTarget(oMaster);
if(oTarget == OBJECT_INVALID) ai_DoAssociateCombatRound(oCreature);
else ai_DoAssociateCombatRound(oCreature, oTarget);
}
else
{
object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET);
if(oTarget == OBJECT_INVALID) oTarget = oMaster;
AssignCommand(oCreature, ActionMoveToObject(oMaster, TRUE, ai_GetFollowDistance(oCreature)));
}
}
ai_SendMessages(GetName(oCreature) + " is now in normal mode!", AI_COLOR_YELLOW, oMaster);
aiSaveAssociateModesToDb(oMaster, oCreature);
}
void ai_Philos_SetSearch(object oMaster, object oCreature, string sAssociateType, int bTurnOn)
{
if(bTurnOn)
{
ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH, TRUE);
SetActionMode(oCreature, ACTION_MODE_DETECT, TRUE);
ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, TRUE);
//ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, TRUE);
ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode On");
}
else
{
ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_SEARCH, FALSE);
SetActionMode(oCreature, ACTION_MODE_DETECT, FALSE);
ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, FALSE);
//ai_PassActionToAssociates(oCreature, ACTION_MODE_DETECT, FALSE);
ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_search_tooltip", " Search mode Off");
}
aiSaveAssociateModesToDb(oMaster, oCreature);
}
void ai_Philos_SetStealth(object oMaster, object oCreature, string sAssociateType, int bTurnOn)
{
if(bTurnOn)
{
ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH);
SetActionMode(oCreature, ACTION_MODE_STEALTH, TRUE);
ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, TRUE);
ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode On");
}
else
{
ai_SetAIMode(oCreature, AI_MODE_AGGRESSIVE_STEALTH, FALSE);
SetActionMode(oCreature, ACTION_MODE_STEALTH, FALSE);
ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, FALSE);
//ai_PassActionToAssociates(oCreature, ACTION_MODE_STEALTH, FALSE);
ai_UpdateToolTipUI(oMaster, sAssociateType + AI_NUI, sAssociateType + AI_WIDGET_NUI, "btn_stealth_tooltip", " Stealth mode Off");
}
aiSaveAssociateModesToDb(oMaster, oCreature);
}
void ai_DoCommand(object oPC, object oAssociate, int nCommand)
{
int nIndex = 1;
if(oPC == oAssociate)
{
if(nCommand == 1) // Guard PC.
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Guard());
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Guard());
}
}
// Use Philos AI commands.
else
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) ai_Philos_Guard(oPC, oAssociate);
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) ai_Philos_Guard(oPC, oAssociate);
}
}
}
else if(nCommand == 2) // Follow PC.
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Follow());
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_Follow());
}
}
// Use Philos AI commands.
else
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_Follow(oPC));
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_Follow(oPC));
}
}
}
else if(nCommand == 3) // Standground.
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_StandGround());
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_StandGround());
}
}
// Use Philos AI commands.
else
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_StandGround(oPC));
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Philos_StandGround(oPC));
}
}
}
else if(nCommand == 4) // Normal mode - i.e. Attack nearest.
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_AttackNearest());
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) AssignCommand(oAssociate, ai_Original_AttackNearest());
}
}
// Use Philos AI commands.
else
{
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) ai_Philos_AttackNearest(oPC, oAssociate);
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) ai_Philos_AttackNearest(oPC, oAssociate);
}
}
}
if(nCommand == 5) // All associates toggle search mode
{
int bTurnOn = !ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_SEARCH);
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
ai_Original_SetSearch(oPC, bTurnOn);
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) ai_Original_SetSearch(oAssociate, bTurnOn);
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) ai_Original_SetSearch(oAssociate, bTurnOn);
}
}
else
{
ai_Philos_SetSearch(oPC, oPC, "pc", bTurnOn);
string sAssociateType;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID)
{
sAssociateType = ai_GetAssociateType(oPC, oAssociate);
ai_Philos_SetSearch(oPC, oAssociate, sAssociateType, bTurnOn);
}
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID)
{
sAssociateType = ai_GetAssociateType(oPC, oAssociate);
ai_Philos_SetSearch(oPC, oAssociate, sAssociateType, bTurnOn);
}
}
}
if(bTurnOn)
{
ai_SendMessages("Everyone is now in search mode!", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_search_tooltip", " Everyone leave search mode");
}
else
{
ai_SendMessages("Everyone has left search mode!", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_search_tooltip", " Everyone enter search mode");
}
}
if(nCommand == 6) // All associate use stealth mode
{
int bTurnOn = !ai_GetAIMode(oPC, AI_MODE_AGGRESSIVE_STEALTH);
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
ai_Original_SetStealth(oPC, bTurnOn);
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID) ai_Original_SetStealth(oAssociate, bTurnOn);
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID) ai_Original_SetStealth(oAssociate, bTurnOn);
}
}
else
{
ai_Philos_SetStealth(oPC, oPC, "pc", bTurnOn);
string sAssociateType;
for(nIndex = 1; nIndex <= AI_MAX_HENCHMAN; nIndex++)
{
oAssociate = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, nIndex);
if(oAssociate != OBJECT_INVALID)
{
sAssociateType = ai_GetAssociateType(oPC, oAssociate);
ai_Philos_SetStealth(oPC, oAssociate, sAssociateType, bTurnOn);
}
}
for(nIndex = 2; nIndex < 6; nIndex++)
{
oAssociate = GetAssociate(nIndex, oPC);
if(oAssociate != OBJECT_INVALID)
{
sAssociateType = ai_GetAssociateType(oPC, oAssociate);
ai_Philos_SetStealth(oPC, oAssociate, sAssociateType, bTurnOn);
}
}
}
if(bTurnOn)
{
ai_SendMessages("Everyone is now in stealth mode.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_stealth_tooltip", " Everyone leave stealth mode");
}
else
{
ai_SendMessages("Everyone has left stealth mode.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, "pc" + AI_COMMAND_NUI, "pc" + AI_WIDGET_NUI, "btn_cmd_stealth_tooltip", " Everyone enter stealth mode");
}
}
}
else
{
if(nCommand == 1)
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
AssignCommand(oAssociate, ai_Original_Guard());
}
else ai_Philos_Guard(oPC, oAssociate);
}
else if(nCommand == 2)
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
AssignCommand(oAssociate, ai_Original_Follow());
}
else AssignCommand(oAssociate, ai_Philos_Follow(oPC));
}
else if(nCommand == 3)
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
AssignCommand(oAssociate, ai_Original_StandGround());
}
else AssignCommand(oAssociate, ai_Philos_StandGround(oPC));
}
else if(nCommand == 4)
{
// Not using Philos Henchman AI. Use vanilla commands.
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) == "")
{
AssignCommand(oAssociate, ai_Original_AttackNearest());
}
else ai_Philos_AttackNearest(oPC, oAssociate);
}
}
}
void ai_Action(object oPC, object oAssociate)
{
if(oPC == oAssociate)
{
DeleteLocalObject(oPC, "NW_ASSOCIATE_COMMAND");
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION_ALL");
ai_SendMessages("Select an action for the party.", AI_COLOR_YELLOW, oPC);
}
else
{
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_ACTION");
ai_SendMessages("Select an action for " + GetName(oAssociate) + ".", AI_COLOR_YELLOW, oPC);
}
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
}
void ai_AIScript(object oPC, object oAssociate, string sAssociateType, int nToken)
{
if(ResManGetAliasFor("ai_a_default", RESTYPE_NCS) != "")
{
string sScript = GetLocalString(oAssociate, AI_COMBAT_SCRIPT);
string sIcon = "ir_scommand";
if(sScript == "ai_a_ambusher")
{
sScript = "ai_a_flanker";
sIcon = "ir_invite";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using flanking tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Flanker: Attacks enemies engaged with allies");
}
else if(sScript == "ai_a_flanker")
{
sScript = "ai_a_peaceful";
sIcon = "ir_ignore";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using peaceful tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Peaceful: Avoids attacking any enemies if possible");
}
else if(sScript == "ai_a_peaceful")
{
sScript = "ai_a_defensive";
sIcon = "ir_knockdwn";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using defensive tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Defensive: Attacks then uses Expertise/Parry");
}
else if(sScript == "ai_a_defensive")
{
sScript = "ai_a_ranged";
sIcon = "ir_ranger";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using ranged tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Ranged: Attacks from range as much as possible");
}
else if(sScript == "ai_a_ranged")
{
sScript = "ai_a_cntrspell";
sIcon = "ir_dcaster";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using counter spell tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Counter Spell: Tries to counter enemy spells");
}
else if(sScript == "ai_a_cntrspell")
{
DeleteLocalString(oAssociate, AI_DEFAULT_SCRIPT);
ai_SetAssociateAIScript(oAssociate, FALSE);
sScript = GetLocalString(oAssociate, AI_DEFAULT_SCRIPT);
ai_SendMessages(GetName(oAssociate) + " is now using default tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Default tactics: Using the creatures base AI script");
}
else
{
sScript = "ai_a_ambusher";
sIcon = "ir_rogue";
SetLocalString(oAssociate, AI_DEFAULT_SCRIPT, sScript);
SetLocalString(oAssociate, AI_COMBAT_SCRIPT, sScript);
ai_SendMessages(GetName(oAssociate) + " is now using ambush tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Ambusher: Attacks from a hidden position");
}
NuiSetBind(oPC, nToken, "btn_cmd_ai_script_image", JsonString(sIcon));
NuiSetBind(oPC, nToken, "btn_cmd_ai_script_label", JsonString("Tactics: " + sScript));
json jAIData = ai_GetAssociateDbJson(oPC, sAssociateType, "aidata");
if(JsonGetType(JsonArrayGet(jAIData, 8)) == JSON_TYPE_NULL) jAIData = JsonArrayInsert(jAIData, JsonString(sScript));
else jAIData = JsonArraySet(jAIData, 8, JsonString(sScript));
ai_SetAssociateDbJson(oPC, sAssociateType, "aidata", jAIData);
}
else
{
if(GetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, oAssociate))
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, TRUE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate);
ai_SendMessages(GetName(oAssociate) + " is now using coward tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using coward tactics");
}
else if(GetCombatCondition(X0_COMBAT_FLAG_COWARDLY, oAssociate))
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, TRUE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate);
ai_SendMessages(GetName(oAssociate) + " is now using defensive tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using defensive tactics");
}
else if(GetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, oAssociate))
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_RANGED, TRUE, oAssociate);
ai_SendMessages(GetName(oAssociate) + " is now using ranged tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ranged tactics");
}
else if(GetCombatCondition(X0_COMBAT_FLAG_RANGED, oAssociate))
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate);
ai_SendMessages(GetName(oAssociate) + " is now using normal tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ambush tactics");
}
else
{
SetCombatCondition(X0_COMBAT_FLAG_AMBUSHER, TRUE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_COWARDLY, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE, FALSE, oAssociate);
SetCombatCondition(X0_COMBAT_FLAG_RANGED, FALSE, oAssociate);
ai_SendMessages(GetName(oAssociate) + " is now using ambush tactics in combat.", AI_COLOR_YELLOW, oPC);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_cmd_ai_script_tooltip", " Using ambush tactics");
}
}
}
void ai_HavePCPlaceTrap(object oPC, object oAssociate)
{
SetLocalObject(oPC, AI_TARGET_ASSOCIATE, oAssociate);
SetLocalString(oPC, AI_TARGET_MODE, "ASSOCIATE_GET_TRAP");
ai_SendMessages(GetName(oAssociate) + " select a trap to place.", AI_COLOR_YELLOW, oPC);
OpenInventory(oAssociate, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_ITEM, MOUSECURSOR_ACTION, MOUSECURSOR_NOWALK);
}
void ai_JumpAssociateToPC(object oPC)
{
ai_ClearCreatureActions(TRUE);
JumpToObject(oPC);
}
void ai_JumpToPC(object oPC, object oAssociate)
{
int nAssociateType, nHenchman, nHenchAssociate;
object oHenchman, oHenchmanAssociate;
if(oPC != oAssociate)
{
if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN)
{
for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++)
{
oHenchmanAssociate = GetAssociate(nHenchAssociate, oHenchman, 1);
if(oHenchmanAssociate != OBJECT_INVALID)
{
AssignCommand(oHenchmanAssociate, ai_JumpAssociateToPC(oPC));
}
}
AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC));
}
else AssignCommand(oAssociate, ai_JumpAssociateToPC(oPC));
return;
}
for(nAssociateType = 1; nAssociateType <= 5; nAssociateType++)
{
if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN)
{
for(nHenchman = 1; nHenchman <= AI_MAX_HENCHMAN; nHenchman++)
{
oHenchman = GetAssociate(nAssociateType, oPC, nHenchman);
if(oHenchman != OBJECT_INVALID)
{
for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++)
{
oHenchmanAssociate = GetAssociate(nHenchAssociate, oHenchman, 1);
if(oHenchmanAssociate != OBJECT_INVALID)
{
AssignCommand(oHenchmanAssociate, ai_JumpAssociateToPC(oPC));
}
}
AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC));
}
}
}
else
{
oHenchman = GetAssociate(nAssociateType, oPC, 1);
if(oHenchman != OBJECT_INVALID) AssignCommand(oHenchman, ai_JumpAssociateToPC(oPC));
}
}
}
void ai_GhostMode(object oPC, object oAssociate, int nToken, string sAssociateType)
{
string sText;
if(ai_GetAIMode(oAssociate, AI_MODE_GHOST))
{
ai_SetAIMode(oAssociate, AI_MODE_GHOST, FALSE);
ai_RemoveASpecificEffect(oAssociate, EFFECT_TYPE_CUTSCENEGHOST);
sText = " Turn On clipping through creatures for " + GetName(oAssociate);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ghost_mode_tooltip", sText);
ai_SendMessages(GetName(oAssociate) + " is not in Ghost Mode and will run into creatures.", AI_COLOR_YELLOW, oPC);
}
else
{
ai_SetAIMode(oAssociate, AI_MODE_GHOST, TRUE);
effect eGhost = EffectCutsceneGhost();
eGhost = UnyieldingEffect(eGhost);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eGhost, oAssociate);
sText = " Turn Off clipping through creatures for " + GetName(oAssociate);
ai_UpdateToolTipUI(oPC, sAssociateType + AI_COMMAND_NUI, sAssociateType + AI_WIDGET_NUI, "btn_ghost_mode_tooltip", sText);
ai_SendMessages(GetName(oAssociate) + " is now in Ghost Mode and will clip through creatures.", AI_COLOR_YELLOW, oPC);
}
}
void ai_ChangeCameraView(object oPC, object oAssociate)
{
object oCamAssociate = GetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE");
if(oCamAssociate == oAssociate)
{
DeleteLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE");
AttachCamera(oPC, oPC);
}
else
{
SetLocalObject(oPC, "AI_CAMERA_ON_ASSOCIATE", oAssociate);
AttachCamera(oPC, oAssociate);
}
}
void ai_SelectCameraView(object oPC)
{
SetLocalString(oPC, AI_TARGET_MODE, "DM_SELECT_CAMERA_VIEW");
ai_SendMessages(GetName(oPC) + " select an object to change the camera view to.", AI_COLOR_YELLOW, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_ALL, MOUSECURSOR_CREATE, MOUSECURSOR_NOCREATE);
}
void ai_OpenInventory(object oAssociate, object oPC)
{
// Funny things happen when you open associate inventories when they are not
// within sight.
if(LineOfSightObject(oPC, oAssociate))
{
OpenInventory(oAssociate, oPC);
}
else ai_SendMessages(GetName(oAssociate) + " is not within sight!", AI_COLOR_RED, oPC);
}
void ai_SelectOpenInventory(object oPC)
{
SetLocalString(oPC, AI_TARGET_MODE, "DM_SELECT_OPEN_INVENTORY");
ai_SendMessages(GetName(oPC) + " select an object to open its inventory.", AI_COLOR_YELLOW, oPC);
EnterTargetingMode(oPC, OBJECT_TYPE_CREATURE, MOUSECURSOR_EXAMINE, MOUSECURSOR_NOEXAMINE);
}
void ai_Plugin_Execute(object oPC, string sElem, int bUser = 0)
{
int nIndex = StringToInt(GetStringRight(sElem, 1));
json jPlugins, jPlugin;
if(bUser == 1) // From DM command menu.
{
string sName = ai_RemoveIllegalCharacters(GetName(oPC));
jPlugins = ai_GetCampaignDbJson("plugins", sName, AI_DM_TABLE);
}
else if(bUser == 2) // From DM plugin menu, master plugin list.
{
jPlugins = ai_GetCampaignDbJson("plugins");
}
else jPlugins = ai_GetAssociateDbJson(oPC, "pc", "plugins");
jPlugin = JsonArrayGet(jPlugins, nIndex);
string sScript = JsonGetString(JsonArrayGet(jPlugin, 0));
if(ResManGetAliasFor(sScript, RESTYPE_NCS) == "")
{
ai_SendMessages(sScript + " not found by ResMan!", AI_COLOR_RED, oPC);
}
else
{
string sName = JsonGetString(JsonArrayGet(jPlugin, 2));
ai_SendMessages("Executing plugin " + sName + ".", AI_COLOR_GREEN, oPC);
ExecuteScript(sScript, oPC);
}
}