Difference between revisions of "OnPerception"

From NWN Lexicon
Jump to: navigation, search
(Ranges of Sight and Hearing)
 
(3 intermediate revisions by the same user not shown)
Line 54: Line 54:
 
Hearing and sight perception ranges appear to be identical if a creature is not in stealth mode or some form of invisibility.
 
Hearing and sight perception ranges appear to be identical if a creature is not in stealth mode or some form of invisibility.
  
<br />
+
==== Ranges of Sight and Hearing ====
 +
 
 +
Creatures have one of 4 different perception ranges which boil down to 3 real values, plus an additional potential "combat" value. Under the "Advanced" tab of any creature is the "Perception Range" dropdown.
 +
 
 +
Note there is no way to change a creatures perception range apart from the resref.
 +
 
 +
These reference ranges.2da, specifically these lines are relevant for perception:
 +
 
 +
<pre>
 +
          Label              PrimaryRange  SecondaryRange  Name     
 +
8          PercepRngShrt      10            10              6668
 +
9          PercepRngMed      20            20              6669
 +
10        PercepRngLng      35            20              6670
 +
11        PercepRngDefault  ****          ****            6671
 +
12        PercepRngPlayer    35            20              ****
 +
13        PercepRngMonster  28            15              ****
 +
</pre>
 +
 
 +
'''PrimaryRange''' is the sight/spot range (used for general sight of non-stealthed creatures, and for spot/stealth checks) and '''SecondaryRange''' is the listen range (used for listen/move silently checks).
 +
 
 +
Players of course use '''PerceptRngPlayer''' for all their checks so get the maximum game range. This can be relevant in NWN:EE since you can set a script in OnPerception for players.
 +
 
 +
If the monster is set to '''Default''' it uses the current appearance.2da "PERCEPTIONDIST" which is a lookup to ranges.2da. Most creatures use "Medium" range (9), while a few use "Long" (10) eg; Dragons, Noble Giants.
 +
 
 +
The '''PercepRngMonster''' entry seems to be used in combat ''if'' the range set here is higher than the current range. This means in combat a "Short" perception range monster (sight: 10 meters, or 1 tile length) can now see further (28 meters) for the purposes of being somewhat competent in combat (a lot of AI scripts assume a seen enemy to properly function). This can be tested with a [[GetNearestCreature]] PERCEPTION_TYPE_SEEN loop on a short ranged creature hit to invoke combat.
 +
 
 +
The ranges, manually if set, have different use cases:
 +
* Short range may be better for dense NPC heavy areas, to limit perception range checks for ambient movement, if they are not intended to be fought (it would not be recommended to use Short range for anyone who you want to fight PCs).
 +
* Medium range is usually used for easier singleplayer modules so the players can spot a creature and plan an attack getting the jump on them. Of course this is not always the case (small rooms and opening a door for instance, or shorter corridors and smaller rooms) but tends to make it significantly easier to deal with enemies.
 +
* Long range is useful for "bosses" or any henchmen, even in easier modules, which is why Dragons default to it.
 +
 
 +
A custom content creator may wish to up PercepRngShrt, PercepRngMed and PercepRngMonster to 35/20 to have the default creature range act similarly to a players range, negating easy sneak attacks and long range spell usage before the creature is aware. Doing this on existing modules is not recommended since it can sometimes have unintended side effects.
 +
 
 +
PrimaryRange going over 35 won't really work well (NWN:EE or not) due to how things are loaded by the game - while it might work for NPCs (who don't load graphics) it'd mess up players who would "see" invisible objects.
 +
 
 +
There are also in [[ruleset.2da]] ranges for FEAT_BLINDSIGHT_60_FEET, FEAT_BLINDSIGHT_10_FEET and FEAT_BLINDSIGHT_5_FEET (Although the latter 2 are dummied out so only 60 feet is available in the toolset for creatures). The ranges appear to default to:
 +
 
 +
<pre>
 +
303  BLINDSIGHT_RANGE_5_FEET                          2.0f
 +
304  BLINDSIGHT_RANGE_10_FEET                        4.0f
 +
305  BLINDSIGHT_RANGE_60_FEET                        18.288f
 +
</pre>
 +
 
 +
This is a special kind of sight, and is likely to make a creature seen in that distance regardless of their stealth value, negating the stealth (to that monster) and meaning they lose the element of surprise. These are relatively close values, so outside those ranges usual perception rules apply.
 +
 
 +
