Jump to content

Calculating detection value


IntenseMute

Recommended Posts

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 by IntenseMute
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...