Aller au contenu

Photo

Creature AI Question - Have Creature Use Spells Only


  • Veuillez vous connecter pour répondre
34 réponses à ce sujet

#1
Darin

Darin
  • Members
  • 282 messages
 Need to get a creature that will not engage in melee combat... only cast spells (Baelnorn Sending ability).  Basically the creature will cast spells until defeated (or out of spells, i guess).  The creature is supposed to represent the effect of a Sending spell, and hence is no capable of physical attacks...

Assume I have never played with Creature AI (I haven't...and got amazingly far without doing so).  I don't mind letting the AI decide the spells to cast (if I picked them out myself, the challenge will go up a lot...I'm evil to players like that).

#2
kevL

kevL
  • Members
  • 4 070 messages
that's the reason i started poking the AI a couple years ago ...

still haven't found it tho. I stumbled across what looked like it at some point, but then since i was doing something else figured "oh that could be it" and ..


I don't think it's a simple switch somewhere. I just don't want casters running in with a dagger when they have Ice Storm + half a dozen other offensive spells. Ever!

maybe someone has a creative alternative,

like spawn it as incorporeal and ranged

// Ranged attacker will attempt to stay at ranged distance from their target.
// SetCombatCondition(X0_COMBAT_FLAG_RANGED);

flag X2_L_IS_INCORPOREAL = TRUE


( but really i'm more inclined to say it *is* a job for a custom AI script )

#3
ColorsFade

ColorsFade
  • Members
  • 1 270 messages
The way to do it would be the way I've been doing it with my AI library. You want to use a custom AI script and then set the X2_SPECIAL_COMBAT_AI_SCRIPT variable on the NPC so your script runs as part of the creature's normal combat routine.

Inside your custom AI script, you want to cast the spells, On a successful spell casting, you want to set the X2_SPECIAL_COMBAT_AI_SCRIPT_OK variable to TRUE to tell the standard AI script that your custom script was successful, and not to do anything else.

Once your NPC is out of spells, you just want to have your custom script set the X2_SPECIAL_COMBAT_AI_SCRIPT_OK to TRUE every time. This should prevent the AI from attacking physically, though I have no tested it.

I can post a sample script later today.

#4
ColorsFade

ColorsFade
  • Members
  • 1 270 messages
Here is a sample script. Try this in a test area. Create a caster NPC and give them a few memorized instances of Magic Missile. 

On the NPC, set the variable X2_SPECIAL_COMBAT_AI_SCRIPT=name_of_this_script
Make sure the NPC has the default script set. Load yourself up into the zone, get close to the NPC, and watch. They should cast all their magic missiles at you, and then stop.

#include "hench_i0_ai"

void FinishAI(object oTarget = OBJECT_SELF)
{	
  SetLocalInt(oTarget, "X2_SPECIAL_COMBAT_AI_SCRIPT_OK",TRUE);
}

void main()
{	
  object oTarget = GetNearestSeenOrHeardEnemyNotDead();	
  int nSpellId = SPELL_MAGIC_MISSILE;		
  // If we have spells, cast them.	
  if(GetHasSpell(nSpellId))	
  {	
    ClearAllActions(TRUE);	
    ActionCastSpellAtObject(nSpellId, oTarget);	
    FinishAI(OBJECT_SELF);	
    return;	
  }	
	
  // Otherwise, do nothing. 	
  FinishAI(OBJECT_SELF);
}

Modifié par ColorsFade, 31 mars 2013 - 03:38 .


#5
kevL

kevL
  • Members
  • 4 070 messages
here's an interesting alternative, that uses the AI to choose spells


from the default spawnscript ( nw_c2_default9 ) call a custom script via a string variable on the creature

SpawnScript = custom_script

// custom_script
#include "hench_i0_generic"
#include "hench_i0_assoc"

void main()
{
  SetHenchAssociateState(HENCH_ASC_NO_MELEE_ATTACKS, TRUE, OBJECT_SELF);
}

( so in this sense it is just a simple switch )


Now, this probably isn't *supposed* to work, but it does in tests here. Using TonyK's -- aka the SoZ AI called w/ HenchDetermineCombatRound() -- my ogre magi cast Cone of Cold, Charm Person, and the Heroism from its greatsword. Then it stood there and never made a physical attack!

It did not cast Darkness, Invisibility, Polymorph Self, or Sleep. ( <- just noting that, I don't know what's going into these AI decisions ) vs a 15 dwarfen Cleric



nb. i Find that the toolset is bugged when assigning #Uses of spells or spellabilities. If you set #Uses, save, close, open, and then look at the creature's Properties|Spell/abilities, the #Uses resets to 1. A save then overwrites previous values,


/fwiw

#6
MasterChanger

MasterChanger
  • Members
  • 686 messages
The idea of being able to figure out which feats and spells the creature has and instruct them to use them is linked to stuff that I was thinking about when it came to player characters. It would potentially be much more powerful to ask: "Tell me which spells this caster has" rather than "Does this creature have spell x? Well then, how about spell y?" This would potentially allow a true custom AI.

It's been a longtime ambition of mine to figure out how to write a series of NWNX plugins that allow nwscript access to the full range of creature data, including feats, known and memorized spells, true AB, etc. My thinking is that Pain's Neverlauncher is eventually going to get to the point where it's going to be easy to run NWNX for single player anyway. Unfortunately, I don't have the C++ skills to accomplish this, but it's a direction that I see things progressing in.

#7
kevL

kevL
  • Members
  • 4 070 messages
yes i'm waiting to be able to load NWNx for single player too. But i got lots to do in the meantime ... ;)

I been poking that ai, MC, and have seen areas with what you've noticed: if(hasSpell_a) +1, if(hasSpell_B) +1, etc. First of all they probably aren't complete; 2nd, who really knows what henchspells.2da does with them.

ironically, as a means to counter the toolset bug i mentioned, I began to devise a 'spells_that_should_be_available.2da', which strikes me as a way to start giving an ai "here are the spells, now use them" instructions (tbh it more than 'struck me' -- put ~100 hr into developing it). But this runs into huge problems once one realizes that without extensive Caster data collection & spellscript rewrites, the spells'd have to bCheat at level 10.

/which just takes the wind right out of that method afaiac. Back to spell fixes & streamlining fer me, i guess

#8
MasterChanger

MasterChanger
  • Members
  • 686 messages

kevL wrote...

ironically, as a means to counter the toolset bug i mentioned, I began to devise a 'spells_that_should_be_available.2da', which strikes me as a way to start giving an ai "here are the spells, now use them" instructions (tbh it more than 'struck me' -- put ~100 hr into developing it). But this runs into huge problems once one realizes that without extensive Caster data collection & spellscript rewrites, the spells'd have to bCheat at level 10.


Yeah, that's it exactly. My thought was that if it becomes possible to see which spells a creature has memorized and/or ready to cast, you could conceivably set a spell as memorized and ready to cast. So if you (you here being an AI writer) determine that a spell should be cast under a certain condition, you declare "Make it so!", and so it is.

#9
Darin

Darin
  • Members
  • 282 messages

kevL wrote...

here's an interesting alternative, that uses the AI to choose spells


from the default spawnscript ( nw_c2_default9 ) call a custom script via a string variable on the creature

SpawnScript = custom_script

// custom_script
#include "hench_i0_generic"
#include "hench_i0_assoc"

void main()
{
  SetHenchAssociateState(HENCH_ASC_NO_MELEE_ATTACKS, TRUE, OBJECT_SELF);
}

( so in this sense it is just a simple switch )


That seems like the way to go for me; ColorFades idea would be great to script the spells, but this idea is better for a single script opn three different liches... which is what I'm looking for.

Now, this probably isn't *supposed* to work, but it does in tests here. Using TonyK's -- aka the SoZ AI called w/ HenchDetermineCombatRound() -- my ogre magi cast Cone of Cold, Charm Person, and the Heroism from its greatsword. Then it stood there and never made a physical attack!

It did not cast Darkness, Invisibility, Polymorph Self, or Sleep. ( <- just noting that, I don't know what's going into these AI decisions ) vs a 15 dwarfen Cleric 



That's actually promising to me...Sleep is only useable if target has 4 or less Hit Dice (so don't bother vs 15), Polymorph Self is blatantly a combat-buff, and I can see why the programmers would have made invis and darkness combat buffs as well...and since he won't enter melee, he won't cast them.




Thank you to everyone for the advice, I'll have to try this out and see what happens...

#10
ColorsFade

ColorsFade
  • Members
  • 1 270 messages

MasterChanger wrote...

Yeah, that's it exactly. My thought was that if it becomes possible to see which spells a creature has memorized and/or ready to cast, you could conceivably set a spell as memorized and ready to cast. 


You can find out if a creature has any spell memorized with a call to GetHasSpell(). That's really all you need, in combination with the remaining functions that already exist. 

If you wanted to write a general-purpose AI script for a given class, say a Cleric, and account for every possible spell that they could have memorized, you could do it. The functions are there. All it would take is time to write the script to account for all the possible spells, to check each spell to see if the PC has it memorized. If they do have a spell memorized - you can determine what to do from that point. 

Casting a spell "under certain conditions", regardless of memorization, is already possible with bCheat=TRUE. No need to have the creature memorize it. Just have them cast it. That's what the method is there for. 

MasterChanger wrote...
So if you (you here being an AI writer) determine that a spell should be cast under a certain condition, you declare "Make it so!", and so it is.


And you can do that with bCheat. 

Managing spell AI is actually the easiest part of working with the AI in NWN2, as I recenty found out in building my AI library. What's much harder is tracking damge/hate/aggro and targeting enemies based on specific criteria (like class-type, or who just hurt me the most, or where is the cleric that just healed the fighter that I was about to kill?) because the game engine lacks specific functions to do that stort of stuff easily, so you have to write it yourself. 

But when it comes to spells - the functions are there. 

#11
Darin

Darin
  • Members
  • 282 messages
Wow, worked really well....only a few spells cast, but no closing for melee, so.

#12
kevL

kevL
  • Members
  • 4 070 messages
:P

if you notice some spells not getting cast that you really want, tie in the X2_Special_Combat script that CF outlined, and call them there under whatever conditions you like.

- when such spells cast, set the ai OFF w/ FinishAI(), but leave it ON otherwise


eg. Greater Stoneskin instant
Displacement @ half-health
if (distance > 20 && #enemies_in_sphere > 2) do Fireball
if (Target_is_caster) do Feeblemind,

etc.

#13
luna_hawke

luna_hawke
  • Members
  • 88 messages
You can try this.  I'm not 100% sure it will work.
But it might let you skip a custom AI.

Tweak the STR down as low as you can so the BA is bad / low.
Put a weapon or token on the creature as well that has a BA penalty.

Set these two variables on the creature as Integeres.
X2_L_BEH_OFFENSE = 100
X2_L_BEH_MAGIC = 100


The comment on X2_L_BEH_MAGIC says it will always use magic if set to 100.
I have not confirmed that.


"The value of this variable (int) is added to the chan
ce that a creature will use magic in combat. Set to 100 for
always, 0 for never
X2_L_BEH_MAGIC "


This setup should take you just a few minutes to try out.   ;)

#14
kevL

kevL
  • Members
  • 4 070 messages

luna_hawke wrote...

The comment on X2_L_BEH_MAGIC says it will always use magic if set to 100.
I have not confirmed that.

i have a /rather strong/ suspicion those variables are limited to use by the pre-MotB ai, eg. DetermineCombatRound() ... ( not HenchDetermineCombatRound() etc )

#15
kevL

kevL
  • Members
  • 4 070 messages
btw CF,

when a spell is bCheat, the engine uses a default level of 10 ( and probably doesn't correctly store other info on an effect or AoE, like the Creator, trueSaveDC, etc. )

unfortunately there is no known 'incrementRemainingSpellUses' function, either. The hardcoded console command 'givespell' brings a spell up ready-to-use, but SetSpellKnown() doesn't ( and has other issues like the creature needs a caster_class )


So yeah, either fake it, bCheat, or rewrite spellscripts ...

#16
ColorsFade

ColorsFade
  • Members
  • 1 270 messages

kevL wrote...

btw CF,

when a spell is bCheat, the engine uses a default level of 10 ( and probably doesn't correctly store other info on an effect or AoE, like the Creator, trueSaveDC, etc. )

unfortunately there is no known 'incrementRemainingSpellUses' function, either. The hardcoded console command 'givespell' brings a spell up ready-to-use, but SetSpellKnown() doesn't ( and has other issues like the creature needs a caster_class )


So yeah, either fake it, bCheat, or rewrite spellscripts ...


That's good to know, that it's default level 10. 

With that knowledge, I can say what I would do (and will do in my campaign if the situation arises) and that is this: I will hard-code the spell into the creature then, when I paint it down. 

I prefer painting down all my encounters. There have been a couple small, really generic encounters where I've used the spawn system, but otherwise, I paint every creature and set them up by hand. I use a default blueprint, adjust the stats/spells/skills/etc, then save as a blueprint and paint. 

This makes working with my AI library really easy too. And it has the added benefit that when I open an area, I can easily see everything that is going on... 

Anyway, my 2 cents :)

#17
kevL

kevL
  • Members
  • 4 070 messages
painting down creatures chews up overhead on the CPU

i mean, just so you know, before anyone gets carried away and puts down 50 of them ....


:)_~

#18
ColorsFade

ColorsFade
  • Members
  • 1 270 messages

kevL wrote...

painting down creatures chews up overhead on the CPU

i mean, just so you know, before anyone gets carried away and puts down 50 of them ....


:)_~



Seriously? 

Sigh... Well, we'll I guess I'll have to change my ways. 

#19
Dann-J

Dann-J
  • Members
  • 3 161 messages
I prefer to spawn groups of hostiles via encounters where possible, since it means there aren't a bunch of placed creatures standing around doing nothing and using up processing power (even if they're in another area, and only running HB scripts once per minute instead of once per second).

