Stealth Mechanics

Discuss modding questions and implementation details.
Post Reply
User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Stealth Mechanics

Post by mikeprichard »

Ha, you shouldn't have encouraged me to keep thinking about this... but let me take one more stab at the stealth system, and if I then still can't fully understand it, I won't clutter this topic with more of my posts and will be satisfied with the much improved text that's already in the revised wiki. The main issue is that 90% of the code is nonsense to me, so I have to rely on your interpretative language, and sometimes my own internal concepts and terms are different. But this is what I'm thinking is the step-by-step process assuming a creature that has the potential to ever turn hostile; please feel free to correct wherever necessary:

1) You enter the detection radius/range of the creature. Your Stealth skill now begins to be actively checked to avoid initial detection by the creature.
2) The creature begins running perception checks to see if it can see and/or hear you.
(I believe this involves not only your distance from and position in relation to the creature, but the creature's own Stealth skill value. If not, I'm not sure when/how exactly the creature's Stealth skill is ever checked in this process of the creature attempting to detect you. The wiki as just revised does indicate the creature's Stealth is somehow a factor, as you seem to agree per your general agreement with the new wiki paragraph.)
3) Before the creature first sees and/or hears you, you may continue to move at any speed and attempt to avoid detection.
4) If the creature does see and/or hear you, it turns hostile - i.e. initiates active combat - and approaches your position.
5) If you then again leave the creature's line of sight and aural range, the creature will no longer be engaged in active combat, but will have entered a heightened "search" state. You may now continue to move only at "crouch" or "sneak" speed if you wish to attempt to continue to avoid detection and another triggering of active combat.

If the above five steps are at least largely accurate, my confusion relates to your recent comments "the enemy also needs to be hostile for stealth checks to go off... enemy being hostile before anything else will start." I'm interpreting the "stealth checks going off" as step 1 above - your Stealth skill is actively checked as soon as you enter the creature's detection range, but before it initially goes hostile - which would jibe with the revised wiki language you generally agree with, but seems to be inconsistent with these final quoted comments of yours just now. So, I'm guessing by the "stealth checks going off" and "anything else... starting" you're instead only referencing my above steps 4 and 5? Reviewing the past few pages again, much of my remaining confusion relates to your statements regarding the creature "finding" you, "detecting" you, triggering the "encountered" flag, and engaging in active combat - sometimes these situations seem to overlap/be identical, while sometimes they seem to be mutually exclusive.

l3lessed
Posts: 1403
Joined: Mon Aug 12, 2019 4:32 pm
Contact:

Re: Cracking Open Combat

Post by l3lessed »

Okay, that's the issue in a way. There are always going to be a number of basic checks done before the stealth check is ever done. Also, there are two switches you are getting confused I think.

We have a detected enemy state.
We have an encounter enemy state.

The detected state/boolean trigger is being set every update no matter what.
The encounter state/boolean trigger is only set when the enemy detects you, and then it stays set for 8 hours or is reset if an enemy detects someone again. And, as explained below, detection is checked at beginning of every update by sight or small proximity radius.

Code for how the target is set before all other checks are done:

Code: Select all

// Classic stealth mechanics would be interfered with by hearing, so only enable
                // hearing if the enemy has detected the target. If target is visible we can omit hearing.
                if (detectedTarget && !targetInSight)
                    targetInEarshot = CanHearTarget();
                else
                    targetInEarshot = false;

                // Note: In classic an enemy can continue to track the player as long as their
                // giveUpTimer is > 0. Since the timer is reset to 200 on every detection this
                // would make chameleon and shade essentially useless, since the enemy is sure
                // to detect the player during one of the many AI updates. Here, the enemy has to
                // successfully see through the illusion spell each classic update to continue
                // to know where the player is.
                if (GameManager.ClassicUpdate)
                {
                    blockedByIllusionEffect = BlockedByIllusionEffect();
                    if (lastHadLOSTimer > 0)
                        lastHadLOSTimer--;
                }

                if (!blockedByIllusionEffect && (targetInSight || targetInEarshot))
                {
                    detectedTarget = true;
                    lastKnownTargetPos = target.transform.position;
                    lastHadLOSTimer = 200f;
                }
                else if (!blockedByIllusionEffect && StealthCheck())
                {
                    detectedTarget = true;

                    // Only get the target's location from the stealth check if we haven't had
                    // actual LOS for a while. This gives better pursuit behavior since enemies
                    // will go to the last spot they saw the player instead of walking into walls.
                    if (lastHadLOSTimer <= 0)
                        lastKnownTargetPos = target.transform.position;
                }
                else
                    detectedTarget = false;