==== Alternatives to OnPerception ====
 +
 
 +
This event is generally most useful for combat usage; it is difficult to use it reliably for ambient AI work. Instead some alternatives are:
 +
* The heartbeat script - this fires ever 6 seconds, so knowing a creature is in a certain distance can work (to react to it) but it can vary greatly
 +
* Triggers - for static NPCs this works to initiate combat / do a animation
 +
* Persistent Area of Effects - Use an invisible "aura" referencing a line in vfx_persistent.2da by using [[EffectAreaOfEffect]] - VFX_CUSTOM line 37 is perfect since it has no visual presence, no default scripts, and has a 5M range. An example may be: <code>EffectAreaOfEffect(37, "greet_nearby", "", "goodbye_nearby");</code> to fire greetings on those entering and goodbyes to those leaving 5M from them.
  
 
====Example====
 
====Example====

Latest revision as of 00:07, 28 June 2020

OnPerception

The script attached to an NPC's Perception event will execute whenever the NPC's perception is triggered by another creature. The perceived creature is returned with GetLastPerceived(). There are four types of perception - Heard, Inaudible, Seen, Vanished - only one of which will have triggered the event. To determine which type, use the following functions:

Note only one of these will ever be true; as per below it will usually fire both seen and heard if you walk into a creatures perception range (and vice versa both vanished and inaudible if you walk away from it). The order appears to be hearing first, than seeing ie; GetLastPerceptionHeard() and GetLastPerceptionInaudible() fire before GetLastPerceptionSeen() and GetLastPerceptionVanished().

When a creature spawns it appears they only get 1 event fired about 4 seconds after spawning (no AI except OnSpawn is run before this time, no heartbeats or anything) - it's a little weird this event!

Since they can both fire at once, if the event is GetLastPerceptionHeard() it may still be that the perceived object is seen with GetObjectSeen().

Note also that creatures always have "eyes". The Blindsense monster feat may help them detect invisible creatures more easily, but in essence they will "see" them still.

Common uses of this script include having the creature yell a battle cry, greet the PC, or run away if combat isn't being initiated.


Trigger

A creature object has switched a perception state of the caller from TRUE to FALSE or vice versa. There are two perception states tracked for each creature relative to the caller: Heard or Seen. It is important to note that this event only executes at the moment one of these states changes. If the state of both perception types change at the same time, this event will occur twice, once for Seen/Vanished, and once for Heard/Inaudible.

For example, when a creature is heard for the first time by the caller, the Heard state switches from FALSE to TRUE, and this event is triggered. Likewise when that same creature goes beyond the hearing range of the caller, the Heard state switches to FALSE and the event is triggered.

Note that "a creature" does not necessarily mean a PC. This event can execute when a NPC or PC is teleported out of the area, as well as if an NPC's corpse disappears.

Perception ranges are configured in ranges.2da - the default for creatures is significantly shorter than the players own range. The highest usable perception range is 35.0 (3.5 tiles) which going over can cause issues - both because placeables have a set 35.0M appear distance, and a multiplayer server will not work on things outside this range properly.

DM note the "disappear" and "appear" options in the top left are odd. If you start off map and in disappear mode, and appear in front of a creature in range of perception it correcly fires (as if invisibility or stealth was lost). However if you disappear in front of a creature, the perception events do not fire and GetObjectSeen() and GetObjectHeard() still return 1. In fact they won't fire until the DM appears again, whereupon suddenly the events fire. Very strange for sure.


Function(s)

Primary

Secondary


Remarks

The OnPerception generic AI gives priority to first going into search mode if an enemy has suddenly vanished, then telling the creature to combat an enemy that has appeared.

GetLastPerception values, as the descriptions imply, will only return a maximum of 1 TRUE value but only fire at most twice at once. You can expect logically an object cannot vanish and become heard, for instance in the same call, but it can vanish and become inaudiable at the same time (eg; moving out of perception range).

Hearing and sight perception ranges appear to be identical if a creature is not in stealth mode or some form of invisibility.

Ranges of Sight and Hearing

Creatures have one of 4 different perception ranges which boil down to 3 real values, plus an additional potential "combat" value. Under the "Advanced" tab of any creature is the "Perception Range" dropdown.

Note there is no way to change a creatures perception range apart from the resref.

These reference ranges.2da, specifically these lines are relevant for perception:

           Label              PrimaryRange   SecondaryRange   Name      
