Author Topic: Only Percieve Player if Seen/ Deaf NPCs  (Read 310 times)

Legacy_Sturmdolch

  • Newbie
  • *
  • Posts: 10
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« on: February 15, 2011, 01:54:44 am »


               I'm having a big problem with my module. I want my NPCs to patrol hallways, and when the player walks into their line of sight, they make the player teleport back to the start. For now, I'm just having them say a line of text for testing purposes.

This is my script, which I attach to the "OnPercieve" slot of the NPC.


#include "nw_i0_generic"

void main()
{
// * if not runnning normal or better Ai then exit for performance reasons
    // * if not runnning normal or better Ai then exit for performance reasons
    if (GetAILevel() == AI_LEVEL_VERY_LOW) return;

    object oPercep = GetLastPerceived();
    int bSeen = GetLastPerceptionSeen();
    int bHeard = GetLastPerceptionHeard();


    if (bSeen)
      {
        //MyPrintString("GetLastPerceptionSeen: TRUE");
        if (GetIsPC(oPercep))
        {

            SpeakString("I C WUT U DID THERE");

        }
    }
    // activate ambient animations or walk waypoints if appropriate
    if (!IsInConversation(OBJECT_SELF)) {
       if (GetIsPostOrWalking()) {
           WalkWayPoints();
       } else if (GetIsPC(oPercep) &&
           (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
            || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)
            || GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS)
            || GetIsEncounterCreature()))
       {
            SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE);
       }
    }
}

The NPCs will whip around if I am too close behind them. I think this is coming from the whole "hearing" thing. Is there a way to make deaf NPCs? I only want them to see the player if the player is running in front of them.

As an alternate way of doing this, would it somehow be possible to use angles, such as with "GetAngleBetweenLocations(location 1, location 2)" to determine if the player is in a certain line of sight..?

Thanks.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #1 on: February 15, 2011, 02:05:54 am »


               The Angle question has recently been answered. 

Function Request

I am not sure about your NPC turning around it is most likely in the OnHeartBeat event. 

You may want to do all of this in the OnHeart Beat event any way.  The on perception event has one major limitation for what you are trying to do.  That is that it only fires when something changes according to it. 

Meaning the PC walks up behind the NPC.  The Event fires for perception precived because the PC came within viewing range.  The event will not fire again untill something changes.   Meaning the PC could then run circles aroung the NPC and the event would never fire again untill he left the perception range or tried to hide.  Drank a potion of invis or ran away.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #2 on: February 15, 2011, 03:47:36 am »


               If you decide to go with the heartbeat, and i recommend you do as well, you could use the function that Lightfoot made like this:


//npc heartbeat

int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc);
int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc)
{
location lSelf = GetLocation(oSelf);
location lTarget = GetLocation(oTarget);

float AngleOffset = VectorToAngle( GetPosition(oTarget) - GetPosition(oSelf)) - GetFacing(oSelf) ;

return (abs(FloatToInt(AngleOffset)) <  nViewArc/2);
}
void main()
{
object oSelf = OBJECT_SELF;
object oTarget = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsFacingTarget(oSelf, oTarget, 120))
    {
    AssignCommand(oTarget, ActionJumpToObject(GetWaypointByTag("tag of wp")));
    }
ExecuteScript("nw_c2_default1", OBJECT_SELF);
}


This is a pretty nifty function. And if you like you can change the view arc from 120 degrees to whatever you think is best for your NPCs.

Hope it helps. Good luck.

               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #3 on: February 15, 2011, 11:01:01 am »


               As Lightfoot touched on the topic- OnPerceive is somewhat tricky and poorly named.



The Name of the event suggests that it fires when the NPC Perceives the player, but it actually fires when they come into a sphere of influence, even if they are inside another room, or blocked line of sight, or stealthed / invisible, the event will fire, the code within the event will then determine whether or not the npc should acknowledge the players/creatures presence.



If you were to use this event, it would only fire again, if the player left the sphere of influence/range of the npc, and then re-entered the range, sometimes leaving the area might be required, depending on how big the area is.