Before everything, the script first begins searching for a target on each update routine using either a small proximity around the enemy or line of site. If the the enemy can't see you or is not close enough to just perceive you, then the script will set him to have no actual target, so the enemy will start wandering around looking for you again. After this point, then all other code kicks in below I'm explaining.

first, check if enemy still has line of site or if the player has a magical effect that would make him disappear from site. if player has effect, no longer will he be detected as he is concealed by magic. Enemy will lose you as a target and start looking for you to regain you as a target.

Second, if no conceal effect, check to see if the enemy can see or hear you. If so, again, you are detected and enemy adjust tracking. If not, enemy wanders trying to detect you again.

Third, do actual stealth check here. If evenmy hasn't detected and this encountered you yet, Returns false if succeed. If you have been detected, the encountered switch is set to true for 8 hours, and you must stay below half speed to do stealth checks.

If the enemy hasn't detected you by this point through one of those methods, detect trigger is set to false.

Code for the above flow explanation:

Code: Select all

// Classic stealth mechanics would be interfered with by hearing, so only enable
                // hearing if the enemy has detected the target. If target is visible we can omit hearing.
                if (detectedTarget && !targetInSight)
                    targetInEarshot = CanHearTarget();
                else
                    targetInEarshot = false;

                // Note: In classic an enemy can continue to track the player as long as their
                // giveUpTimer is > 0. Since the timer is reset to 200 on every detection this
                // would make chameleon and shade essentially useless, since the enemy is sure
                // to detect the player during one of the many AI updates. Here, the enemy has to
                // successfully see through the illusion spell each classic update to continue
                // to know where the player is.
                if (GameManager.ClassicUpdate)
                {
                    blockedByIllusionEffect = BlockedByIllusionEffect();
                    if (lastHadLOSTimer > 0)
                        lastHadLOSTimer--;
                }

                if (!blockedByIllusionEffect && (targetInSight || targetInEarshot))
                {
                    detectedTarget = true;
                    lastKnownTargetPos = target.transform.position;
                    lastHadLOSTimer = 200f;
                }
                else if (!blockedByIllusionEffect && StealthCheck())
                {
                    detectedTarget = true;

                    // Only get the target's location from the stealth check if we haven't had
                    // actual LOS for a while. This gives better pursuit behavior since enemies
                    // will go to the last spot they saw the player instead of walking into walls.
                    if (lastHadLOSTimer <= 0)
                        lastKnownTargetPos = target.transform.position;
                }
                else
                    detectedTarget = false;
So heres two flow diagrams start from the beginning of the script running:
Checks if you are in enemies line of site or peripheral senses -> Succeed -> Sets player as target -> Checks for null target -> fails because player has been set to target -> flips encountered trigger to true -> Goes through detection code discussed in previous posts but doesn't matter since already detected -> Sets encountered trigger to true and then tries pacifying the enemy as a last attempt to stop combat enagement.

Checks if you are in enemies line of site or peripheral senses -> fail -> sets target to null -> checks for null target -> succeeds -> sets detectedTarget and targetInsight to false -> If already encounters enemy wanders around looking for enemies | If not encountered yet, enemy runs normal non-hostile mode.

Aka, stealth checks will not happen until the player is set as a target, and this happens before everything else only if the enemy can either be close enough to feel your presence or see you. That is, every update, if you are not in close proximity of the enemy or can be seen by the enemy, the detectPlayer switch goes back to false to tell the enemy to go back to wandering around for you, trying to either see or hear you so they can set a target again.

Think of it like humans again. A human cannot go to a place unless they can see what it is. That is, humans can't have a target until their senses register something to target. It's the same here. Nothing will happen, until the enemy can see you or you're really close to them.

The small block of code is ran before all other checks. It is easy to run over without noticing but is central to how the AI works. This ensures you can't be seen or detected if you are not within line of site or near the enemy at the beginning of every update cycle. It doesn't matter if you have been detected or encountered before. It will check every update cycle for a target, no matter what, using site and proximity, and when it can't find it, it activates this to tell the AI, hey, you have encountered someone, but you can't see them anymore and don't know where they went. And then the rest of the code we discussed before runs.