I often tie encounter spawns to opening doors, and cache the creature types in the area to minimise any pause when they appear. If you cross an encounter trigger on the ground then you almost always notice the tell-tale delay, but if you're standing still opening a door then you notice it far less. Plus, ground triggers can be unreliable, whereas you can't get through a closed door without opening it first. It *does* prevent tracking from locating creatures in other rooms though - not that tracking should be of much use indoors anyway.

It's easy enough to force a specific group to spawn by not giving the encounter settings any wiggle room. Although personally, I *like* a bit of wiggle room in my encounters, so that ever I (as the module author) won't know exactly what I'll get every time. I might specify a boss and a couple of upper-level lackies to always appear consistently, but the number and composition of the lower-level underlings can vary without much consequence.

#20
ColorsFade

ColorsFade
  • Members
  • 1 270 messages

DannJ wrote...

I often tie encounter spawns to opening doors, and cache the creature types in the area to minimise any pause when they appear.


Dan, 

How do you cache creature types?

Caching is always good... 

#21
Dann-J

Dann-J
  • Members
  • 3 161 messages
You can cache creature blueprints in the area's property settings. Doing so reduces the pause that spawning an encounter causes to a degree, but you never quite get rid of it entirely.

Modifié par DannJ, 03 avril 2013 - 04:08 .


