WoR_PRC8/_module/nss/j_cai_necro.nss
Jaysyn904 b5e28e52f4 Initial commit
Initial commit [1.18]
2025-04-03 11:49:34 -04:00

181 lines
6.7 KiB
Plaintext

/************************ [Necromancer (Low) Custom AI] ************************
Filename: J_CAI_Necro
************************* [Necromancer (Low) Custom AI] ************************
This is a custom AI file for necromancers.
It will summon 3 skeletons (by creating them, and adding them as faction
members) until it has 3, 1 each round. Healing is done normally, so it
should be a non-undead necromancer (Necromancers are meant to be not undead!)
It will cheat-cast negative spells, "Negative Energy Ray" and "Negative energy
Burst". Spells it'll cast on self ar "Negative energy protection" and
"Mage armor". Pretty odd selection, but this is only a sample AI.
Also note the skeletons hang around at the end. It could be scripted to
destroy all skeletons OnDeath too.
Note:
- Add negative spells to heal undead allies.
- All other spells are cheat-cast (when cast at enemies)
- CR of necromancer should be 4-8.
Ideas:
- Modify to summon "Deer" for a ranger, or "Dogs" for a dog trainer, the functions
ActionCreateAlly() and CountCreaturesOfTagInFaction() can be changed to
check for amounts of these exsisting, and "summon" new ones.
************************* [History] ********************************************
1.3 - Added as sample
************************* [Workings] *******************************************
Uses Combat_GetAITargetObject, to see if we saw something new or something.
Then we do:
- Summon an extra skeleton (From default pallet) if we have under 5
- Healing self with normal arrangements
- Heal undead around us
- Defend self with spells
- Use negative attacks
************************* [Arguments] ******************************************
Arguments: N/A
************************* [Necromancer (Low) Custom AI] ***********************/
// Useful custom AI functions here
#include "J_INC_BASIC"
// Amount of skeletons to summon. 1-4 are OK, 5-7 are a hell of a lot! 8+ are too many.
const int SKELETONS_MAX = 3;
// Counts amount of creatures of tag sTag, that are in the area and in the same
// faction as the caster.
int CountCreaturesOfTagInFaction(string sTag);
// Summon a undead ally of sResRef, with casting animations and effects, using
// nVisEffect for the visual effect applied to the created creature.
void ActionCreateAlly(string sResRef, int nVisEffect = VFX_FNF_SUMMON_UNDEAD);
void main()
{
// If we have summoned an undead in the last 3 seconds, stop. Set in ActionCreateAlly.
if(GetLocalInt(OBJECT_SELF, "SUMMONING")) return;
// Get the target to attack
object oTarget = Combat_GetAITargetObject();
// Check if valid
// - Can be seen or heard
if(!Combat_GetTargetValid(oTarget))
{
// Nearest seen or heard enemy. If not valid, stop the script.
oTarget = Combat_GetNearestSeenOrHeardEnemy();
if(!GetIsObjectValid(oTarget))
{
// Heal ourselves after combat.
if(Combat_HealTarget(OBJECT_SELF)) return;
// Walk waypoints if we do not heal
Combat_WalkWaypoints();
return;
}
}
// Do combat.
// Heal ourselves first, if under 50% HP.
Combat_HealTarget(OBJECT_SELF);
// Get amount of skeletons by tag "NW_SKELWARR01"
int nFollowers = CountCreaturesOfTagInFaction("NW_SKELWARR01");
// May also check for the second skeleton that we create, "NW_SKELWARR02",
// and check how many of them there are.
if(nFollowers < SKELETONS_MAX)
{
// Add it onto the exsisting nFollowers.
nFollowers += CountCreaturesOfTagInFaction("NW_SKELWARR02");
}
// We will summon more if nFollowers is < SKELETONS_MAX (Default: 3).
if(nFollowers < SKELETONS_MAX)
{
// Stop, and summon
// There are 2 suitable undead - warriors that is.
// - Skeleton Warrior 6 nw_skelwarr01 NW_SKELWARR01
// - Skeleton Warrior 6 nw_skelwarr02 NW_SKELWARR02
string sUse = "nw_skelwarr0" + IntToString(d2());
// Use function created for it (so we could modify to make it, say,
// summon deer).
ActionCreateAlly(sUse);
return;
}
// Heal undead allies (or other allies) using spells we know
object oMostDamaged = GetFactionMostDamagedMember();
// Check if undead
if(GetIsObjectValid(oMostDamaged))
{
if(GetRacialType(oMostDamaged) == RACIAL_TYPE_UNDEAD)
{
// Heal this undead with negative spells
if(Combat_CastAtObject(SPELL_NEGATIVE_ENERGY_BURST, oMostDamaged)) return;
if(Combat_CastAtObject(SPELL_NEGATIVE_ENERGY_RAY, oMostDamaged)) return;
}
else
{
// Normal heal
Combat_HealTarget(oMostDamaged);
}
}
// Cheat cast hostile, and defensive, spells.
// Negative energy protection - 90
if(Combat_CheatRandomSpellAtObject(SPELL_NEGATIVE_ENERGY_PROTECTION, OBJECT_SELF, 90)) return;
// Mage armor - 60
if(Combat_CheatRandomSpellAtObject(SPELL_MAGE_ARMOR, OBJECT_SELF, 60)) return;
// Negative energy burst - 50
if(Combat_CheatRandomSpellAtObject(SPELL_NEGATIVE_ENERGY_BURST, oTarget, 50)) return;
// Negative energy ray - 100
if(Combat_CheatRandomSpellAtObject(SPELL_NEGATIVE_ENERGY_RAY, oTarget, 100)) return;
}
// Counts amount of creatures of tag sTag, that are in the area and in the same
// faction as the caster.
int CountCreaturesOfTagInFaction(string sTag)
{
// Get amount of followers to return
int nFollowers = 0;
int nCnt = 1;
object oUndead = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
while(GetIsObjectValid(oUndead))
{
if(GetFactionEqual(oUndead))
{
// Add 1 to the followers
nFollowers++;
}
nCnt++;
oUndead = GetNearestObjectByTag(sTag, OBJECT_SELF, nCnt);
}
return nFollowers;
}
// Summon a undead ally of sResRef, with casting animations and effects, using
// nVisEffect for the visual effect applied to the created creature.
void ActionCreateAlly(string sResRef, int nVisEffect = VFX_FNF_SUMMON_UNDEAD)
{
// Stop, and summon
ClearAllActions();
// Fake cast spell
ActionCastFakeSpellAtObject(SPELL_CREATE_GREATER_UNDEAD, OBJECT_SELF);
object oNewUndead = CreateObject(OBJECT_TYPE_CREATURE, sResRef, GetLocation(OBJECT_SELF));
// Add to our faction
ChangeFaction(oNewUndead, OBJECT_SELF);
// Apply visual effect to new creature after a few seconds
effect eVis = EffectVisualEffect(nVisEffect);
DelayCommand(0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oNewUndead));
SetLocalInt(OBJECT_SELF, "SUMMONING", TRUE);
DelayCommand(3.0, DeleteLocalInt(OBJECT_SELF, "SUMMONING"));
return;
}