NPC blocked but not by door
#1
Posté 06 juillet 2011 - 02:45
How do you detect this situation in a script? OnBlocked only appears to work for a door or creature that is blocking a path of travel. Would the event also capture this situation? Or do I need to try different events? I'm hoping to avoid a heartbeat, but suspect it is the only way to approach this problem.
To clarify, I am looking for a situation in which an NPC is attempting to move to a location/object, has line of site on its destination, but is unable to path find their way to it.
#2
Posté 06 juillet 2011 - 06:08
object oNearestSeenEnemy = GetNearestSeenEnemy();
if (GetIsInCombat()
&& GetIsObjectValid(oNearestSeenEnemy)
&& !GetIsObjectValid(GetAttemptedAttackTarget())
&& !GetIsObjectValid(GetAttemptedSpellTarget())
&& !GetHasEffect(EFFECT_TYPE_SLEEP)
&& !GetHasEffect(EFFECT_TYPE_PARALYZE)
&& !GetHasEffect(EFFECT_TYPE_PETRIFY)
&& !GetHasEffect(EFFECT_TYPE_STUNNED)
&& !GetHasEffect(EFFECT_TYPE_TURNED)
&& !GetHasEffect(EFFECT_TYPE_TIMESTOP)
&& !GetHasEffect(EFFECT_TYPE_MOVEMENT_SPEED_DECREASE)
&& !GetHasEffect(EFFECT_TYPE_FRIGHTENED)
&& !GetHasEffect(EFFECT_TYPE_DAZED)
)
{
location lLastLocation = GetLocalLocation(OBJECT_SELF, "LOCATION");
location lLocation = GetLocation(OBJECT_SELF);
SetLocalLocation(OBJECT_SELF, "LOCATION", lLocation);
float fDelta = GetDistanceBetweenLocations(lLastLocation, lLocation);
if (fDelta < 0.5)
{
int iStuckCount = GetLocalInt(OBJECT_SELF, "STUCK_HB_COUNT");
SetLocalInt(OBJECT_SELF, "STUCK_HB_COUNT", ++iStuckCount);
if(iStuckCount>1)
{
SpeakString("I am unable to attack "+GetName(oNearestSeenEnemy)+" because I am stuck.");
SpeakString("Leap or fly.");
DeleteLocalInt(OBJECT_SELF, "STUCK_HB_COUNT");
}
}
else
{
DeleteLocalInt(OBJECT_SELF, "STUCK_HB_COUNT");
}
}
Modifié par henesua, 06 juillet 2011 - 06:14 .
#3
Posté 06 juillet 2011 - 03:01
Consider adding the following to the check in the script:
EFFECT_TYPE_CUTSCENEIMMOBILIZE
EFFECT_TYPE_CUTSCENE_PARALYZE
EFFECT_TYPE_DOMINATED
EFFECT_TYPE_ENTANGLED
Having timestop checked is pointless as if you have the timestop effect, you are the one who is not stopped. Movement speed decrease check can lead to errors, if you are slowed down so much the script thinks you are stuck when you are not. (Althougth a distance of 0.5 is very short)
I think on some occasions creatures have also got stuck in a way that makes them walk back and forth over some distance.
Clever script though, I might use a modified version of this for something all different...
Modifié par Xardex, 06 juillet 2011 - 03:10 .
#4
Posté 06 juillet 2011 - 04:27
Xardex wrote...
You could use smaller creatures in smaller areas. You could also consider making them ranged.
All true, BUT there are other applications to this. Example, I have giant spiders in Diademus's spider caves. They are having trouble with the wok meshes which is jarring for the player given they should be on there home turf there, and more mobile than the player. Also, Flying creatures blocked by water or chasms is something I've considered solving for a long time now. This script solves that problem too.
Xardex wrote...
Consider adding the following to the check in the script:
EFFECT_TYPE_CUTSCENEIMMOBILIZE
EFFECT_TYPE_CUTSCENE_PARALYZE
EFFECT_TYPE_DOMINATED
EFFECT_TYPE_ENTANGLED
thanks for those recommendations. I'm also going to remove TURNED and FRIGHTENED. Those should be used to differentiate between a fight or flight response.
Xardex wrote...
Having timestop checked is pointless as if you have the timestop effect, you are the one who is not stopped.
I wondered about that. Thanks. I'll remove it.
Xardex wrote...
Movement speed decrease check can lead to errors, if you are slowed down so much the script thinks you are stuck when you are not. (Althougth a distance of 0.5 is very short)
I think I skip those NPCs with reduced movement, right? Therefore avoiding the problem you are talking about? I'm not sure I follow you here.
Thats a potential problem. I'll look into it.Xardex wrote...
I think on some occasions creatures have also got stuck in a way that makes them walk back and forth over some distance.
By the way, I've further refined the above, and will also incorporate your comments. When its finished, I'll post to the vault. This behavior is working well as a self contained USERDEF event script.
#5
Posté 06 juillet 2011 - 06:22
(Though now that I think about it... If you don't skip, it might think its sometimes stuck when its not)
Modifié par Xardex, 06 juillet 2011 - 06:24 .
#6
Posté 06 juillet 2011 - 06:30
#7
Posté 06 juillet 2011 - 09:01
Once you have tied it into the AI the check for the creature being in combat becomes pointlees for because the script will only fire if the creature is in combat. most of the checks you have in your list can be decteded by checking to see if the creature is commandable or not.
// Determine whether oTarget's action stack can be modified.
int GetCommandable(object oTarget=OBJECT_SELF)
The one I can think of that that my not catch is sleep. but I think it is taken care of before the spicial AI script is fired.
Here is the outline of how I see it being done.
Set the special AI string on the creature either in the OnAreaEnter event ot the OnSpawn Event for the creatue. I myself like the Idea of useing the area enter event. This will allow you to define different responces to diffreant areas. and allow you to apply it to only the ones you want without having to change the standard scripts. the string var that would need to be set on the creature is "X2_SPECIAL_COMBAT_AI_SCRIPT". So something like the following added to the Area Enter script.
...
object oEnter = GetEnteringObject();
if (GetCreatureSize(oEnter)>)CREATURE_SIZE_MEDIUM)
SetLocalString(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT","Name of script to run");
...
The Script will ran anytime DetermineCombatRound is called for that creature. There are just a couple of extra things to know when writting the script. If you set the localstring "X2_SPECIAL_COMBAT_AI_SCRIPT_OK" on the creature to true in the script, it will abort the normal AI from running. If you do not set the string the Normal AI will still run after this script is finished. If you want to get the target that the creature is currently targeting you can get the local object "X2_NW_I0_GENERIC_INTRUDER" from the creature. ie.
object oCurrTarget =GetLocalObject(OBJECT_SELF,"X2_NW_I0_GENERIC_INTRUDER");
Hope that helps.
L8
#8
Posté 06 juillet 2011 - 09:30
I assume that this event only occurs once, that being at the start of combat. Is that true?
It seems to me that a pair of scripts would be better than just one - one at the start of combat, and one following up at the end of every combat round. I think all of this could be set up with one special combat ai script and the USERDEF which would handle initialization and the other events.
For example I am assuming that the post spawn event can be used to determine what area the creature has been spawned in rather than use an onarea enter script.
#9
Posté 06 juillet 2011 - 09:59
henesua wrote...
Lightfoot, thanks. I had no idea that you could have a special script that would run first when "DetermineCombatRound" is called. That sounds much better than using a HB.
I assume that this event only occurs once, that being at the start of combat. Is that true?
No, It will happen every combat round. It is in fact written into the "DetermineCombatRound" function. If you look into nw_io.generic you can see where it is at in the combat round. Here is the code fragment that hooks the special AI.
// ----------------------------------------------------------------------------------------
// July 27/2003 - Georg Zoeller,
// Added to allow a replacement for determine combat round
// If a creature has a local string variable named X2_SPECIAL_COMBAT_AI_SCRIPT
// set, the script name specified in the variable gets run instead
// see x2_ai_behold for details:
// ----------------------------------------------------------------------------------------
string sSpecialAI = GetLocalString(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT");
if (sSpecialAI != "")
{
SetLocalObject(OBJECT_SELF,"X2_NW_I0_GENERIC_INTRUDER", oIntruder);
ExecuteScript(sSpecialAI, OBJECT_SELF);
if (GetLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK"))
{
DeleteLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK");
return;
}
}
So basicly if the special AI string exsists it runs the script by the same name. But before running the script is sets the local object for who the current target is, so that you can retrive it from the special IA script.
After the special AI script is ran it chects to see if the X2_SPECIAL_COMBAT_AI_SCRIPT_OK" local string has been set. If it has it deletes it so that it has to be set againg next round and returns so that the rest of the AI does not run. If it was not set after the special AI script was ran it just continues to run the standard AI.
The OnCombatRoundEnd Event calls DeterminCombatRound if they are still in combat, so it is already taken care of.It seems to me that a pair of scripts would be better than just one - one at the start of combat, and one following up at the end of every combat round....
....I think all of this could be set up with one special combat ai script and the USERDEF which would handle initialization and the other events.
For example I am assuming that the post spawn event can be used to determine what area the creature has been spawned in rather than use an onarea enter script.
Yes there a may way to set it up. It just come down to how you want to handle it. Just keep in mind that the OnSpawn event will only set things up one time And you will need to have the onspawn event modified to check all creatures vs the area they are spawning into. With the OnAreaEnter event they would fire it when they spawned into the area, That would handle it pretty much the same as the onspawn. However if that creature ever moved to a new area you could change the Special AI event on them entering. Of cource that is not to say that you could not just write your Special AI to check the area they are in first and act accordingly. It is really just a matter of how you decide to do it and what fits the best with what you already have in place.
#10
Posté 06 juillet 2011 - 10:08
Thanks, I can see this being useful not only in this instance, but many many others.
#11
Posté 11 juillet 2011 - 04:25
http://nwvault.ign.c....Detail&id=3819
#12
Posté 24 septembre 2011 - 01:30
henesua wrote...
I made this work with the Special Combat AI Script, and posted it on the vault. So far it only works for jumping creatures, but I am also working on fliers and teleporters (blink dogs, spellcasters etc...)
http://nwvault.ign.c....Detail&id=3819
Will this work in NWN2 - I mean things can be similar sometimes in the nwscripting way.





Retour en haut







