2025/11/30 Update
Updated for NWN:EE 37-17 Updated NWNxEE libraries. Updated nim tooling Updated PEPs Associated new GUI module event script. Full compile.
This commit is contained in:
@@ -152,6 +152,8 @@ void ai_AmbientAnimations();
|
||||
|
||||
void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID)
|
||||
{
|
||||
object oMaster = GetMaster(oCreature);
|
||||
if(GetLocalInt(oMaster, AI_TARGET_MODE_ON) && GetLocalObject(oMaster, AI_TARGET_MODE_ASSOCIATE) == oCreature) return;
|
||||
if(ai_StayClose(oCreature)) return;
|
||||
// Is the target our Player has locked in dead? If so then clear it.
|
||||
if(GetIsDead(GetLocalObject(oCreature, AI_PC_LOCKED_TARGET))) DeleteLocalObject(oCreature, AI_PC_LOCKED_TARGET);
|
||||
@@ -176,21 +178,27 @@ void ai_DoAssociateCombatRound(object oCreature, object oTarget = OBJECT_INVALID
|
||||
// the polymorph AI script.
|
||||
if(sAI != "ai_coward" && sAI != "ai_a_peaceful")
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "173", "Should we use polymorph? " +
|
||||
IntToString(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature)));
|
||||
if(AI_DEBUG)
|
||||
{
|
||||
ai_Debug("0i_actions", "181", "Should we use polymorph? Current: " +
|
||||
IntToString(GetAppearanceType(oCreature)) + " Normal: " + IntToString(ai_GetNormalAppearance(oCreature)));
|
||||
if(ai_GetIsHidden(oCreature))
|
||||
{
|
||||
ai_Debug("0i_actions", "179", "We are hidden!" +
|
||||
ai_Debug("0i_actions", "185", "We are hidden!" +
|
||||
" Can they see us? " + IntToString(ai_GetNearestIndexThatSeesUs(oCreature)));
|
||||
}
|
||||
}
|
||||
if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature))
|
||||
if(ai_GetIsHidden(oCreature) && !ai_GetNearestIndexThatSeesUs(oCreature)) sAI = "ai_a_invisible";
|
||||
else if(GetAppearanceType(oCreature) != ai_GetNormalAppearance(oCreature))
|
||||
{
|
||||
sAI = "ai_a_polymorphed";
|
||||
if(!GetLocalInt(oCreature, AI_POLYMORPHED))
|
||||
{
|
||||
SetLocalInt(oCreature, AI_POLYMORPHED, TRUE);
|
||||
ai_ClearTalents(oCreature);
|
||||
ai_SetCreatureSpecialAbilityTalents(oCreature, FALSE, TRUE);
|
||||
}
|
||||
}
|
||||
else if(ai_GetIsHidden(oCreature) && !ai_GetNearestIndexThatSeesUs(oCreature)) sAI = "ai_a_invisible";
|
||||
}
|
||||
if(sAI == "") sAI = "ai_a_default";
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "190", "********** " + GetName (oCreature) + " **********");
|
||||
@@ -226,11 +234,24 @@ void ai_DoMonsterCombatRound(object oMonster)
|
||||
string sAI = GetLocalString(oMonster, AI_COMBAT_SCRIPT);
|
||||
if(sAI != "ai_coward")
|
||||
{
|
||||
if(GetAppearanceType(oMonster) != ai_GetNormalAppearance(oMonster))
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "235", "Should we use polymorph? Current: " +
|
||||
IntToString(GetAppearanceType(oMonster)) + " Normal: " + IntToString(ai_GetNormalAppearance(oMonster)));
|
||||
if(ai_GetIsHidden(oMonster))
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "239", "We are hidden!" +
|
||||
" Can they see us? " + IntToString(ai_GetNearestIndexThatSeesUs(oMonster)));
|
||||
}
|
||||
if(ai_GetIsHidden(oMonster) && !ai_GetNearestIndexThatSeesUs(oMonster)) sAI = "ai_invisible";
|
||||
else if(GetAppearanceType(oMonster) != ai_GetNormalAppearance(oMonster))
|
||||
{
|
||||
sAI = "ai_polymorphed";
|
||||
if(!GetLocalInt(oMonster, AI_POLYMORPHED))
|
||||
{
|
||||
SetLocalInt(oMonster, AI_POLYMORPHED, TRUE);
|
||||
ai_ClearTalents(oMonster);
|
||||
ai_SetCreatureSpecialAbilityTalents(oMonster, TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
else if(ai_GetIsHidden(oMonster) && !ai_GetNearestIndexThatSeesUs(oMonster)) sAI = "ai_invisible";
|
||||
}
|
||||
if(sAI == "") sAI = "ai_default";
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "230", "********** " + GetName (oMonster) + " **********");
|
||||
@@ -277,7 +298,7 @@ int ai_StayClose(object oCreature)
|
||||
if(fPerceptionDistance == 0.0)
|
||||
{
|
||||
fPerceptionDistance = GetLocalFloat(oMaster, AI_ASSOC_PERCEPTION_DISTANCE);
|
||||
if(fPerceptionDistance == 0.0) fPerceptionDistance = 20.0;
|
||||
if(fPerceptionDistance == 0.0) fPerceptionDistance = 25.0;
|
||||
}
|
||||
object oTarget = GetLocalObject(oCreature, AI_FOLLOW_TARGET);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = oMaster;
|
||||
@@ -521,11 +542,11 @@ int ai_MoralCheck(object oCreature)
|
||||
if(nHpPercent <= AI_HEALTH_WOUNDED)
|
||||
{
|
||||
// Debug code to look for multiple moral checks at once by one creature?
|
||||
if(GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) == "")
|
||||
{
|
||||
SetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE, GetName(oCreature));
|
||||
ai_Debug("0i_actions", "424", GetName(oCreature) + " starting debug mode to test Moral checks!");
|
||||
}
|
||||
//if(GetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE) == "")
|
||||
//{
|
||||
// SetLocalString(GetModule(), AI_RULE_DEBUG_CREATURE, GetName(oCreature));
|
||||
// ai_Debug("0i_actions", "424", GetName(oCreature) + " starting debug mode to test Moral checks!");
|
||||
//}
|
||||
if(nHpPercent <= AI_HEALTH_BLOODY) nDC = AI_BLOODY_MORAL_DC;
|
||||
else nDC = AI_WOUNDED_MORAL_DC;
|
||||
nDC = nDC - GetLocalInt(oCreature, AI_ALLY_NUMBERS);
|
||||
@@ -681,17 +702,17 @@ void ai_DoPhysicalAttackOnBest(object oCreature, int nInMelee, int bAlwaysAtk =
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
|
||||
}
|
||||
if(oTarget != OBJECT_INVALID)
|
||||
{
|
||||
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
|
||||
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
|
||||
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
|
||||
return;
|
||||
@@ -739,17 +760,17 @@ void ai_DoPhysicalAttackOnNearest(object oCreature, int nInMelee, int bAlwaysAtk
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestPhysicalTarget(oCreature, AI_RANGE_MELEE);
|
||||
}
|
||||
if(oTarget != OBJECT_INVALID)
|
||||
{
|
||||
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
|
||||
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "519", "Do ranged attack against nearest: " + GetName(oTarget) + "!");
|
||||
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
|
||||
return;
|
||||
@@ -796,17 +817,17 @@ void ai_DoPhysicalAttackOnLowestCR(object oCreature, int nInMelee, int bAlwaysAt
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_DEFEND_MASTER)) oTarget = ai_GetLowestCRAttackerOnMaster(oCreature);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetNearestFavoredEnemyTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRTarget(oCreature, AI_RANGE_MELEE);
|
||||
if(oTarget == OBJECT_INVALID) oTarget = ai_GetLowestCRPhysicalTarget(oCreature, AI_RANGE_MELEE);
|
||||
}
|
||||
if(oTarget != OBJECT_INVALID)
|
||||
{
|
||||
if(ai_TryRapidShotFeat(oCreature, oTarget, nInMelee)) return;
|
||||
if(ai_TryRangedTalents(oCreature, oTarget, nInMelee)) return;
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "559", GetName(OBJECT_SELF) + " does ranged attack on weakest: " + GetName(oTarget) + "!");
|
||||
ai_ActionAttack(oCreature, AI_LAST_ACTION_RANGED_ATK, oTarget, nInMelee, TRUE);
|
||||
return;
|
||||
@@ -1112,7 +1133,7 @@ void ai_ActionTryHealing(object oCreature, object oTarget)
|
||||
}
|
||||
int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "733", "Try healing: oCreature: " + GetName(oCreature) +
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1136", "Try healing: oCreature: " + GetName(oCreature) +
|
||||
" oTarget: " + GetName(oTarget) + " No Party Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_PARTY_HEALING_OFF)) +
|
||||
" No Self Healing: " + IntToString(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF)) +
|
||||
" AI_I_AM_BEING_HEALED: " + IntToString(GetLocalInt(oTarget, "AI_I_AM_BEING_HEALED")) +
|
||||
@@ -1133,52 +1154,92 @@ int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
|
||||
oCreature != oTarget) return FALSE;
|
||||
if(ai_GetAIMode(oCreature, AI_MODE_SELF_HEALING_OFF) &&
|
||||
oCreature == oTarget) return FALSE;
|
||||
// Undead don't heal so lets skip this for them, maybe later we can fix this.
|
||||
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD) return FALSE;
|
||||
int nHpLost = ai_GetPercHPLoss(oTarget);
|
||||
// If the player is forcing a heal then we always heal.
|
||||
if(bForce && nHpLost < 100) nHpLost = 0;
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "743", "nHpLost: " + IntToString(nHpLost) +
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1160", "nHpLost: " + IntToString(nHpLost) +
|
||||
" limit: " + IntToString(ai_GetHealersHpLimit(oTarget, FALSE)));
|
||||
if(nHpLost >= ai_GetHealersHpLimit(oTarget, FALSE))
|
||||
// Check to see if we need poison, disease, or ability drain removed.
|
||||
int nEffectType;
|
||||
effect eEffect = GetFirstEffect(oTarget);
|
||||
while(GetIsEffectValid(eEffect))
|
||||
{
|
||||
// Check to see if we need poison, disease, or ability drain removed.
|
||||
int nEffectType;
|
||||
effect eEffect = GetFirstEffect(oTarget);
|
||||
while(GetIsEffectValid(eEffect))
|
||||
nEffectType = GetEffectType(eEffect);
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1168", "Checking to cure(31/32/39) nEffectType: " + IntToString(nEffectType));
|
||||
if(nEffectType == EFFECT_TYPE_DISEASE)
|
||||
{
|
||||
nEffectType = GetEffectType(eEffect);
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1094", "Checking to cure(31/32/39) nEffectType: " + IntToString(nEffectType));
|
||||
if(nEffectType == EFFECT_TYPE_DISEASE)
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1171", GetName(oTarget) + " is diseased!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_DISEASED, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1097", "I am diseased!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_DISEASED, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(!d20()) ai_HaveCreatureSpeak(oCreature, 5, ":43:4:14:15:16:");
|
||||
SpeakString(AI_I_AM_DISEASED, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 5, ":43:4:14:15:16:");
|
||||
SpeakString(AI_I_AM_DISEASED, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
else if(nEffectType == EFFECT_TYPE_POISON)
|
||||
}
|
||||
else if(nEffectType == EFFECT_TYPE_POISON)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1181", GetName(oTarget) + " is poisoned!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_POISONED, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1107", "I am poisoned!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_POISONED, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(!d20()) ai_HaveCreatureSpeak(oCreature, 6, ":43:4:14:15:16:19:");
|
||||
SpeakString(AI_I_AM_POISONED, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 6, ":43:4:14:15:16:19:");
|
||||
SpeakString(AI_I_AM_POISONED, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
else if(nEffectType == EFFECT_TYPE_ABILITY_DECREASE)
|
||||
}
|
||||
else if(nEffectType == EFFECT_TYPE_ABILITY_DECREASE)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1191", GetName(oTarget) + " is weak!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_WEAK, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "1117", "I am weak!");
|
||||
if(ai_HealSickness(oCreature, oTarget, ai_GetPlayerMaster(oCreature), AI_ALLY_IS_WEAK, bForce)) return TRUE;
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
if(!d20()) ai_HaveCreatureSpeak(oCreature, 3, ":43:4:5:");
|
||||
SpeakString(AI_I_AM_WEAK, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
if(!Random(20)) ai_HaveCreatureSpeak(oCreature, 3, ":43:4:5:");
|
||||
SpeakString(AI_I_AM_WEAK, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
eEffect = GetNextEffect(oTarget);
|
||||
}
|
||||
eEffect = GetNextEffect(oTarget);
|
||||
}
|
||||
// Everything below here is for healing.
|
||||
if(nHpLost >= ai_GetHealersHpLimit(oTarget, FALSE)) return FALSE;
|
||||
// Undead require inflict spells to heal!
|
||||
object oMaster = ai_GetPlayerMaster(oCreature);
|
||||
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
// Do we have no magic on?
|
||||
if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC))
|
||||
{
|
||||
int nClass, nPosition = 1;
|
||||
string sMemorized;
|
||||
while(nPosition <= AI_MAX_CLASSES_PER_CHARACTER)
|
||||
{
|
||||
nClass = GetClassByPosition(nPosition, oCreature);
|
||||
if(AI_DEBUG) ai_Debug("0i_actions", "753", "nClass: " + IntToString(nClass));
|
||||
if(nClass == CLASS_TYPE_INVALID) break;
|
||||
sMemorized = Get2DAString("classes", "MemorizesSpells", nClass);
|
||||
// If Memorized column is "" then they are not a caster.
|
||||
if(sMemorized != "")
|
||||
{
|
||||
if(sMemorized == "1")
|
||||
{
|
||||
if(ai_CastMemorizedInflict(oCreature, oTarget, oMaster, nClass))
|
||||
{
|
||||
SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if(ai_CastKnownInflict(oCreature, oTarget, oMaster, nClass))
|
||||
{
|
||||
SetLocalInt(oTarget, "AI_I_AM_BEING_HEALED", TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
nPosition++;
|
||||
}
|
||||
}
|
||||
// We can't heal ourselves! Can any of our allies? Lets ask.
|
||||
if(oCreature == oTarget)
|
||||
{
|
||||
SetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT", GetLocalInt(oCreature, "AI_WOUNDED_SHOUT_LIMIT") + 1);
|
||||
SpeakString(AI_I_AM_WOUNDED, TALKVOLUME_SILENT_TALK);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1192,7 +1253,6 @@ int ai_TryHealing(object oCreature, object oTarget, int bForce = FALSE)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
object oMaster = ai_GetPlayerMaster(oCreature);
|
||||
// Do we have no magic on?
|
||||
if(!ai_GetMagicMode(oCreature, AI_MAGIC_NO_MAGIC))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user