Jump to content

Detect() trigger misconceptions


aVENGER_(RR)

Recommended Posts

I noticed that many people (even experienced modders) seem to think that the Move Silently Thief skill can actually reduce the chance of being spotted when the Detect() trigger is used within a script. For the record, this is utterly false.

 

In reality, Detect() will return true as long as the referenced object is within the visual range of the actor who is running the script, regardless of invisibility, stealth and magical silence. This can be easily confirmed via testing. Simply assign the following script block to an enemy:

 

IF
Detect([PC])
THEN
RESPONSE #100
	DisplayStringHead(Myself,12964) // Detect Invisibility
END

 

Next, roll up a Thief with 100 Move Silently (or higher) and 100 Hide in Shadows (or higher), then try sneaking around the enemy who's running this script and watch what happens. Just for kicks, you could even cast a Silence spell on the Thief and he'll still be detected. Anyway, this is why I'd suggest revising the (somewhat vague) IESDP description of the Detect() trigger in favor of a clearer definition.

 

In other news, Move Silently and Hide in Shadows appear to to the same thing. For example, you are equally stealthy with a 100 in Move Silently skill and 0 Hide in Shadows and with 100 Hide in Shadows and 0 in Move Silently. Here's how to test it: roll up a Human Thief with 10 Dexterity and assign 100 Points into Move Silently and 0 to Hide in Shadows and then try to use stealth. You will fail a couple of times but, eventually, you will successfully hide despite having 0 ranks in that skill.

Link to comment

This should be known (I'm not sure where these "many people" come from).

 

Note that certain object types can't be used to detect invisibles this way -- Detect(NearestEnemyOf()) is indistinguishable from See(NearestEnemyOf()) (NearestEnemyOf and similar objects have to be visible to the caller). You need to use a spec ([2] or [255]; these will return an invisible actor iff Detect() is used) or run from a creature with SEEINVISIBLE.

 

Does it look like move silently is equivalent to hide in shadows (i.e., the bonus is 1:1), or do you think move silently is a lesser modifier? I'm not sure how to conclusively test it (in a manner more exact than just a roll of the bones); another item for Avenger's todo list. ;)

 

Of course, they were merged in BG, so it's possible that it's just an interface hack to separate the two values and they're just summed and handled in the same spot...

Link to comment

So, Detect([PC]) is simply a Range(PC, VISUALRANGE) check?

 

What about line of sight, is it checked?

 

Devsin: i think you mean NearestEnemy... filters invisibles before they could be passed to Detect.

 

Other object filters, like Player1 would still return an actor when that actor is invisible.

So or(6) Detect(Player1)Detect(Player2)... would do the same (arguably less effective).

Link to comment
In other news, Move Silently and Hide in Shadows appear to to the same thing. For example, you are equally stealthy with a 100 in Move Silently skill and 0 Hide in Shadows and with 100 Hide in Shadows and 0 in Move Silently. Here's how to test it: roll up a Human Thief with 10 Dexterity and assign 100 Points into Move Silently and 0 to Hide in Shadows and then try to use stealth. You will fail a couple of times but, eventually, you will successfully hide despite having 0 ranks in that skill.

 

Oh, yay! No more wasting points in Move Silently!

 

I always thought that Hide in Shadows was a skill for actually managing to go into Stealth mode, and Move Silently was a skill for remaining in this mode. But this puts it into entirely new light.

Link to comment
So, Detect([PC]) is simply a Range(PC, VISUALRANGE) check?
Yes. Protection from creature type (i.e., protection from GENDER 9 and Protection from Undead) will block this when applicable, however.

 

What about line of sight, is it checked?
Yes.

 

Devsin: i think you mean NearestEnemy... filters invisibles before they could be passed to Detect.
Yes, Nearest* triggers are assigned when used (recalculated every single time), and the object has to be visible to the calling actor to be valid (objects, like trigger points, automagically see invisible creatures). If the object is in range but not visible to the caller, Nearest* can never be that object (even if it really is the nearest).

 

Other object filters, like Player1 would still return an actor when that actor is invisible.

So or(6) Detect(Player1)Detect(Player2)... would do the same (arguably less effective).

I had an object writeup somewhere around here where I lumped them into three types based on behaviors; these objects are static (always defined). Other objects are usually bound only once when needed (LastAttackerOf, LastSummoner, etc.), and the only requirement there is that they be alive (although there were some exceptions IIRC). (Actually, I don't think I'm remembering that correctly; I think the ones I listed are the annoying variety that accept dead objects. Meh, find the old post, I guess.)

 

Oh, yay! No more wasting points in Move Silently!
It's almost certain that they stack, so you can probably exceed 255 if you spend on both, or you can just divide the points evenly for a little more flavor than all move silently or hide in shadows. Unless you're roleplaying the halfling assassin who wears flip-flops when sneaking up to his targets... :D
Link to comment

A good implementation would check if the target is deaf (automatic 100 in move silently) or blind (automatic 100 in hide in shadows).

 

So, if victim is blind, you got 0 in hide in shadows and 50 in move silently, you will still have an excellent chance (150% before applying spot checks).

 

But i guess the bg2 engine only checks if you can transfer to the hidden state (hide in shadows failed/succeed) and everyone are fooled unless they got some special detection method.

Link to comment
Note that certain object types can't be used to detect invisibles this way -- Detect(NearestEnemyOf()) is indistinguishable from See(NearestEnemyOf()) (NearestEnemyOf and similar objects have to be visible to the caller).

 

