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

424 lines
20 KiB
Plaintext

/*////////////////////////////////////////////////////////////////////////////////////////////////////
// Script Name: 0i_states_cond
//////////////////////////////////////////////////////////////////////////////////////////////////////
Include scripts that handle states and conditions for combat.
*/////////////////////////////////////////////////////////////////////////////////////////////////////
#include "0i_main"
#include "0i_messages"
#include "0i_time"
//#include "X0_I0_COMBAT"
// Wrapper for ClearAllActions - we have added extra vars to be cleared as well.
// Note this references OBJECT_SELF!
void ai_ClearCreatureActions(int bClearCombatState = FALSE);
// Used in combat to keep track of the creatures last rounds action.
// One use is to make sure we don't use the same spell on the next round.
// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants.
void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE);
// Returns TRUE if oCreatures last rounds action is equal to nAction.
// 0+ is the spell that was cast, other actions use AI_LAST_ACTION_* constants.
int ai_CompareLastAction(object oCreature, int nAction);
// Sets the correct listen checks on oCreature.
void ai_SetListeningPatterns(object oCreature);
// Returns TRUE if oCreature is an elemental, undead, or golem i.e. non-living.
int ai_IsNonliving(int nRacialType);
// Returns TRUE if oCreature is in combat.
int ai_GetIsInCombat(object oCreature);
// Sets the time that this oCreature's current combat round started.
// Using action based combat rounds has an unfortunate side effect:
// Once you attack in melee you will continue to attack in melee do to hardcoded
// logic. This will "PUSH" your end of round back until it decides to stop attacking!
// We avoid this by setting the time and if we check for combat and 6 seconds has
// passed then we assume the current round is over, ClearAllActions, and start the next round.
void ai_SetCombatRound(object oCreature);
// Clears the current combat round timer by deleting the value.
void ai_EndCombatRound(object oCreature);
// Returns TRUE if AI_COMBAT_ROUND_IN_SECONDS has not passed since ai_SetCombatRound.
// If it returns FALSE then it will clear the current combat round timer.
int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS);
// Returns TRUE if oCreature is busy.
// This checks various actions to see if oCreature is busy;
// in combat, busy mode, Actions: attacking, casting spell, counterspelling,
// disabling trap, item casting spell, opening lock, resting, setting trap.
int ai_GetIsBusy(object oCreature);
// Returns a value based on the disabling effect.
// Dead = 1, Bleeding = 2, Dying = 2, Stunned = 29, Confused = 24, Paralyzed = 27
// Frightened 25, Turned = 35, Petrified = 79, Charmed = 23, Disappearappear = 75,
// Time Stop = 66, Dazed = 28, Sleep = 30.
// Returns FALSE if not Disabled.
int ai_Disabled(object oCreature);
// Set one of the AI_MODE_* bitwise constants on oAssociate to bOn.
void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE);
// Return if nMode is set on oAssociate. Uses the AI_MODE_* bitwise constants.
int ai_GetAIMode(object oAssociate, int nBit);
// Set one of the AI_MAGIC_* bitwise constants on oAssociate to bOn.
void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE);
// Return if nMode is set on oAssociate. Uses the AI_MAGIC_* bitwise constants.
int ai_GetMagicMode(object oAssociate, int nBit);
// This is based off of the PC's settings for an associate and other creatures use a default.
// Set one of the AI_LOOT_* bitwise constants on oAssociate to bOn.
void ai_SetLootFilter(object oAssociate, int nBit, int bOn = TRUE);
// Return if nMode is set on oAssociate. Uses the AI_LOOT_* bitwise constants.
int ai_GetLootFilter(object oAssociate, int nBit);
// Set one of the AI_IP_* bitwise constants on oCreature to bOn.
void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE);
// Return if nMode is set on oCreature. Uses the AI_IP_* bitwise constants.
int ai_GetItemProperty(object oCreature, string sVarname, int nBit);
// Returns the number of hitpoints a creature must have to not be healed.
// This is based off of the PC's settings for an associate and other creatures use a default.
int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE);
// Returns TRUE if nCondition is within nCurrentConditions.
// nCurrentConditions is setup in ai_GetNegativeConditions.
int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions);
// Returns an integer with bitwise flags set that represent the current negative
// conditions on oCreature. ai_GetHasNegativeCondition uses this function.
int ai_GetNegativeConditions(object oCreature);
// Returns TRUE if oObject is in the line of sight of oCreature.
// If the creature is close LineOfSight doesn't work well.
int ai_GetIsInLineOfSight(object oCreature, object oObject);
// Add the specified condition flag to the behavior state of the caller
void ai_SetBehaviorState(int nCondition, int bValid = TRUE);
// Returns TRUE if the specified behavior flag is set on the caller
int ai_GetBehaviorState(int nCondition);
// Highlights the current mode for the widget passed.
void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken);
// Checks to see if the party scale is correctly adjusted.
void ai_CheckXPPartyScale(object oCreature);
void ai_ClearCreatureActions(int bClearCombatState = FALSE)
{
if(AI_DEBUG) ai_Debug("0i_states_cond", "89", GetName(OBJECT_SELF) + " is clearing actions (" +
IntToString(bClearCombatState) + ")!");
DeleteLocalInt(OBJECT_SELF, AI_CURRENT_ACTION_MODE);
ClearAllActions(bClearCombatState);
}
void ai_SetLastAction(object oCreature, int nAction = AI_LAST_ACTION_NONE)
{
SetLocalInt(oCreature, sLastActionVarname, nAction);
}
int ai_CompareLastAction(object oCreature, int nAction)
{
// Are we checking to see if we cast a spell?
if(nAction == AI_LAST_ACTION_CAST_SPELL &&
GetLocalInt(oCreature, sLastActionVarname) > -1) return TRUE;
// Check other last actions.
return (nAction == GetLocalInt(oCreature, sLastActionVarname));
}
void ai_SetListeningPatterns(object oCreature)
{
SetListenPattern(oCreature, AI_I_SEE_AN_ENEMY, AI_ALLY_SEES_AN_ENEMY);
SetListenPattern(oCreature, AI_I_HEARD_AN_ENEMY, AI_ALLY_HEARD_AN_ENEMY);
SetListenPattern(oCreature, AI_ATKED_BY_WEAPON, AI_ALLY_ATKED_BY_WEAPON);
SetListenPattern(oCreature, AI_ATKED_BY_SPELL, AI_ALLY_ATKED_BY_SPELL);
SetListenPattern(oCreature, AI_I_AM_WOUNDED, AI_ALLY_IS_WOUNDED);
SetListenPattern(oCreature, AI_I_AM_DEAD, AI_ALLY_IS_DEAD);
SetListenPattern(oCreature, AI_I_AM_DISEASED, AI_ALLY_IS_DISEASED);
SetListenPattern(oCreature, AI_I_AM_POISONED, AI_ALLY_IS_POISONED);
SetListenPattern(oCreature, AI_I_AM_WEAK, AI_ALLY_IS_WEAK);
SetListening(oCreature, TRUE);
}
int ai_IsNonliving(int nRacialType)
{
switch(nRacialType)
{
case RACIAL_TYPE_CONSTRUCT:
case RACIAL_TYPE_ELEMENTAL:
case RACIAL_TYPE_UNDEAD: return TRUE;
}
return FALSE;
}
int ai_GetIsInCombat(object oCreature)
{
if(AI_DEBUG) ai_Debug("0i_states_cond", "110", GetName(oCreature) + " is in Combat: Enemy Numbers = " + IntToString(GetLocalInt(oCreature, AI_ENEMY_NUMBERS)));
return GetLocalInt(oCreature, AI_ENEMY_NUMBERS);
}
void ai_SetCombatRound(object oCreature)
{
SetLocalInt(oCreature, "AI_COMBAT_ROUND_START", SQLite_GetTimeStamp());
if(AI_DEBUG) ai_Debug("0i_states_cond", "116", " ===============> " + GetName(oCreature) + " ROUND START:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
}
void ai_EndCombatRound(object oCreature)
{
if(AI_DEBUG) ai_Debug("0i_states_cond", "120", " ===============> " + GetName(oCreature) + " ROUND END:" + IntToString(SQLite_GetTimeStamp()) + " <===============");
DeleteLocalInt(oCreature, "AI_COMBAT_ROUND_START");
}
int ai_IsInCombatRound(object oCreature, int nCombatRound = AI_COMBAT_ROUND_IN_SECONDS)
{
int nCombatRoundStart = GetLocalInt(oCreature, "AI_COMBAT_ROUND_START");
if(AI_DEBUG) ai_Debug("0i_states_cond", "148", " nCombatRoundStart: " + IntToString(nCombatRoundStart));
if(!nCombatRoundStart) return FALSE;
// New combat round calculator. If 6 seconds has passed then we are on a new round!
int nSQLTime = SQLite_GetTimeStamp();
int nCombatRoundTime = nSQLTime - nCombatRoundStart;
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", " SQLite_GetTimeStamp: " + IntToString(nSQLTime) +
"(" + IntToString(nSQLTime - nCombatRoundStart) + ")");
if(nCombatRoundTime < nCombatRound) return TRUE;
ai_EndCombatRound(oCreature);
return FALSE;
}
// Testing to see if we can fix some delaying in combat.
int ai_GetIsBusy(object oCreature)
{
int nAction = GetCurrentAction(oCreature);
if(AI_DEBUG) ai_Debug("0i_states_cond", "140", GetName(oCreature) + " Get is Busy, action: " +
IntToString(nAction));
switch(nAction)
{
case ACTION_CASTSPELL :
case ACTION_ITEMCASTSPELL :
case ACTION_OPENLOCK :
case ACTION_REST :
case ACTION_DISABLETRAP :
case ACTION_ATTACKOBJECT :
case ACTION_COUNTERSPELL :
case ACTION_SETTRAP : return TRUE;
case ACTION_WAIT :
case ACTION_INVALID :
{
int nCombatWait = GetLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
if(AI_DEBUG) ai_Debug("0i_states_cond", "153", "nCombatWait: " + IntToString(nCombatWait) +
" AI_AM_I_SEARCHING: " + IntToString(GetLocalInt(oCreature, AI_AM_I_SEARCHING)));
if(nCombatWait)
{
if(ai_IsInCombatRound(oCreature, nCombatWait)) return TRUE;
DeleteLocalInt(oCreature, AI_COMBAT_WAIT_IN_SECONDS);
}
else if(GetLocalInt(oCreature, AI_AM_I_SEARCHING)) DeleteLocalInt(oCreature, AI_AM_I_SEARCHING);
return FALSE;
}
case ACTION_MOVETOPOINT :
{
return ai_GetIsInCombat(oCreature);
}
}
return FALSE;
}
int ai_Disabled(object oCreature)
{
if(GetIsDead(oCreature)) return 1;
// Check for effects.
effect eEffect = GetFirstEffect(oCreature);
while(GetIsEffectValid(eEffect))
{
switch(GetEffectType(eEffect))
{
case EFFECT_TYPE_DOMINATED :
{
if(!GetCommandable(oCreature)) SetCommandable(TRUE, oCreature);
return FALSE;
}
case EFFECT_TYPE_STUNNED :
case EFFECT_TYPE_DAZED :
case EFFECT_TYPE_SLEEP :
case EFFECT_TYPE_CONFUSED :
case EFFECT_TYPE_FRIGHTENED :
case EFFECT_TYPE_PARALYZE :
case EFFECT_TYPE_TURNED :
case EFFECT_TYPE_CHARMED :
case EFFECT_TYPE_PETRIFY :
case EFFECT_TYPE_TIMESTOP :
{
if(AI_DEBUG) ai_Debug("0i_stats_cond", "195", GetName(oCreature) + " is disabled(" +
IntToString(GetEffectType(eEffect)) + ")");
return GetEffectType(eEffect);
}
}
eEffect = GetNextEffect(oCreature);
}
// Not Commandable is basically disabled as far as the AI is concerned.
if(!GetCommandable(oCreature))
{
if(AI_DEBUG) ai_Debug("0i_stats_cond", "213", GetName(oCreature) + " is disabled(Not Commandable)!");
return EFFECT_TYPE_PARALYZE;
}
if(AI_DEBUG) ai_Debug("0i_states_cond", "202", GetName(oCreature) + " is not disabled.");
return FALSE;
}
void ai_SetAIMode(object oAssociate, int nBit, int bOn = TRUE)
{
int nAIModes = GetLocalInt(oAssociate, sAIModeVarname);
if(bOn) nAIModes = nAIModes | nBit;
else nAIModes = nAIModes & ~nBit;
SetLocalInt(oAssociate, sAIModeVarname, nAIModes);
// Set widget to show the mode they are in.
}
int ai_GetAIMode(object oAssociate, int nBit)
{
if(GetLocalInt(oAssociate, sAIModeVarname) & nBit) return TRUE;
return FALSE;
}
void ai_SetMagicMode(object oAssociate, int nBit, int bOn = TRUE)
{
int nMagicModes = GetLocalInt(oAssociate, sMagicModeVarname);
if(bOn) nMagicModes = nMagicModes | nBit;
else nMagicModes = nMagicModes & ~nBit;
SetLocalInt(oAssociate, sMagicModeVarname, nMagicModes);
}
int ai_GetMagicMode(object oAssociate, int nBit)
{
if(GetLocalInt(oAssociate, sMagicModeVarname) & nBit) return TRUE;
return FALSE;
}
void ai_SetLootFilter(object oAssociate, int nLootBit, int bOn = TRUE)
{
int nLootFilter = GetLocalInt(oAssociate, sLootFilterVarname);
if(bOn) nLootFilter = nLootFilter | nLootBit;
else nLootFilter = nLootFilter & ~nLootBit;
SetLocalInt(oAssociate, sLootFilterVarname, nLootFilter);
}
int ai_GetLootFilter(object oAssociate, int nBit)
{
if(GetLocalInt(oAssociate, sLootFilterVarname) & nBit) return TRUE;
return FALSE;
}
void ai_SetItemProperty(object oCreature, string sVarname, int nBit, int bOn = TRUE)
{
int nItemProperties = GetLocalInt(oCreature, sVarname);
if(bOn) nItemProperties = nItemProperties | nBit;
else nItemProperties = nItemProperties & ~nBit;
SetLocalInt(oCreature, sVarname, nItemProperties);
}
int ai_GetItemProperty(object oCreature, string sVarname, int nBit)
{
if(GetLocalInt(oCreature, sVarname) & nBit) return TRUE;
return FALSE;
}
int ai_GetHealersHpLimit(object oCreature, int bInCombat = TRUE)
{
if(bInCombat) return GetLocalInt(oCreature, AI_HEAL_IN_COMBAT_LIMIT);
else return GetLocalInt(oCreature, AI_HEAL_OUT_OF_COMBAT_LIMIT);
}
int ai_GetHasNegativeCondition(int nCondition, int nCurrentConditions)
{
return (nCurrentConditions & nCondition);
}
int ai_GetNegativeConditions(object oCreature)
{
int nCondition, nEffectType;
effect eEffect = GetFirstEffect(oCreature);
while(GetIsEffectValid (eEffect))
{
// Rage and maybe other abilities might come from the oCreature!
if(GetEffectCreator(eEffect) != oCreature)
{
nEffectType = GetEffectType(eEffect);
switch(nEffectType)
{
case EFFECT_TYPE_DISEASE: nCondition = nCondition | AI_CONDITION_DISEASE; break;
case EFFECT_TYPE_POISON: nCondition = nCondition | AI_CONDITION_POISON; break;
case EFFECT_TYPE_CURSE: nCondition = nCondition | AI_CONDITION_CURSE; break;
case EFFECT_TYPE_BLINDNESS:
case EFFECT_TYPE_DEAF: nCondition = nCondition | AI_CONDITION_BLINDDEAF; break;
case EFFECT_TYPE_ABILITY_DECREASE: nCondition = nCondition | AI_CONDITION_ABILITY_DRAIN; break;
case EFFECT_TYPE_NEGATIVELEVEL: nCondition = nCondition | AI_CONDITION_LEVEL_DRAIN; break;
case EFFECT_TYPE_AC_DECREASE: nCondition = nCondition | AI_CONDITION_AC_DECREASE; break;
case EFFECT_TYPE_ATTACK_DECREASE: nCondition = nCondition | AI_CONDITION_ATK_DECREASE; break;
case EFFECT_TYPE_CHARMED: nCondition = nCondition | AI_CONDITION_CHARMED; break;
case EFFECT_TYPE_CONFUSED: nCondition = nCondition | AI_CONDITION_CONFUSED; break;
case EFFECT_TYPE_DAZED: nCondition = nCondition | AI_CONDITION_DAZED; break;
case EFFECT_TYPE_DAMAGE_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_DECREASE; break;
case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE: nCondition = nCondition | AI_CONDITION_DMG_I_DECREASE; break;
case EFFECT_TYPE_DOMINATED: nCondition = nCondition | AI_CONDITION_DOMINATED; break;
case EFFECT_TYPE_FRIGHTENED: nCondition = nCondition | AI_CONDITION_FRIGHTENED; break;
case EFFECT_TYPE_PARALYZE: nCondition = nCondition | AI_CONDITION_PARALYZE; break;
case EFFECT_TYPE_SAVING_THROW_DECREASE: nCondition = nCondition | AI_CONDITION_SAVE_DECREASE; break;
case EFFECT_TYPE_SKILL_DECREASE: nCondition = nCondition | AI_CONDITION_SKILL_DECREASE; break;
case EFFECT_TYPE_SLOW: nCondition = nCondition | AI_CONDITION_SLOW; break;
case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE: nCondition = nCondition | AI_CONDITION_SR_DECREASE; break;
case EFFECT_TYPE_STUNNED: nCondition = nCondition | AI_CONDITION_STUNNED; break;
}
}
eEffect = GetNextEffect(oCreature);
}
return nCondition;
}
int ai_GetIsInLineOfSight(object oCreature, object oObject)
{
// Creatures can block the line of sight so when close we shouldn't check.
if(GetDistanceBetween(oObject, oCreature) <= AI_RANGE_MELEE) return TRUE;
return LineOfSightObject(oCreature, oObject);
}
void ai_SetBehaviorState(int nCondition, int bValid = TRUE)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
if(bValid)
{
nPlot = nPlot | nCondition;
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
}
else
{
nPlot = nPlot & ~nCondition;
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
}
}
int ai_GetBehaviorState(int nCondition)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
if(nPlot & nCondition) return TRUE;
return FALSE;
}
void ai_HighlightWidgetMode(object oPC, object oAssociate, int nToken)
{
if(oPC == oAssociate) return;
int bBool;
bBool = ai_GetAIMode(oAssociate,AI_MODE_DEFEND_MASTER);
NuiSetBind(oPC, nToken, "btn_cmd_guard_encouraged", JsonBool(bBool));
bBool = ai_GetAIMode(oAssociate,AI_MODE_STAND_GROUND);
NuiSetBind(oPC, nToken, "btn_cmd_hold_encouraged", JsonBool(bBool));
bBool = ai_GetAIMode(oAssociate,AI_MODE_FOLLOW);
NuiSetBind(oPC, nToken, "btn_cmd_follow_encouraged", JsonBool(bBool));
if(!ai_GetAIMode(oAssociate, AI_MODE_DEFEND_MASTER) &&
!ai_GetAIMode(oAssociate, AI_MODE_STAND_GROUND) &&
!ai_GetAIMode(oAssociate, AI_MODE_FOLLOW)) bBool = TRUE;
else bBool = FALSE;
NuiSetBind(oPC, nToken, "btn_cmd_attack_encouraged", JsonBool(bBool));
}
void ai_CheckXPPartyScale(object oCreature)
{
object oModule = GetModule();
if(!GetLocalInt(oModule, AI_RULE_PARTY_SCALE)) return;
object oMaster;
if(!ai_GetIsCharacter(oCreature))
{
oMaster = GetMaster(oCreature);
while(oMaster != OBJECT_INVALID)
{
if(ai_GetIsCharacter(oMaster)) break;
oMaster = GetMaster(oMaster);
}
if(oMaster == OBJECT_INVALID) return;
}
else oMaster = oCreature;
float fDefaultXPScale = IntToFloat(GetLocalInt(oModule, AI_BASE_PARTY_SCALE_XP));
float fPartySize = 4.0;
int nAssociateType, nHenchman, nHenchAssociate;
object oHenchman;
for(nAssociateType = 1; nAssociateType <= 5; nAssociateType++)
{
if(nAssociateType == ASSOCIATE_TYPE_HENCHMAN)
{
for(nHenchman = 1; nHenchman <= AI_MAX_HENCHMAN; nHenchman++)
{
oHenchman = GetAssociate(nAssociateType, oMaster, nHenchman);
if(oHenchman != OBJECT_INVALID)
{
fPartySize += 1.0;
for(nHenchAssociate = 2; nHenchAssociate <= 5; nHenchAssociate++)
{
if(GetAssociate(nHenchAssociate, oHenchman, 1) != OBJECT_INVALID) fPartySize += 1.0;
}
}
}
}
else if(GetAssociate(nAssociateType, oMaster, 1) != OBJECT_INVALID) fPartySize += 1.0;
}
int nXPScale = FloatToInt(fPartySize / 4.0 * fDefaultXPScale);
//SendMessageToPC(oMaster, GetName(oMaster) + " nXPScale = (3 + fPartySize / 4.0 * fDefaultXPScale)" +
// IntToString(nXPScale) + " = (" + FloatToString(fPartySize, 0, 1) + " / 4.0 * " +
// FloatToString(fDefaultXPScale, 0, 1) + ")");
SetModuleXPScale(nXPScale);
}