Author Topic: NPC blocked but not by door  (Read 449 times)

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« on: July 06, 2011, 03:45:27 am »


               I have a tileset with a difficult WOK mesh. Largish monsters get caught in places that a player or small monster can negotiate. Often the monster has line of site, but is unable to negotiate the WOK mesh to pursue the PC.

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.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #1 on: July 06, 2011, 07:08:57 am »


                I decided to try this in a creature's heartbeat script and it appears to be doing a good job of determining if a creature wants to attack an enemy but is unable because it is stuck. When it determines that it is stuck, it will do something to alleviate the situation. That part is unwritten, but much easier to solve. I would be happy to hear criticism of the code.


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 .
                     
                  


            

Legacy_Xardex

  • Sr. Member
  • ****
  • Posts: 414
  • Karma: +0/-0
NPC blocked but not by door
« Reply #2 on: July 06, 2011, 04:01:17 pm »


               You could use smaller creatures in smaller areas. You could also consider making them ranged.

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 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #3 on: July 06, 2011, 05:27:58 pm »


               

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.

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.

Thats a potential problem. I'll look into it.

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.
               
               

               
            

Legacy_Xardex

  • Sr. Member
  • ****
  • Posts: 414
  • Karma: +0/-0
NPC blocked but not by door
« Reply #4 on: July 06, 2011, 07:22:53 pm »


               I miswrote. I ment that the movement speed related error can occur if an NPC that does have movement penalty gets stuck, the script skips him.

(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 .
                     
                  


            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #5 on: July 06, 2011, 07:30:20 pm »


               Yeah. So the thought is that if the creature is slowed it can not fly or jup effectively.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC blocked but not by door
« Reply #6 on: July 06, 2011, 10:01:51 pm »


               I also do not think you need to do this an a HB it would be better to tie it into the AI. 

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
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #7 on: July 06, 2011, 10:30:32 pm »


               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?

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.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
NPC blocked but not by door
« Reply #8 on: July 06, 2011, 10:59:12 pm »


               

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. 



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....

The OnCombatRoundEnd Event calls DeterminCombatRound if they are still in combat, so it is already taken care of.

 

....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.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #9 on: July 06, 2011, 11:08:06 pm »


               I see. So the advantage of this over on combat round end is that the special ai script happens first, and you can toggle it on and off with a variable.

Thanks, I can see this being useful not only in this instance, but many many others.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
NPC blocked but not by door
« Reply #10 on: July 11, 2011, 05:25:14 am »


                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
               
               

               
            

Legacy_Morbane

  • Jr. Member
  • **
  • Posts: 79
  • Karma: +0/-0
NPC blocked but not by door
« Reply #11 on: September 24, 2011, 02:30:40 am »


               

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.