Author Topic: Understanding the listen skill  (Read 464 times)

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« on: January 13, 2012, 08:10:50 pm »


               Hi,

I see in the default OnPerception script that the creatures hearing an invisible enemy up to 7 meters will try to use some abilities/spells in order to "beat" the invisibility. Testing with a PC fighter wearing full plate + tower shield, I drink the invisibility potion and enter the area... None of the creatures hear me, except if I bump them while running through the area, even with their listen skill up to 75. The creatures have keen sense, invisibility purge and the function ActionCastSpell() is updated to allow non-casters to use the latter in the script.

In that same script, there is a warning not to rely on the listen skill for enemy detection. I wonder why...

Thanks for any insight


Kato
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Understanding the listen skill
« Reply #1 on: January 13, 2012, 09:21:26 pm »


               It seems there is very short range that cannot be extended via perception range in creature properties for listen similar to perception range. Keen senses seem to have no effect on this.

This range for to be heard is very short (5.0 max) and it does trigger OnPerception script only once similary to be seen until you left and reenter this range.

You should probably code this behavior in OnHeartbeat...
               
               

               


                     Modifié par ShaDoOoW, 13 janvier 2012 - 09:22 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« Reply #2 on: January 13, 2012, 09:25:45 pm »


               That's what I feared. Thanks for the infos, ShadoOoW '<img'>


Kato
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Understanding the listen skill
« Reply #3 on: January 13, 2012, 09:36:34 pm »


               Im however interested on this subject as well (smells a bug) so I try to make the adjustion in heartbeat to increase the range, I post it here soon
               
               

               
            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« Reply #4 on: January 13, 2012, 09:43:57 pm »


               As an additional info, I've tested the area's listen modifier with a few values, and upon giving a negative one(-10), poof! I'm instantly heard by the creatures. I'm not sure this is a clean approach though...


Kato
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Understanding the listen skill
« Reply #5 on: January 13, 2012, 10:17:56 pm »


               

Kato_Yang wrote...

As an additional info, I've tested the area's listen modifier with a few values, and upon giving a negative one(-10), poof! I'm instantly heard by the creatures. I'm not sure this is a clean approach though...


Kato

hmm strange, I had negative results with this, nothing had changed

Try this script, I guess the listen DC and maybe also listen rank still needs to be corrected but its a start:

EDIT: both scripts improved

heartbeat

//:://////////////////////////////////////////////////
//:: NW_C2_DEFAULT1
/*
  Default OnHeartbeat script for NPCs.

  This script causes NPCs to perform default animations
  while not otherwise engaged.

  This script duplicates the behavior of the default
  script and just cleans up the code and removes
  redundant conditional checks.

 */
//:://////////////////////////////////////////////////
//:: Copyright © 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 12/22/2002
//:://////////////////////////////////////////////////

#include "nw_i0_generic"

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

    if(GetCommandable() && GetCurrentAction() == ACTION_INVALID && !GetIsInCombat() && !GetHasEffect(EFFECT_TYPE_DEAF) && !GetHasEffect(EFFECT_TYPE_SILENCE))
    {
    location l = GetLocation(OBJECT_SELF);
    object oHeard = GetFirstObjectInShape(SHAPE_SPHERE,RADIUS_SIZE_COLOSSAL,l,TRUE);
     while(GetIsObjectValid(oHeard))
     {
      if(GetIsReactionTypeHostile(oHeard) && !GetHasEffect(EFFECT_TYPE_SILENCE,oHeard) && !GetHasEffect(EFFECT_TYPE_ETHEREAL,oHeard) && !GetHasEffect(EFFECT_TYPE_SANCTUARY,oHeard))
      {
       if(GetIsSkillSuccessful(OBJECT_SELF,SKILL_LISTEN,GetSkillRank(SKILL_MOVE_SILENTLY,oHeard)+d20()))
       {
       SetLocalObject(OBJECT_SELF,"HEARD_INTRUDER",oHeard);
       ExecuteScript("nw_c2_default2",OBJECT_SELF);
       DeleteLocalObject(OBJECT_SELF,"HEARD_INTRUDER");
       break;
       }
      }
     oHeard = GetNextObjectInShape(SHAPE_SPHERE,RADIUS_SIZE_COLOSSAL,l,TRUE);
     }
    }

    // Buff ourselves up right away if we should
    if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))
    {
        // This will return TRUE if an enemy was within 40.0 m
        // and we buffed ourselves up instantly to respond --
        // simulates a spellcaster with protections enabled
        // already.
        if(TalentAdvancedBuff(40.0))
        {
            // This is a one-shot deal
            SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);

            // This return means we skip sending the user-defined
            // heartbeat signal in this one case.
            return;
        }
    }


    if(GetHasEffect(EFFECT_TYPE_SLEEP))
    {
        // If we're asleep and this is the result of sleeping
        // at night, apply the floating 'z's visual effect
        // every so often

        if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
        {
            effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);
            if(d10() > 6)
            {
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
            }
        }
    }

    // If we have the 'constant' waypoints flag set, walk to the next
    // waypoint.
    else if ( GetWalkCondition(NW_WALK_FLAG_CONSTANT) )
    {
        WalkWayPoints();
    }

    // Check to see if we should be playing default animations
    // - make sure we don't have any current targets
    else if ( !GetIsObjectValid(GetAttemptedAttackTarget())
          && !GetIsObjectValid(GetAttemptedSpellTarget())
          // && !GetIsPostOrWalking())
          && !GetIsObjectValid(GetNearestSeenEnemy()))
    {
        if (GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) || GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE) ||
            GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
        {
            // This handles special attacking/fleeing behavior
            // for omnivores & herbivores.
            DetermineSpecialBehavior();
        }
        else if (!IsInConversation(OBJECT_SELF))
        {
            if (GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS)
                || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)
                || GetIsEncounterCreature())
            {
                PlayMobileAmbientAnimations();
            }
            else if (GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS))
            {
                PlayImmobileAmbientAnimations();
            }
        }
    }

    // Send the user-defined event signal if specified
    if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_HEARTBEAT));
    }
}


