Jump to content

Hit Location-based DT


schlangster

Recommended Posts

OK, before further cluttering our release thread in the beth forums with this, I might as well make use of this forum to get some fresh ideas :)

 

When tweaking around values for body part multipliers and DT bleedthrough i once again thought how annoying it is that armor DT counts for the head as well, even if its completely unprotected. So I thought why not give it a try to implement something that adds some extra damage for headshots if the head is unprotected, though I'm surely not the first to attempt this.

 

First approach:

Perk that does DT reduction if getHitLocation == 1, plus some more conditions to check for the absence of helmets etc. That would've been easy, but getHitLocation always returns -1 for this entry point.

 

Second approach:

Ammo effect script. getHitLocation works here, but the damage is already applied. So it would be possible to apply some fixed extra damage at least. Problem: Requires modification of every ammo record. I tried doing it dynamically with something like

ref ammoScript
set ammoScript to getScript DummyAmmo
setScript ammoScript AmmoX 

but setScript didn't seem to work.

 

Third approach:

A challenge, with a reward script that runs after every headshot. GetCombatTarget could be used to get the tartget. Problem here is that a completion message is displayed after every shot. The message box can be temporarily disabled with setUIFloat, but since mutliple messages are queued you never really know when and how long it will be displayed.

 

Talkie proposed polling the head condition, which works fine but as long as its >0, but then it can't detect changes anymore.

 

So at this point, it seemed to me like there's no "simple" solution :( I accepted that any solution would probably not be feasible, at least some proof-of-concept would be nice.

 

Approach 2 seemed worth pursuing since it at least allowed the detection of headshots without any negative side effects. But if every ammo entry has to be changed, then it better something more than just a static damage bonus.

 

An effect script running on an actor could monitor its health, but it can't use getHitLocation. An ammo effect script has getHitlocation but no way to get the damage. That's why both are necessary: An effect script is added to nearby actors, which waits until a dummy effect is added by the ammo effect. This effect is active for one frame, just at the moment when the damage is done.

The effect script then reverses the DT reductions to get original damage, and reduces enough health so it's as if there was no DT.

 

Here's the script

scn PNxRHeadshotMonitorEffectScript

float lastHealth
float damage
float dam1
float dam2
ref helmet

;---------------------------------------
Begin ScriptEffectUpdate

if getNumericGameSetting fMinDamMultiplier == 0 || getDead == 1
return
endif

; Return unless headshot
if isSpellTarget PNxRHeadshotSpell == 0
set lastHealth to getAV Health
return
endif

printToConsole "Headshot!"

; Return unless DT > 0
if getAV DamageThreshold <= 0
set lastHealth to getAV Health
return
endif

; Return unless head is unprotected
set helmet to getEquippedObject 9
if helmet != 0
if getArmorDT helmet > 0
	set lastHealth to getAV Health
	return
endif
endif


; Apply extra damage if head is unprotected
set damage to lastHealth - getAV Health

if damage > 0
printToConsole "Real damage %.3f" damage

; Damage: 16, fMinDam 0.25
; 16 * 0.25 = 4    >   16 - 15 = 1
; 4 / 0.25 = 16   <  4 + 15 = 19

; Damage: 24, fMinDam 0.25
; 24 * 0.25 = 6    <   24 - 15 = 9
; 9 / 0.25 = 36   >  9 + 15 = 24

set damage to damage / PNxRHeadshotDamMult
set dam1 to damage / getNumericGameSetting fMinDamMultiplier
set dam2 to damage + getAV DamageThreshold

PrintToConsole "Min Dmg: %.3f vs Dmg: %.3f" dam1, dam2
if dam1 < dam2
	PrintToConsole "Original damage was %.0f" dam1
	set damage to (dam1 - damage) * PNxRHeadshotDamMult
else
	PrintToConsole "Original damage was %.0f" dam2
	set damage to (dam2 - damage) * PNxRHeadshotDamMult
endif

PrintToConsole "Extra damage: %.3f" damage
damageAV Health damage

endif
endif

set lastHealth to getAV Health

End

 

PNxRHeadshotDamMult is the body part multiplier for headshots.

 

The ammo effect:

scn PNxRHeadshotAmmoEffectScript

Begin ScriptEffectStart

if getHitLocation == 1
castImmediateOnSelf PNxRHeadshotSpell
endif

End

 

And this worked really nicely, the real damage was accurately detected even with fMinDamMultiplier 0.01.

So I thought what the hell, I'll just attach the ammo effect script to each ammo record. But when testing FPS suddenly dropped to 1 or so... seems like these ammo effect scripts run all the time, like an object script (i was carrying lots of ammo), even though they have no active block, the fact that they are processed is enough to kill the game.

 

So the reason why I have written all of this :) : I'm looking for another way to tell the PNxRHeadshotMonitorEffectScript that a headshot happened, since the ammo effects can't be used. Any ideas? Basically any situation where getHitLocation returns something meaningful would be helpful. Dialogue combat topics didn't seem to work, maybe checking for hit animations?

Hopefully someone has an idea cause I'd really like this to work..

Edited by schlangster
Link to comment
Share on other sites

You could attach the script to the player entry, and use the "Begin OnHit" to detect when the player been shot/hit

 

It would be something like this I think:

scn PNxRHeadshotAmmoEffectScript

Begin OnHit

       if getHitLocation == 1
               castImmediateOnSelf PNxRHeadshotSpell
       endif

End

Edited by Alexx378
Link to comment
Share on other sites

Well, I think I got it working now. Since everything else failed, I was settling for the head condition polling in the same effect script that already does the health polling, but keeping the actors head condition above 0 all the time so it would still register changes, even if that means its no longer possible to cripple an enemies head.. you can't have everything :). While doing this I tried if it would be somehow possible to "break" something with setAV PerceptionCondition and weird values. After a bit of brute forcing, this seems to do the trick:

set headCond to getAV PerceptionCondition

; Magic
if headCond == 0 && lastHeadCond > 0
setAV PerceptionCondition -10
set headCond to -10
endif

if headCond > 0
if lastHeadCond <= headCond
	set lastHeadCond to headCond
	set lastHealth to getAV Health
	return
endif
elseif headCond == lastHeadCond
set lastHeadCond to headCond
set lastHealth to getAV Health
return
endif

set lastHeadCond to headCond

printToConsole "Headshot!"
...

You can cripple the head only once, yet afterwards it still registers headshots. Doesn't work for the player though.

Edited by schlangster
Link to comment
Share on other sites

  • Recently Browsing   0 members

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