Note - remember that Heartbeats only fire once every 6 seconds (ideally).

If you want smoother detection, you would need to set up a pseudo-hb  with a shorter interval, but remember - the shorter the interval, and the more complicated the code, the more of a hit to performance your server/game will take.



Note-  By Smoother detection, I mean 'More accurate'.



Eg - If you put the above scripts in the onHeartbeat of the npc, your player will either

1. Have to be very unlucky, and just be in the line of sight at the instant that the 6 second hb fires. Means there is 5 seconds of grace time that your player could run around circles of the npc, and do anything he wants.

2. Lower the interval via pseudo-hb   - Make the script fire once every second, making it more likely to pick up on the player being infront of the npc.





Note- Just a personal suggestion -

GetNearestCreature does do what you need it to do, but it loops through all Creatures in the area, filtering out only the ones that meet the criteria, but the fact that it still loops through all the creatures, just looking for ones of that type, means it could potentially be a performance hit if there are 30 npc's there. eg - Loops through 30 npcs, and then returns OBJECT_INVALID anyway.



If you are wanting to locate Player characters, or work with them, then GetFirstPC and GetNextPC, and then filtering via GetArea etc, might be more efficient.



eg - Some servers/games might be more likely to have less players, than npc's in the area.

eg - 6 Players in the whole server, means looping through 6 players to find the one that is in the current area and in line of sight.

opposed to

Looping through 30 creatures in the current area, to determine if they are a player, and then check if they are in line of sight.
               
               

               
            

Legacy_Sturmdolch

  • Newbie
  • *
  • Posts: 10
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #4 on: February 24, 2011, 03:48:48 pm »


               Hi, sorry for the late reply but thanks a ton to all of you for the tips. It's really helping. GhostofGod's function from Lightfoot is working pretty good for stationary NPCs.

I altered it a bit to make it like this:

int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc);int GetIsFacingTarget(object oSelf, object oTarget, int nViewArc){location lSelf = GetLocation(oSelf);location lTarget = GetLocation(oTarget);
float AngleOffset = VectorToAngle( GetPosition(oTarget) - GetPosition(oSelf)) - GetFacing(oSelf) ;
return (abs(FloatToInt(AngleOffset)) <  nViewArc/2);}
void PseudoHeartBeat(){    object oSelf = OBJECT_SELF;    object oTarget = GetFirstPC();
    int inView = 0;
    if (GetIsFacingTarget(oSelf, oTarget, 120))    {        inView = 1;
        if(inView == 1)        {           AssignCommand(oSelf, SpeakString("5"));
            //ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oTarget, 0.5);

            AssignCommand(oTarget,ClearAllActions());
            AssignCommand(oSelf,ClearAllActions());
            AssignCommand(oTarget, ActionJumpToObject(GetWaypointByTag("home")));   
        }    }
    if(TRUE)    {    
DelayCommand(0.5, PseudoHeartBeat());    }}

Now, the only problem I seem to have is when I make the NPC patrol. The character seen will become stuck at the start and be unable to move forward, as if the "ActionJumpToObject" function keeps getting called. I think it only happens if the character is in the radius of view, which means the enemy can see through walls.

Is there something I can do here? I tried it with LineOfSight but that didn't work out.
               
               

               


                     Modifié par Sturmdolch, 24 février 2011 - 03:49 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #5 on: February 25, 2011, 12:00:29 am »


               instead of

inView = 1;

try :

inView = LineOfSightObject(oSelf, oTarget);

An let me know how that works.  

But keep in mind that line of sight is an expensive function to be running every half second. 
               
               

               
            

Legacy_Sturmdolch

  • Newbie
  • *
  • Posts: 10
  • Karma: +0/-0
Only Percieve Player if Seen/ Deaf NPCs
« Reply #6 on: March 01, 2011, 03:01:06 pm »


               Alright, so apparently my group actually just wants to do a radius around the guard for detection, which makes my life a lot easier. I got that one.

Thanks a ton for the help, though!