perceived

//:://////////////////////////////////////////////////
//:: NW_C2_DEFAULT2
/*
  Default OnPerception event handler for NPCs.

  Handles behavior when perceiving a creature for the
  first time.
 */
//:://////////////////////////////////////////////////

#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 oOverride = GetLocalObject(OBJECT_SELF,"HEARD_INTRUDER");
    object oPercep = GetLastPerceived();
    int bSeen = GetLastPerceptionSeen();
    int bHeard = GetLastPerceptionHeard();
    int bVanished = GetLastPerceptionVanished();
    if(GetIsObjectValid(oOverride))
    {
        oPercep = oOverride;
        bSeen = FALSE;
        bVanished = FALSE;
        bHeard = TRUE;
    }

    if (bHeard == FALSE)
    {
        // Has someone vanished in front of me?
        bHeard = GetLastPerceptionVanished();
    }

    // This will cause the NPC to speak their one-liner
    // conversation on perception even if they are already
    // in combat.
    if(GetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION)
       && GetIsPC(oPercep)
       && bSeen)
    {
        SpeakOneLinerConversation();
    }

    // March 5 2003 Brent
    // Had to add this section back in, since  modifications were not taking this specific
    // example into account -- it made invisibility basically useless.
    //If the last perception event was hearing based or if someone vanished then go to search mode
    if (bVanished && GetIsEnemy(oPercep))
    {
        object oGone = GetLastPerceived();
        if((GetAttemptedAttackTarget() == oPercep ||
           GetAttemptedSpellTarget() == oPercep ||
           GetAttackTarget() == oPercep) && GetArea(oPercep) != GetArea(OBJECT_SELF))
        {
           ClearAllActions();
           DetermineCombatRound();
        }
    }

    // This section has been heavily revised while keeping the
    // pre-existing behavior:
    // - If we're in combat, keep fighting.
    // - If not and we've perceived an enemy, start to fight.
    //   Even if the perception event was a 'vanish', that's
    //   still what we do anyway, since that will keep us
    //   fighting any visible targets.
    // - If we're not in combat and haven't perceived an enemy,
    //   see if the perception target is a PC and if we should
    //   speak our attention-getting one-liner.
    if (GetIsInCombat(OBJECT_SELF))
    {
        // don't do anything else, we're busy
        //MyPrintString("GetIsFighting: TRUE");

    }
    // * BK FEB 2003 Only fight if you can see them. DO NOT RELY ON HEARING FOR ENEMY DETECTION
    else if (GetIsEnemy(oPercep) && bSeen)
    { // SpawnScriptDebugger();
        //MyPrintString("GetIsEnemy: TRUE");
        // We spotted an enemy and we're not already fighting
        if(!GetHasEffect(EFFECT_TYPE_SLEEP)) {
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
            {
                //MyPrintString("DetermineSpecialBehavior");
                DetermineSpecialBehavior();
            } else
            {
                //MyPrintString("DetermineCombatRound");
                SetFacingPoint(GetPosition(oPercep));
                SpeakString("NW_I_WAS_ATTACKED", TALKVOLUME_SILENT_TALK);
                DetermineCombatRound();
            }
        }
    }
    else
    {
        if (bSeen)
        {
            //MyPrintString("GetLastPerceptionSeen: TRUE");
            if(GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL)) {
                DetermineSpecialBehavior();
            } else if (GetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION)
                       && GetIsPC(oPercep))
            {
                // The NPC will speak their one-liner conversation
                // This should probably be:
                // SpeakOneLinerConversation(oPercep);
                // instead, but leaving it as is for now.
                ActionStartConversation(OBJECT_SELF);
            }
        }
        else
        // * July 14 2003: Some minor reactions based on invisible creatures being nearby
        if (bHeard && GetIsEnemy(oPercep))
        {
           // SpeakString("vanished");
            // * don't want creatures wandering too far after noises
            if (GetDistanceToObject(oPercep) <= 7.0)
            {
//                if (GetHasSpell(SPELL_TRUE_SEEING) == TRUE)
                if (GetHasSpell(SPELL_TRUE_SEEING))
                {
                    ActionCastSpellAtObject(SPELL_TRUE_SEEING, OBJECT_SELF);
                }
                else
//                if (GetHasSpell(SPELL_SEE_INVISIBILITY) == TRUE)
                if (GetHasSpell(SPELL_SEE_INVISIBILITY))
                {
                    ActionCastSpellAtObject(SPELL_SEE_INVISIBILITY, OBJECT_SELF);
                }
                else
//                if (GetHasSpell(SPELL_INVISIBILITY_PURGE) == TRUE)
                if (GetHasSpell(SPELL_INVISIBILITY_PURGE))
                {
                    ActionCastSpellAtObject(SPELL_INVISIBILITY_PURGE, OBJECT_SELF);
                }
                else
                {
                    ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_LEFT, 0.5);
                    ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_RIGHT, 0.5);
                    ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD, 0.5);
                }
            }
        }

        // 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);
           }
        }
    }

    // Send the user-defined event if appropriate
    if(GetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT) && bSeen)
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_PERCEIVE));
    }
}


               
               

               


                     Modifié par ShaDoOoW, 13 janvier 2012 - 10:30 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« Reply #6 on: January 13, 2012, 10:38:49 pm »


               tyvm ShadoOoW. I was hoping not to use any HB script, but no choice indeed.