Yes, my tests confirm this as well.

 

You need to use a spec ([2] or [255]; these will return an invisible actor iff Detect() is used) or run from a creature with SEEINVISIBLE.

 

Correct, if an EA.IDS entry is used, Detect() will work fine on invisible characters i.e. Detect([GOODCUTOFF]) and Detect([EVILCUTOFF]) will return true in such cases.

 

Does it look like move silently is equivalent to hide in shadows (i.e., the bonus is 1:1), or do you think move silently is a lesser modifier? I'm not sure how to conclusively test it (in a manner more exact than just a roll of the bones); another item for Avenger's todo list. :)

 

By my estimates, that they are of equal value, i.e. having 100 in both HiS and MS is the same as having 0 in HiS and 200 in MS (i.e. you will successfully hide 95% of the time).

 

Of course, they were merged in BG, so it's possible that it's just an interface hack to separate the two values and they're just summed and handled in the same spot...

 

That's pretty much my impression as well. Also, note that these skills are still merged into "Stealth" for Rangers in BG2 and yet they still benefit from items which grant a bonus to either HiS or MS. However, in that case, the bonus to "Stealth" is applied at half rate i.e. if you equip the Boots of Elvenkind (BOOT07.ITM - grants +30% to Move Silently) on a Ranger he'll get a +15% bonus to his stealth according to the character sheet.

 

So, Detect([PC]) is simply a Range(PC, VISUALRANGE) check? What about line of sight, is it checked?

 

Correct. Detect() only works within the visual range of the creature who is running the script and any hindrances that block line of sight (i.e. walls) will block Detect() as well.

 

A good implementation would check if the target is deaf (automatic 100 in move silently) or blind (automatic 100 in hide in shadows).

 

I'd also add an automatic 100 in Move Silently if the target is STATE_SILENCED. Perhaps something for GemRB to tackle? How about implementing this in a new Sense(O:Object*) trigger?

Link to comment

There's probably nothing more behind the division of skills than a desire to keep people from capping out early or rolling over the total bonus; I've never seen any difference between the two skills and expect that the old stealth value is still used in the engine, it's just calculated by averaging the bytes at 0x45 and 0x68 now instead of just using the one.

 

There's nothing like a spot check in BGII and stealth rolls aren't even penalized for standing next to an enemy :)

 

How would you calculate the target of a modal state?

Link to comment

Nythrun: i think you ask how could a modal state in itself affect people differently, well it couldn't. But it could trigger a check which is personal. Probably it would be difficult to implement fairly. I don't know how a large group of monsters should behave when all of them are entitled to separate spot checks (one successful check will ruin the cover).

 

The opcodes themselves are fairly simple, they modify a single, separate stat.

So the averaging should be done on display and before check.

Link to comment

I guess what I'm cryptically alluding to is that stealth is an entirely personal matter in BGII - the game doesn't even care if your enemies can see you when you try to hide, it cares if you can see your enemies. So you'd really have to redo how stealth works from the ground up, in addition to adding STATE_DEAF and STATE_I_DONT_SEE_YOU_(Object) and making up rules for spot checks :D

 

I'd be chipper if you just kept thief skills from doing 255 + 1 = 0 :)

 

How come when anyone finds something new nowadays it's peculiar and unsatisfactory?

Link to comment
I believe that Detect(PlayerN) will still return positive even if PlayerN is appropriately protected (e.g. protection from undead scroll vs. lich), but Detect([PC]) won't.
I really, really hope that's true, but I don't think it is: I had to modify every single initiate dialogue script to Or(7) See([3]) See(Player6) ... See(Player1) to keep people from talking to the damn familiar, and I don't believe I was ever successful in forcing a general UNDEAD creature to realize that the protected from undead character existed.

 

Then, maybe nothing will be able to reference [PC] if pc is protected.
I can't remember how it worked exactly, but that's pretty close. An object spec is determined (again, every single time) as the nearest visible living object of type (unlike some of the identifiers, specs can be forced to pick up invisibles with Detect()); with a protected character, the creature protected from won't ever return that character as a valid object (so not just See(), but Spell([2],BIGBYS_CLENCHING_ANUS) will also fail). What I can't remember is if the engine moves on to the nearest visible living unprotected object, or if the check gets stuck on the protected character.

 

Given how specs are identified, no, I can't even fathom why Nearest() doesn't work (luckily, it's unnecessary: Nearest([x]) == [x]).

Link to comment
I believe that Detect(PlayerN) will still return positive even if PlayerN is appropriately protected (e.g. protection from undead scroll vs. lich), but Detect([PC]) won't.
I really, really hope that's true, but I don't think it is: I had to modify every single initiate dialogue script to Or(7) See([3]) See(Player6) ... See(Player1) to keep people from talking to the damn familiar, and I don't believe I was ever successful in forcing a general UNDEAD creature to realize that the protected from undead character existed.

 

Apparently, David is right. For some reason Detect(Player1) goes right through Protection from Undead while Detect([PC]) doesn't. Note that the creature in question (SKELWA01.CRE) didn't have the SEEINVISIBLE effect applied to it. You still need a clear line of sight for either though, so obstacles like walls will make them fail.

 

However, Range(Player1,20) seems to ignore invisibility, Protection from Undead and even obstacles such as walls! OTOH, Range([PC],20) fails on either of those. Weird...

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...