Understanding the listen skill
#1
Posté 13 janvier 2012 - 08:10
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
#2
Posté 13 janvier 2012 - 09:21
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 .
#3
Posté 13 janvier 2012 - 09:25
Kato
#4
Posté 13 janvier 2012 - 09:36
#5
Posté 13 janvier 2012 - 09:43
Kato
#6
Posté 13 janvier 2012 - 10:17
hmm strange, I had negative results with this, nothing had changedKato_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
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 .
#7
Posté 13 janvier 2012 - 10:38
Kato
#8
Posté 13 janvier 2012 - 10:49
you are wrong in thisKato_Yang wrote...
tyvm ShadoOoW. I was hoping not to use any HB script, but no choice indeed.
Kato
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.
#9
Posté 13 janvier 2012 - 11:07
Kato
Modifié par Kato_Yang, 13 janvier 2012 - 11:08 .
#10
Posté 14 janvier 2012 - 12:30
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.
#11
Posté 14 janvier 2012 - 02:37
Kato





Retour en haut