Kato
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Understanding the listen skill
« Reply #7 on: January 13, 2012, 10:49:37 pm »


               

Kato_Yang wrote...

tyvm ShadoOoW. I was hoping not to use any HB script, but no choice indeed.


Kato

you are wrong in this

every creature has heartbeat script, any hostile creature should HAVE hearbeat script. There is nothing wrong on using heartbeat for this as default hearbeat script is ran nevertheless.

Few lines of code like this has no impact on the efficienty of anything.
               
               

               
            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« Reply #8 on: January 13, 2012, 11:07:53 pm »


               No doubt about your code ShadoOoW, I did simply ignore that every hostile creature MUST have a HB script. I'll add the one you posted to them(they have none currently), thanks again '<img'>


Kato
               
               

               


                     Modifié par Kato_Yang, 13 janvier 2012 - 11:08 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Understanding the listen skill
« Reply #9 on: January 14, 2012, 12:30:15 am »


               well of course, they dont have to, if you remove the heartbeat code, they still will be able to perform attacks, however they SHOULD HAVE. Without it, they wont wander around area, they wont do any special behavior etc. Default AI scripts contain heartbeat and its fine.

Since the code performs only single line when there is no player in area, there is minimal CPU intense. I was also very obsessed with script performancy, but then I learned how AI works. Believe me, each attack against single creature creates huge ammount of scripts run and code being performed. Even worse with area of effect spells like fireball. Each hit by the spell cause each creature to perform attack and tell every other creatures nearby to do the same. With default AI scripts if you get hoarded by 50+ small monsters and you cast aoe spell like meteor swarm, you will see a huge lag. (if you are interested in this issue, I have some tips how to prevent it, unfortunately no idea how to fix it)

SO being concerned with something so simple as heartbeat is really senseless. Though its a good idea to somehow despawn or clean your monsters if you are working on PW, in single player module neither this have any sense.
               
               

               
            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Understanding the listen skill
« Reply #10 on: January 14, 2012, 02:37:41 am »


               Okay, this is good to know.(I would indeed be interested by the tips to prevent spell lag, yet I guess this is another topic)


Kato