8          PercepRngShrt      10             10               6668
9          PercepRngMed       20             20               6669
10         PercepRngLng       35             20               6670
11         PercepRngDefault   ****           ****             6671
12         PercepRngPlayer    35             20               ****
13         PercepRngMonster   28             15               ****

PrimaryRange is the sight/spot range (used for general sight of non-stealthed creatures, and for spot/stealth checks) and SecondaryRange is the listen range (used for listen/move silently checks).

Players of course use PerceptRngPlayer for all their checks so get the maximum game range. This can be relevant in NWN:EE since you can set a script in OnPerception for players.

If the monster is set to Default it uses the current appearance.2da "PERCEPTIONDIST" which is a lookup to ranges.2da. Most creatures use "Medium" range (9), while a few use "Long" (10) eg; Dragons, Noble Giants.

The PercepRngMonster entry seems to be used in combat if the range set here is higher than the current range. This means in combat a "Short" perception range monster (sight: 10 meters, or 1 tile length) can now see further (28 meters) for the purposes of being somewhat competent in combat (a lot of AI scripts assume a seen enemy to properly function). This can be tested with a GetNearestCreature PERCEPTION_TYPE_SEEN loop on a short ranged creature hit to invoke combat.

The ranges, manually if set, have different use cases:

  • Short range may be better for dense NPC heavy areas, to limit perception range checks for ambient movement, if they are not intended to be fought (it would not be recommended to use Short range for anyone who you want to fight PCs).
  • Medium range is usually used for easier singleplayer modules so the players can spot a creature and plan an attack getting the jump on them. Of course this is not always the case (small rooms and opening a door for instance, or shorter corridors and smaller rooms) but tends to make it significantly easier to deal with enemies.
  • Long range is useful for "bosses" or any henchmen, even in easier modules, which is why Dragons default to it.

A custom content creator may wish to up PercepRngShrt, PercepRngMed and PercepRngMonster to 35/20 to have the default creature range act similarly to a players range, negating easy sneak attacks and long range spell usage before the creature is aware. Doing this on existing modules is not recommended since it can sometimes have unintended side effects.

PrimaryRange going over 35 won't really work well (NWN:EE or not) due to how things are loaded by the game - while it might work for NPCs (who don't load graphics) it'd mess up players who would "see" invisible objects.

There are also in ruleset.2da ranges for FEAT_BLINDSIGHT_60_FEET, FEAT_BLINDSIGHT_10_FEET and FEAT_BLINDSIGHT_5_FEET (Although the latter 2 are dummied out so only 60 feet is available in the toolset for creatures). The ranges appear to default to:

303  BLINDSIGHT_RANGE_5_FEET                          2.0f
304  BLINDSIGHT_RANGE_10_FEET                         4.0f
305  BLINDSIGHT_RANGE_60_FEET                         18.288f

This is a special kind of sight, and is likely to make a creature seen in that distance regardless of their stealth value, negating the stealth (to that monster) and meaning they lose the element of surprise. These are relatively close values, so outside those ranges usual perception rules apply.

Alternatives to OnPerception

This event is generally most useful for combat usage; it is difficult to use it reliably for ambient AI work. Instead some alternatives are:

  • The heartbeat script - this fires ever 6 seconds, so knowing a creature is in a certain distance can work (to react to it) but it can vary greatly
  • Triggers - for static NPCs this works to initiate combat / do a animation
  • Persistent Area of Effects - Use an invisible "aura" referencing a line in vfx_persistent.2da by using EffectAreaOfEffect - VFX_CUSTOM line 37 is perfect since it has no visual presence, no default scripts, and has a 5M range. An example may be: EffectAreaOfEffect(37, "greet_nearby", "", "goodbye_nearby"); to fire greetings on those entering and goodbyes to those leaving 5M from them.

Example

// creature turns towards anyone he sees
// if the creature seen is female, the NPC bows
void main()
{
     int nEvent = GetUserDefinedEventNumber();
     if (nEvent == 1002) //  OnPerception event
     {
          object oTarget = GetLastPerceived();
          // check for sight
          if (GetLastPerceptionSeen())
          {
               ActionDoCommand(SetFacingPoint(GetPosition(oTarget)));
               // if they female, bow
               if (GetGender(oTarget) == GENDER_FEMALE)
               {
                    ActionWait(0.5);
                    ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);
               }
          }
     }
}

See Also

functions: 

GetLastPerceptionVanished()