Code: Select all

                if (target == null)
                {
                    targetInSight = false;
                    detectedTarget = false;
                    return;
                }
The only way the encounter trigger will change is if the enemy has not detected a target within 8 hours of the last encounter. And, pretty much all the encounter trigger does, is ensure you have to move at half-speed once detected. Encounter trigger is their to make it so their is a difference in how the AI behaves before detecting an enemy and after, and all it does to make that change is the half speed check if they have encountered an enemy.
Last edited by l3lessed on Fri Dec 13, 2019 10:33 pm, edited 4 times in total.
My Daggerfall Mod Github: l3lessed DFU Mod Github

My Beth Mods: l3lessed Nexus Page

Daggerfall Unity mods: Combat Overhaul Mod

Enjoy the free work I'm doing? Consider lending your support.

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Cracking Open Combat

Post by mikeprichard »

You've made heroic efforts to get me to understand, but I have to admit there are several points I still just don't grasp. However, I really don't want to take up more of your time here, and it seems the revised wiki language is now accurate at least as far as it goes, so I'm going to let you move on! In any case, this is excellent information for future reference - thanks once more for all your work.

l3lessed
Posts: 1403
Joined: Mon Aug 12, 2019 4:32 pm
Contact:

Re: Cracking Open Combat

Post by l3lessed »

No problem. It's hard for me, and I have been coding on and off since 6th grade.

There is a number of switches referencing backwards in the code flow cycle, which makes it hard to understand how things are being activated and when.

Way I try to understand it is by thinking of how humans work because it actually is not a bad approximation.

Mind senses or see's something near us -> our brain goes we detect something and flips us into encounter/fight mode -> we begin searching for it with eyes and ears -> can't find it -> our mind doesn't detect anything but it still is in encountered/survival mode -> we keep searching until we give up because we didn't detect anything, feel safe again, and leave encounter/fight mode.

Mind senses or see's something near us -> our brain goes we detect something and flips us into encounter/fight mode -> we begin searching for it with eyes and ears -> we think we see, hear, or sense something near us -> brain says we detect something again -> encounter mode/survival mode reactivated -> begin heading to new source of information/sound/site -> repeat until engagement starts or nothing is found and feel safe enough to return to normal routine and home.

The only difference with being encountered is how fast you can move. It does nothing else within the stealth code. Everything else is managed by if the enemy has a target and can detect them in some way (AKA the detect trigger is set to true on the update cycle).

Anyways, yeah, think I'm done now too. Either way, there is enough information posted on this, people in the future should be fine for mods.
Last edited by l3lessed on Fri Dec 13, 2019 10:46 pm, edited 3 times in total.
My Daggerfall Mod Github: l3lessed DFU Mod Github

My Beth Mods: l3lessed Nexus Page

Daggerfall Unity mods: Combat Overhaul Mod

Enjoy the free work I'm doing? Consider lending your support.

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Cracking Open Combat

Post by mikeprichard »

Yeah, I'd love to see mods that significantly adjust/expand the base stealth mechanics, and I'm sure they'll all find something useful here!

User avatar
Hazelnut
Posts: 3016
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Cracking Open Combat

Post by Hazelnut »

May be worth splitting this stealth discussion into it's own thread with a suitable title for posterity... yes?
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

User avatar
mikeprichard
Posts: 1037
Joined: Sun Feb 19, 2017 6:49 pm

Re: Cracking Open Combat

Post by mikeprichard »

It's up to you and l3lessed, but since there are other topics weaved into the discussion here and there, and the current topic is already linked from the UESP wiki page (which can't be edited if the topic URL were to change), I have a slight preference for leaving it here. :)

l3lessed
Posts: 1403
Joined: Mon Aug 12, 2019 4:32 pm
Contact:

Re: Cracking Open Combat

Post by l3lessed »

Don't mind moving this discussion into separate thread. Could you drop the movement speed discussion and code explanation into its own post too?
My Daggerfall Mod Github: l3lessed DFU Mod Github

My Beth Mods: l3lessed Nexus Page

Daggerfall Unity mods: Combat Overhaul Mod

Enjoy the free work I'm doing? Consider lending your support.

User avatar
Jay_H
Posts: 4070
Joined: Tue Aug 25, 2015 1:54 am
Contact:

Re: Stealth Mechanics

Post by Jay_H »

I've done a topic split based on my perception. I make no promise that all relevant content was included :D

Post Reply