IntenseMute Posted October 6, 2021 Share Posted October 6, 2021 (edited) I'm currently working on a mod that requires me to know the formula on how the game calculates detection (Due to workarounds involving bugs with detection).Apparently this GECK Wiki page is all we know about this calculation, which is very much incomplete.Below is what I tested to be the actual calculation and I even made a mod displaying the predicted detection value compared to the actual value provided by the JIP function "GetDetectionValue". Ref Actor1 Ref Actor2 Float _Attenuation Float _VisualFactor Float _PerceptionFactor Float _AuditoryFactor Float _SneakFactor Float _DetectionValue If Actor1.GetDistance3D Actor2 <= GetGameSetting fSneakMaxDistance If Actor1.IsInInterior == 1 Let _Attenuation := (1 - Actor1.GetDistance3D Actor2 / GetGameSetting fSneakMaxDistance) ^ GetGameSetting fSneakDistanceAttenuationExponent ElseIf GetGameSetting fSneakExteriorDistanceMult != 0 Let _Attenuation := (1 - Actor1.GetDistance3D Actor2 / (GetGameSetting fSneakMaxDistance * GetGameSetting fSneakExteriorDistanceMult)) ^ GetGameSetting fSneakDistanceAttenuationExponent Else Let _Attenuation := 0 EndIf Else Let _Attenuation := 0 ^ GetGameSetting fSneakDistanceAttenuationExponent EndIf Let _VisualFactor := Actor1.GetLOS Actor2 * (Floor (Actor2.GetActorLightAmount) + GetGameSetting fDetectionSneakLightMod) * GetGameSetting fSneakLightMult If Actor2.IsMoving == 0 Let _VisualFactor *= 1 + Actor2.IsRunning * GetGameSetting fSneakLightRunMult Else Let _VisualFactor *= 1 + Actor2.IsRunning * GetGameSetting fSneakLightRunMult + GetGameSetting fSneakLightMoveMult EndIf If Actor1.GetSleeping == 3 Let _VisualFactor += 50 * GetGameSetting fSneakSleepBonus * GetGameSetting fSneakSkillMult EndIf If Actor2.GetAV Chameleon > 0 Let _VisualFactor *= 0 EndIf Let _PerceptionFactor := (GetGameSetting fSneakPerceptionSkillMax - GetGameSetting fSneakPerceptionSkillMin) / 10 If Actor1.GetAV Perception < 1 Let _PerceptionFactor *= 1 ElseIf Actor1.GetAV Perception > 10 Let _PerceptionFactor *= 10 Else Let _PerceptionFactor *= Actor1.GetAV Perception EndIf Let _PerceptionFactor += GetGameSetting fSneakPerceptionSkillMin Let _PerceptionFactor *= GetGameSetting fSneakSkillMult Let _AuditoryFactor := 0 If FunctionRef2.IsMoving != 0 Let _AuditoryFactor += Floor (GetGameSetting fSneakBootWeightBase) + GetGameSetting fSneakBootWeightMult * GetWeight (Actor2.GetEquippedObject 2) If Actor2.IsRunning == 1 Let _AuditoryFactor *= GetGameSetting fSneakRunningMult EndIf EndIf If (Actor2 == Player && (IsPlayerActionActive 1 == 1 || IsPlayerActionActive 2 == 1 || IsPlayerActionActive 3 == 1 || IsPlayerActionActive 4 == 1)) || (Actor2 != Player && Actor2.GetCurrentAIPackage == 33) If GetWeaponDetectionSoundLevel (Actor2.GetEquippedObject 5) == 2 Let _AuditoryFactor += GetGameSetting iSoundLevelSilent * GetGameSetting fSneakActionMult ElseIf GetWeaponDetectionSoundLevel (Actor2.GetEquippedObject 5) == 1 Let _AuditoryFactor += GetGameSetting iSoundLevelNormal * GetGameSetting fSneakActionMult ElseIf GetWeaponDetectionSoundLevel (Actor2.GetEquippedObject 5) == 0 Let _AuditoryFactor += GetGameSetting iSoundLevelLoud * GetGameSetting fSneakActionMult EndIf EndIf ;Their is currently no function that allows you to check 360 degree LOS, so we'll just have to make do with using GetLOS (190 degree LOS) for now If Actor1.GetLOS Actor2 == 0 && Actor2.GetLOS Actor1 == 0 Let _AuditoryFactor *= GetGameSetting fSneakSoundLosMult EndIf If Actor2.GetActorVelocity != 0 && (Actor2.GetHasContactType 42 == 1 || Actor2.GetHasContactType 43 == 1) Let _AuditoryFactor += GetGameSetting iSoundLevelLoud * GetGameSetting fSneakActionMult EndIf Let _AuditoryFactor *= GetGameSetting fSneakSoundsMult Let _AuditoryFactor := Floor _AuditoryFactor If Actor2.IsSneaking == 1 If Actor2.GetAV Sneak < 0 Let _SneakFactor := 0 ElseIf Actor2.GetAV Sneak > 100 Let _SneakFactor := 100 Else Let _SneakFactor := Actor2.GetAV Sneak EndIf Let _SneakFactor += GetGameSetting iSneakLevelBonus * Actor2.GetLevel - GetGameSetting iSneakLevelBonus * Actor1.GetLevel Let _SneakFactor += GetGameSetting iSneakStartBonus If Actor2.GetArmorClass == 2 Let _SneakFactor -= GetGameSetting iMediumArmorStealthPenalty ElseIf Actor2.GetArmorClass == 3 Let _SneakFactor -= GetGameSetting iHeavyArmorStealthPenalty EndIf If GetGameSetting iSneakStartBonus < (GetGameSetting iSneakStartBonusLevelPenatly * Actor2.GetLevel) Let _SneakFactor -= GetGameSetting iSneakStartBonus Else Let _SneakFactor -= GetGameSetting iSneakStartBonusLevelPenatly * Actor2.GetLevel EndIf Let _SneakFactor *= GetGameSetting fSneakSkillMult EndIf Let _DetectionValue := GetGameSetting fSneakBaseValue + Ceil ((_VisualFactor * _Attenuation) + (_PerceptionFactor * _Attenuation) + (_AuditoryFactor * _Attenuation)) - Floor _SneakFactor The game uses many environmental variables and conditions to determine detection.If you wanted to predict the outcome of a detection event that will happen in the future, you would have to answer each question listed below: [int] What is Actor1's perception level? See "GetAV Perception"[int] What is Actor2's sneak level? See "GetAV Sneak"[Float] In "game-units", what is the distance (In 3D-space) between the two actors? The function, "GetDistance3D", can be used here as it returns values in game-units.[boolean] Is Actor2 moving? See "IsMoving"[boolean] Is Actor2 running? See "IsRunning"[boolean] Is Actor2 sneaking? See "IsSneaking"[boolean] Is Actor2 under the effects of a Stealth Boy or any other stealth field effect? Use "GetAV Chameleon"[Float] From 0 to 100, how illuminated is Actor2? See "GetActorLightAmount", requires JIP LN NVSE Plugin[int] How much weight does Actor2's equipped body armor have? See "GetEquippedObject 2" and "GetWeight"[boolean] Is Actor2 wearing heavy armor? See "GetArmorClass", requires JIP LN NVSE Plugin[boolean] Is Actor2 wearing medium armor? See "GetArmorClass", requires JIP LN NVSE Plugin[boolean] Is the location marked as an interior? See "IsInInterior"[boolean] Does Actor1 have line of sight with Actor2? See "GetLineOfSight"[boolean] Is there an object between both actors? Their is currently no function that allows you to check this.[boolean] Has Actor2 used his/her weapon within the last couple seconds? See "IsPlayerActionActive 1-4" and "GetCurrentAIPackage == 33"[int] From 0 to 2, how loud is Actor2's weapon when being used? See "GetWeaponDetectionSoundLevel", requires JIP LN NVSE Plugin[boolean] Is Actor1 sleeping? See "GetSleeping"[int] What is Actor1's level? See "GetLevel"[int] What is Actor2's level? See "GetLevel"[boolean] Has Actor2 touched any actor within the last couple seconds? See "GetHasContactType == 42" and "GetHasContactType == 43" The game also uses many game setting variables to determine detection: fSneakMaxDistance fSneakDistanceAttenuationExponent fSneakExteriorDistanceMult fDetectionSneakLightMod fSneakLightMult fSneakLightRunMult fSneakLightMoveMult fSneakPerceptionSkillMax fSneakPerceptionSkillMin fSneakSkillMult fSneakBootWeightBase fSneakBootWeightMult fSneakRunningMult iSoundLevelSilent iSoundLevelNormal iSoundLevelLoud fSneakActionMult fSneakSoundLosMult fSneakSoundsMult iSneakLevelBonus iSneakStartBonus iMediumArmorStealthPenalty iHeavyArmorStealthPenalty iSneakStartBonusLevelPenatly fSneakBaseValue NOTE: When it comes to calculating sound detection, the value might seem to be off by a lot but that is only because the game has the sounds persisting in the calculations for a lot longer than I am able to detect. For example, you shoot your gun and that gun shot will persist in my calculation for about 2 seconds while it will persist in the actual game calculation for about 5 seconds, thus creating 3 seconds of what looks to be a false calculation. NOTE: I seemed to have forgotten about the silent running perk so keep that in mind. Edited October 6, 2021 by IntenseMute Link to comment Share on other sites More sharing options...
Recommended Posts