Hi CPK87,
Again, I have not read all the posts here, but I looked at creature AI and have
a flowchart in this thread that may help you, as well as the rest of the posts there.
EDIT: Using X2_SPECIAL_COMBAT_AI_SCRIPT on a creature is the way to go.
Cheers,
Lance.
And here is just a direct copy of my own creature AI script, which I use to enhance the basic AI of many creatures. Note, also that it contains a reference to another specific script for individual creature's special attacks. NOTE: This makes reference to my own include for monsters for some parts, but, hopefully, the gist of what I do and recommend works is here:
// MONSTER AI TEMPLATE (FIND TALENT FUNCTIONS IN x0_i0_talent INCLUDE)
// BASED ON OC TEMPLATE FOUND IN x2_ai_demo.
//#include "nw_i0_generic" (Included via alb_functions)
//#include "x2_inc_switches" (Included via alb_functions)
//#include "x0_i0_talent" (Included via alb_functions)
#include "alb_functions_mon"
// RETURN TRUE IF IT IS SUCCESSFUL AND REQUIRES AN ACTION REQUIRED OR FALSE IF NOT OF FREE ACTION
int LBMakeInvisible(object oTarget = OBJECT_SELF)
{
// ALREADY INVISIBLE (NO ACTION REQUIRED)
if(GetHasSpellEffect(SPELL_DARKNESS, oTarget) || GetHasSpellEffect(SPELL_I_DARKNESS, oTarget)
|| GetHasSpellEffect(SPELL_SHADOW_CONJURATION_DARKNESS, oTarget) || GetHasSpellEffect(SPELL_GREATER_INVISIBILITY, oTarget)
|| GetHasSpellEffect(SPELL_INVISIBILITY, oTarget) || GetHasSpellEffect(724, oTarget)
|| GetHasSpellEffect(SPELL_INVISIBILITY_SPHERE, oTarget) || GetHasSpellEffect(SPELL_ETHEREALNESS, oTarget)
|| GetHasSpellEffect(SPELL_I_RETRIBUTIVE_INVISIBILITY, oTarget) || GetHasSpellEffect(SPELL_I_WALK_UNSEEN, oTarget))
{return FALSE;}
if(GetLocalInt(oTarget, "X2_L_STOPCASTING") == 10)
{
// IF NPC HAS THIS FEAT, THEN USE INSTEAD
if (GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oTarget))
{
SetActionMode(oTarget, ACTION_MODE_STEALTH, TRUE);
return FALSE;
}
}
// TEST IF NPC HAS ONE OF THESE SPELLS TO BECOME INVISIBLE (IN THIS PRIORITY)
int iCastSpell = -1;
if(GetSpellKnown(oTarget, SPELL_ETHEREALNESS)){iCastSpell = SPELL_ETHEREALNESS;}
else if(GetSpellKnown(oTarget, 724)){iCastSpell = 724;} // ETHEREAL JAUNT
else if(GetSpellKnown(oTarget, SPELL_I_RETRIBUTIVE_INVISIBILITY)){iCastSpell = SPELL_I_RETRIBUTIVE_INVISIBILITY;}
else if(GetSpellKnown(oTarget, SPELL_GREATER_INVISIBILITY)){iCastSpell = SPELL_GREATER_INVISIBILITY;}
else if(GetSpellKnown(oTarget, SPELL_I_WALK_UNSEEN)){iCastSpell = SPELL_I_WALK_UNSEEN;}
else if(GetSpellKnown(oTarget, SPELL_INVISIBILITY)){iCastSpell = SPELL_INVISIBILITY;}
else if(GetSpellKnown(oTarget, SPELL_INVISIBILITY_SPHERE)){iCastSpell = SPELL_INVISIBILITY_SPHERE;}
else if(GetSpellKnown(oTarget, SPELL_I_DARKNESS)){iCastSpell = SPELL_I_DARKNESS;}
else if(GetSpellKnown(oTarget, SPELL_DARKNESS)){iCastSpell = SPELL_DARKNESS;}
else if(GetSpellKnown(oTarget, SPELL_SANCTUARY)){iCastSpell = SPELL_SANCTUARY;}
// FALL BACK TO HIDE INPLAIN SIGHT IF AVAILABLE
else if(GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oTarget)){SetActionMode(oTarget, ACTION_MODE_STEALTH, TRUE);}
// VALID SPELL FOUND - CAST ON SELF
if(iCastSpell != -1)
{
// SendMessageToAllPCs("SPELL FOUND AND CAST > ");
ClearAllActions(TRUE);
//DecrementRemainingSpellUses(oTarget, iCastSpell); // DOES NOT WORK WITH NPCS (TRACK ANOTHER WAY)
// IF THE NPC MEETS REQUIREMENTS OF SPELL CASTING (CHEAT FALSE BELOW), THEN WIZARD SPELL USE IS TRACKED AUTOMATICALLY
ActionCastSpellAtObject(iCastSpell, oTarget, METAMAGIC_ANY, FALSE);
return TRUE;
}
else{return FALSE;}
}
// HEAL ALLIES IF POSSIBLE
int LBTalentHealAlly(object oAlly)
{
int bValid = FALSE;
if(TrySpellGroup(SPELL_HEAL, SPELL_MASS_CURE_CRITICAL_WOUNDS, SPELL_MASS_CURE_SERIOUS_WOUNDS, SPELL_MASS_CURE_MODERATE_WOUNDS, oAlly) == TRUE){bValid = TRUE;}
if(bValid == FALSE)
{
if(TrySpellGroup(SPELL_MASS_CURE_LIGHT_WOUNDS, SPELL_CURE_CRITICAL_WOUNDS, SPELL_CURE_SERIOUS_WOUNDS, SPELL_CURE_LIGHT_WOUNDS, oAlly) == TRUE){bValid = TRUE;}
}
if(bValid == FALSE)
{
if(TrySpell(SPELL_CURE_MINOR_WOUNDS, oAlly) == TRUE){bValid = TRUE;}
}
return bValid;;
}
// FLEE COMBAT AND HOSTILES
int LBTalentFlee(object oIntruder)
{
if(!GetIsObjectValid(oIntruder))
{
oIntruder = GetLastHostileActor();
if(!GetIsObjectValid(oIntruder) || GetIsDead(oIntruder))
{
oIntruder = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if(!GetIsObjectValid(oIntruder)){return FALSE;}
}
}
ClearAllActions(TRUE);
ActionMoveAwayFromObject(oIntruder, TRUE, 40.0f);
return TRUE;
}
void main()
{
// DO NOT RUN IF PLAYED BY A PLAYER
if(GetMainPC(OBJECT_SELF) != OBJECT_INVALID){return;}
// The following two lines should not be touched
object oTarget = GetCreatureOverrideAIScriptTarget();
ClearCreatureOverrideAIScriptTarget();
// IT APPEARS OTARGET IS LOST AFTER FIRST DESIGNATION
object oNPC = OBJECT_SELF;
// ONLY RUN IF PLAYERS ARE IN THE SAME AREA AS THIS CREATURE
if(GetArea(GetFirstPC()) != GetArea(oNPC)){return;}
// ENSURE TARGET IS VALID
if(oTarget == OBJECT_INVALID || GetIsDead(oTarget)){oTarget = GetLocalObject(oNPC, "CurrentTarget");}
if(oTarget == OBJECT_INVALID || GetIsDead(oTarget)){oTarget = GetNearestLiveEnemy();}
SetLocalObject(oNPC, "CurrentTarget", oTarget);
// ********************* Start of custom AI script ****************************
// SendMessageToAllPCs("AI FIRED " + GetTag(OBJECT_SELF)); // DEBUG
// GET CURRENT ATTACK MODE OF CREATURE (ACTIVE OR PASSIVE)
int iPASSIVE = GetLocalInt(oNPC, "SETPASSIVE");
// DEBUG GETHASSPELL FUNCTION (SOMETIMES COMES UP DESCRIBED AS GETHASSPELLEFFECT FUNCTION - WEIRD?)
// SendMessageToAllPCs("INVIS SPELL > " + IntToString(GetHasSpell(SPELL_INVISIBILITY, oNPC)));
// SendMessageToAllPCs("INVIS EFFECT > " + IntToString(GetHasSpellEffect(SPELL_INVISIBILITY, oNPC)));
// SendMessageToAllPCs("INVIS KNOWN > " + IntToString(GetSpellKnown(oNPC, SPELL_INVISIBILITY)));
// NOTE: To make a creature cast spells (and be limited by number memorised), then add the
// spell via the wizard/cleric/druid class and ensure the creature DOES MEET spell ability. i.e. CHEAT FALSE.
// To allow a creature to have "limitless" spells, then if using the same class, simply add spell
// the same way, but ensure creature does not meet spell casting ability and change the CHEAT to TRUE.
// ALTERNATE METHOD: Using a class that does not "memorise" (Spirit Shaman) allows unlimited uses.
// NB: MAKE SURE THE "WIZARD" DOES NOT DROP A CAPTURED SPELL BOOK BY ADDING "NOSPELLBOOK" VAR 1.
// DO NOT INTERRUPT A CURRENT MOVE OR SPELL CASTING
if(GetCurrentAction(oNPC)==ACTION_CASTSPELL || GetCurrentAction(oNPC)==ACTION_MOVETOPOINT)
{SetCreatureOverrideAIScriptFinished();}
// TEST THESE EVENTS ////////////////////////////////////////////////////////////////
// ADD ALL AS SPECIAL ABILITIES (SPELLS SOMETIMES TAKE PRIORITY)
// KNOCKDOWN IS A FREE ACTION IF POSSIBLE (ASSIGN THE FEAT - NORMAL OR IMPROVED)
if(iPASSIVE == 0){TalentKnockdown(oTarget);}
// HIDE / BECOME INVISIBLE IF POSSIBLE (nw_i0_generic)
// if(GetLocalInt(oNPC, "WILLFLEE") == 0 && LBMakeInvisible() == TRUE){SetCreatureOverrideAIScriptFinished();}
// NOT REALLY NEEDED HERE .. SAVE FOR JUST FLEEING ... ADD A BUFF INSTEAD?
// PRIORITY HEALING < 25% HPS (ONLY GIVE HEALING ITEMS IF INTEND TO USE IN COMBAT)
// UNDEAD CONSTRUCTS & OOZES CANNOT USE THIS TALENT
if(GetPercentageHPLoss(oNPC) < 25 && TalentHealingSelf(TRUE) == TRUE){SetCreatureOverrideAIScriptFinished();}
// CREATURES DECIDES TO FLEE (HUMANOIDS ONLY)
if(GetPercentageHPLoss(oNPC) < 25 && AmIAHumanoid(oNPC) == TRUE && GetLocalInt(oNPC, "WILLFLEE") == 1)
{
if(LBMakeInvisible() == TRUE){SetCreatureOverrideAIScriptFinished();}
else if(LBTalentFlee(oTarget) == TRUE){SetCreatureOverrideAIScriptFinished();}
// DO NOT DO ANYTHING ELSE AFTER FLEEING EXCEPT 1 HP RECOVER PER ROUND (TO ALLOW ATTACK AGAIN)
FloatingTextStringOnCreature("** FLEEING **", OBJECT_SELF, FALSE);
int HealPercent = FloatToInt(5.0/100.0 * IntToFloat(GetMaxHitPoints(oNPC)));
if(HealPercent < 1){HealPercent = 1; SendMessageToAllPCs("HEALING");}
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(HealPercent), oNPC);
return;
}
// TRY TO INITIALISE A RAGE EFFECT
if(GetLocalInt(oNPC, "RAGER") == 1 && GetLocalInt(oNPC, "RAGECHECKED") == 0)
{SetLocalInt(oNPC, "RAGECHECKED", 1); ExecuteScript("nw_s1_barbrage", oNPC); SetCreatureOverrideAIScriptFinished();}
// TRY TO DO A SPECIAL ATTACK
string sSA = GetLocalString(oNPC, "AdditionalAIScript");
if(sSA != ""){ExecuteScript(sSA, oNPC); SetCreatureOverrideAIScriptFinished();}
// HEAL ANY ALLIES IF POSSIBLE
object oAlly = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, oNPC, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if(oAlly == OBJECT_INVALID){oAlly = oNPC;}
if(oAlly != OBJECT_INVALID && GetPercentageHPLoss(oAlly) < 50){if(LBTalentHealAlly(oAlly) == TRUE){SetCreatureOverrideAIScriptFinished();}}
// BUFF OTHERS OR SELF WITH SPELL (SEE SPELLS POSSIBLE BELOW)
if(TalentAdvancedBuff2(oAlly, oTarget) == TRUE){SetCreatureOverrideAIScriptFinished();}
// USE ANY POTIONS CARRIED
if(TalentBuffSelf() == TRUE){SetCreatureOverrideAIScriptFinished();}
// BREATH WEAPON - USE CONES
// SPECIAL ABILITY SPELL CAST PRIORITY (OTHER SPELLS HANDLED VIA CLASS SPELLS)
// DO ONLY D4 TIMES TO ALLOW REMAINDER OF USAGE TO CAST ANOTHER DAY IF NEED BE
int SpellAbilityAttack = GetLocalInt(oNPC, "SPELLABILITYATTACK") + 1;
// RANDOMIZE D10 EACH USAGE (DELETE WHEN PLAYER LEAVES AREA) GIVE 30 + CHARGES FOR REUSE
if(SpellAbilityAttack <= d10()){if(TalentSpellAttack(oTarget) == TRUE)
{SetLocalInt(oNPC, "SPELLABILITYATTACK", SpellAbilityAttack); SetCreatureOverrideAIScriptFinished();}}
// CREATURE HEALS ITSELF (ONLY GIVE HEALING ITEMS IF INTEND TO USE IN COMBAT)
// UNDEAD CONSTRUCTS & OOZES CANNOT USE THIS TALENT
if(GetPercentageHPLoss(oNPC) < 50 && TalentHealingSelf(TRUE) == TRUE){SetCreatureOverrideAIScriptFinished();}
// JUST DO AN NORMAL ATTACK BY LETTING THE NORMAL AI FIRE NOW
else
{
// ENSURE CORRECT WEAPON IS CHOSEN DURING COMBAT WITH PC (INITIALLY SET ON PERCEPTION)
ChangeWeaponCheck(oNPC, oTarget);
// ATTACK MODE ACTIVE/PASSIVE MAY HAVE BEEN ALTERED IN THE FUNCTION ABOVE
iPASSIVE = GetLocalInt(oNPC, "SETPASSIVE");
AssignCommand(oNPC, ActionAttack(oTarget, iPASSIVE));
}
// ********************* End of custom AI script ****************************
// This line *** has to be called here *** or the default AI will take over from
// this point and really bad things are going to happen
SetCreatureOverrideAIScriptFinished(); // < ---- REM OUT TO ALLOW A NORMAL ROUND NOW (CANNOT CONTINUES SPELLS)
}
/* TALENT ADVANCED BUFF 2 USES (BASED ON OPPONENT HD)
SPELL_PREMONITION, SPELL_GREATER_STONESKIN, SPELL_I_DARK_FORESIGHT, SPELL_STONESKIN
SPELL_GREATER_INVISIBILITY SPELL_I_RETRIBUTIVE_INVISIBILITY
SPELL_MIRROR_IMAGE, SPELL_DISPLACEMENT
SPELL_SHADOW_SHIELD, SPELL_ETHEREAL_VISAGE, SPELL_GHOSTLY_VISAGE
SPELL_ELEMENTAL_SHIELD, SPELL_DEATH_ARMOR
SPELL_MIND_BLANK, SPELL_LESSER_MIND_BLANK
SPELL_ENERGY_IMMUNITY, SPELL_PROTECTION_FROM_ENERGY, SPELL_RESIST_ENERGY, SPELL_ENDURE_ELEMENTS
// AURAS - SEE ALSO ALB_MON_SPAWNSCRIPT FOR VISUAL EFFECT & NEW AURAS
// BUFFS - A MONSTER WILL TRY TO USE THE FOLLOWING (ADD TO CREATURE TO USE IN THEIR HB)
/*Combat Protections
SPELL_PREMONITION
SPELL_GREATER_STONESKIN
SPELL_STONESKIN
//Visage Protections
SPELL_SHADOW_SHIELD
SPELL_ETHEREAL_VISAGE
SPELL_GHOSTLY_VISAGE
//Mantle Protections
SPELL_GREATER_SPELL_MANTLE
SPELL_SPELL_MANTLE
SPELL_LESSER_SPELL_BREACH
// Globes
SPELL_GLOBE_OF_INVULNERABILITY
SPELL_LESSER_GLOBE_OF_INVULNERABILITY
//Misc Protections
SPELL_ELEMENTAL_SHIELD
SPELL_MESTILS_ACID_SHEATH
SPELL_DEATH_ARMOR
//Elemental Protections
SPELL_PROTECTION_FROM_ENERGY
SPELL_RESIST_ENERGY
SPELL_ENDURE_ELEMENTS
//Mental Protections
SPELL_MIND_BLANK
SPELL_LESSER_MIND_BLANK
SPELL_CLARITY
//Summon Ally
SPELL_BLACK_BLADE_OF_DISASTER
SPELL_SUMMON_CREATURE_IX
SPELL_SUMMON_CREATURE_VIII
SPELL_SUMMON_CREATURE_VII
SPELL_SUMMON_CREATURE_VI
SPELL_SUMMON_CREATURE_V
SPELL_SUMMON_CREATURE_IV
SPELL_SUMMON_CREATURE_III
SPELL_SUMMON_CREATURE_II
SPELL_SUMMON_CREATURE_I
Modifié par Lance Botelle, 15 février 2014 - 02:50 .