how do you properly script spell casters?
sarevok57
Member Posts: 6,002
*sigh*
im having a hell of a time with this, sometimes scripts work, sometimes they dont, sometimes they just do whatever they damn well please
i can NEVER consistently make it so spell casters 100% cast spells correctly,
usually they will cast spells ( when they actually feel like doing so ) but sometimes they will just start their script over again ( so for example if they cast invisibility, mage armor, color spray, burning hands, ray of frost, ray of frost in this order ) and once they get to the burning hands part, my character will hit them in combat and sometimes they will just start over again and go back to invisibility and go down the list once more
and sometimes they just get stuck in an infinite loop where they will cast invisibility then haste then mage armor, and do nothing and if i attack then they just continue to cast those 3 spells over and over again forever with no end
does someone out there, know how to PROPERLY script casters so they will ONLY cast their spells when they are supposed to, AND do it when the PC is around and not have to wait to be attacked before they do something
i can't believe the frustration i am having over this nonsense, the toolset or this engine just in general is super unintuitive when it comes to scripting spell casters
im having a hell of a time with this, sometimes scripts work, sometimes they dont, sometimes they just do whatever they damn well please
i can NEVER consistently make it so spell casters 100% cast spells correctly,
usually they will cast spells ( when they actually feel like doing so ) but sometimes they will just start their script over again ( so for example if they cast invisibility, mage armor, color spray, burning hands, ray of frost, ray of frost in this order ) and once they get to the burning hands part, my character will hit them in combat and sometimes they will just start over again and go back to invisibility and go down the list once more
and sometimes they just get stuck in an infinite loop where they will cast invisibility then haste then mage armor, and do nothing and if i attack then they just continue to cast those 3 spells over and over again forever with no end
does someone out there, know how to PROPERLY script casters so they will ONLY cast their spells when they are supposed to, AND do it when the PC is around and not have to wait to be attacked before they do something
i can't believe the frustration i am having over this nonsense, the toolset or this engine just in general is super unintuitive when it comes to scripting spell casters
0
Comments
coding a specific order of spellcasting is something I never heard of - some randomization is usually welcome because especially in PW environment, same order is easily exploitable
so most builders don't care and they just put the spells to npc they want and leave it be
I recommend to read: https://neverwintervault.org/article/tutorial/tutorial-vanilla-community-patch-ai-depth
It is not covering what you want to do, but it is still very informative tutorial for anyone dealing with vanilla NPC AI.
If you are experienced with scripting I can send you npc-specific AI using vanilla AI routines that can be easily modified to do what you want to do. But if you aren't scripter it will be useless for you. This however gave me idea to create a dynamic npc-specific AI that would allow to do this just with variables...
so here is the exact script of one of the lizard folk;
void main()
{
object oPC = GetLastPerceived();
if(!(GetPlotFlag(OBJECT_SELF)))
{
if(GetIsPC(oPC))
{
ActionCastSpellAtObject(SPELL_INVISIBILITY, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_HASTE, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_SLOW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_FLAME_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_FLAME_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MELFS_ACID_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MELFS_ACID_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_GEDLEES_ELECTRIC_LOOP, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_GEDLEES_ELECTRIC_LOOP, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_COLOR_SPRAY, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_NEGATIVE_ENERGY_RAY, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BURNING_HANDS, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BURNING_HANDS, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BURNING_HANDS, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_DAZE, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_ACID_SPLASH, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_ACID_SPLASH, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_ACID_SPLASH, oPC, METAMAGIC_ANY, TRUE);
ActionAttack(oPC);
}
}
}
now, i used to also have ( after casting haste ) ghostly visage and mage armor, but when i had that, then all this guy did was cast; invisibility, haste, ghostly visage - and sometimes mage armor - and then just repeat that over and over and over again
so now when i got rid of ghostly visage and mage armor, this guy will cast invisibility, haste - and sometimes cast slow on the PC - and then just cast invisibility and haste over and over and over again
now this is incredibly dumb because here is my kobold arcane caster that has no problems;
void main()
{
object oPC = GetLastPerceived();
if(!(GetPlotFlag(OBJECT_SELF)))
{
if(GetIsPC(oPC))
{
ActionCastSpellAtObject(SPELL_INVISIBILITY, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MAGE_ARMOR, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BLINDNESS_AND_DEAFNESS, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MELFS_ACID_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MELFS_ACID_ARROW, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_RAY_OF_ENFEEBLEMENT, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_COLOR_SPRAY, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MAGIC_MISSILE, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_MAGIC_MISSILE, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_RAY_OF_FROST, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_RAY_OF_FROST, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_RAY_OF_FROST, oPC, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_RAY_OF_FROST, oPC, METAMAGIC_ANY, TRUE);
ActionAttack(oPC);
}
}
}
and yet with this, i never have problems with the kobold caster ever
the ONLY difference between the lizard folk and the kobold in these 2 scripts is that the lizard folk has a different spell list THAT IS IT, and yet the lizard folk REFUSES to act right while the kobold is doing as it should
so what gives?
you need to make a npc-specific AI script which should be explained in the tutorial I linked, and that script looks like this:
(npc specific AI created for cleric npc on my PW Arkhalia)
where do i need to edit the scripts? which ones do i edit? which ones do i need to change? how do i need to change them? and it doesnt tell me at all how to make spell caster scripts ( unless there is a link somewhere? )
i have basically zero knowledge on how C++ works, and what little knowledge i have, couldn't even get me outside a paper bag if i were trapped in one
Maybe this explanation of what the article is saying will get you a step closer.
To set a variable on a creature (or anything else) you go to its Advanced tab and click the variables button to bring up the variables dialog box.
For example, putting the following variable in the creature's variable list:
X2_SPECIAL_COMBAT_AI_SCRIPT | string | ai_liz_wiz
will cause the default NWN AI to execute the code in ai_liz_wiz as part of the AI routines.
So, if you make a script saved as ai_liz_wiz and add what you want it to do, then it should do that. You don't have to put ai_liz_wiz anywhere other than just create it. The by setting X2_SPECIAL_COMBAT_AI_SCRIPT | string | ai_liz_wiz on the creature, it will find ai_liz_wiz at the appropriate time and use it.
Giving a creature this variable
X2_L_BEH_MAGIC | INT | 100
will make it use its magic over other abilities. (the article explains this really well)
but now, i have a new problem;
when my NPC runs out of spells, he will go to attack for half a second and then just go back to spell casting the entire list again
first, i on purposely made sure the NPC had no spells memorized thinking that was the problem, but it is not
so far the script i have, works just as intended now all i need is that when the NPC is done casting the spells in my script i want the NPC to go and attack and use whatever default AI ( because it does have cure minor wounds memorized so if it wants to cast that afterwards i dont care )
so here is my script i have now;
#include "x2_inc_switches"
#include "nw_i0_generic"
void main()
{
object oSelf = OBJECT_SELF;
SetCreatureOverrideAIScriptFinished(OBJECT_SELF);
if(__InCombatRound())
return;
ClearAllActions();
object oEnemy = bkAcquireTarget();
if (GetIsObjectValid(oEnemy))
{
// ** Store HOw Difficult the combat is for this round
int nDiff = GetCombatDifficulty();
SetLocalInt(OBJECT_SELF, "NW_L_COMBATDIFF", nDiff);
__TurnCombatRoundOn(TRUE);
if(TalentPersistentAbilities()) // * Will put up things like Auras quickly
{
__TurnCombatRoundOn(FALSE);
return;
}
else if(TalentHealingSelf())
{
__TurnCombatRoundOn(FALSE);
return;
}
else if(TalentHeal())
{
__TurnCombatRoundOn(FALSE);
return;
}
ActionCastSpellAtObject(SPELL_SANCTUARY, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_SHIELD_OF_FAITH, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BLESS, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_SUMMON_CREATURE_II, OBJECT_SELF, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_SOUND_BURST, oEnemy, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_HOLD_PERSON, oEnemy, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_HOLD_PERSON, oEnemy, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_DOOM, oEnemy, METAMAGIC_ANY, TRUE);
ActionCastSpellAtObject(SPELL_BANE, oEnemy, METAMAGIC_ANY, TRUE);
// Attack the PC.
ActionAttack(oEnemy);
}
}
as i said it works perfect except that when it comes time to attack he will just cast those spells in this order again
if one of you chaps can help add to this so when he is done with those spells and then attacks afterwards without casting those spells again that would be great
add this line:
My thinking is that since this variable that you set on the creature:
X2_SPECIAL_COMBAT_AI_SCRIPT | string | ai_liz_wiz (or whatever you named the script)
is what is telling the AI to run this special AI script, by deleting the variable once the script has run once, it won't run it again.
That's probably a comically poor way to do it to someone who understands it better, but it's simple and might work. Good luck
P.S. Post code between [c ode] & [/c ode] for it to look nice on the forum. (Of course, remove the space I put between 'c' and 'o')
no this is wrong
You both need to realize that the creature AI is not a script where you define 10 spells in succession to cast and creature will cast it. That will never work.
Creature AI is called when npc finishes previous cast, when she fails to cast the spell (interrupted), and dozen of other cases.
The AI script I sent shows this. There is not a queve of spells but each time it is called script will perform only one cast.
The problem of OP with his script is that he took mine script, deleted what he should have deleted but then pasted his old code which is not going to work as it is the same as before, just in other "event".
The script needs to be written in a way so it always casts just one spell and when no spell is available, performs ActionAttack.
Specifically, the problem of OP script is that he doesn't check whether the spell is available and casts it "cheated". He needs to assign the creature as many uses of the spels he needs, and then use same logic as me in original AI script I posted - check if spell is available (+addiionally check some conditions if he wants to) and then cast the single spell (not using bCheat=TRUE) and exit the script the same way. Only when there will be no spell uses, ActionAttack is on the menu.
,METAMAGIC_ANY, TRUE at the end of all the spell lines
( although now i actually have to give the spells they are supposed to cast, but that is okay )
and now everything works as it should
baddies cast their spells, and then they attack once their spells are depleted, excellent
thanks for the help guys