#22
ColorsFade

ColorsFade
  • Members
  • 1 270 messages

DannJ wrote...

You can cache creature blueprints in the area's property settings. Doing so reduces the pause that spawing an encounter causes to a degree, but you never quite get rid of it entirely.


Thanks. That's good to know. 

There are ways to trigger encounters so the PC doesn't "see" the creatures emerge from nothing, and to me that's probably the most important thing. I still might paint a few in outdoor areas for tracking scenarios... We'll see. 

Thanks for the tips folks. 

#23
-Semper-

-Semper-
  • Members
  • 2 259 messages

kevL wrote...

painting down creatures chews up overhead on the CPU


if you paint those creatures down and set them to script hidden with ai off while hidden this shouldn't take effect, right?

#24
kevL

kevL
  • Members
  • 4 070 messages
good point Semp.

that'd make them pretty much like environmental objects (or less, in terms of system stress), i figur


[edit] ... wait a sec, I seem to remember that scriptHidden creatures *do* some events; but an important thing is they shouldn't be doing any collision detection. Testing ...

[edit2] ok, it's good.

with Disable AI while hidden ON - nada, not a peep.
w/ FALSE - HB runs. (not sure on others like Perception, prolly not)


I think this might actually be why ScriptHidden was added to NwN2 -- as a means for major 'scripted fights' to get around the spawnLag that Dann mentioned. Do it on ClientEnter* and the player never notices


*[edit3] personally i like to keep critters off the table until needed. There are plenty of counter-instances ...

Modifié par kevL, 03 avril 2013 - 12:56 .


#25
kevL

kevL
  • Members
  • 4 070 messages
&ps. Another reason to like spawned creatures is that it's easier to modify them later. Like, in the middle of a saved game .... An instanced creature is stored right in the saved module; a blueprint, however, is subject to Override ( and Campaign folder, etc. )