Talk:OnHit - ObjectReference

From the CreationKit Wiki
Jump to navigation Jump to search

Damage and Application[edit source]

It seems that the script runs after damage is applied. Is there no functionality in the CK right now to be able to detect the amount of damage, and manipulate it before it's applied? That would be really nice. I've been thinking of ways to achieve this. Trying to use perks with the "Mod Incoming Damage" entry point is a step in the right direction (as it manipulates damage before it's applied), but it still doesn't seem that we have access to the incoming damage to be able to store it in a variable.

The method I've had to use is to run an OnUpdate event block updating a variable with the target's health, then store the new health total in an OnHit event block, and subtract one from the other to find the "damage." But this seems so unsatisfying and imprecise, and only "manipulates" damage after it's been applied. It feels like Ghetto script. I don't like running OnUpdate blocks unless I have to.

So, the question is: Is there something I'm missing that might help? --Doulos 21:47, 6 March 2012 (EST)


Projectile[edit source]

Can anyone confirm that akProjectile is equal to None when an NPC fires an arrow at the player. I have a RefAlias on the player and the akProjectile is always None, even when the player is hit with arrows. Might have something to do with NPCs not using real ammo. --Nitor

Yes, it's the same for me. But you can also use the following to determine whether an arrow was used or not:
Event OnHit(ObjectReference Attacker, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

if((attacker as actor).getequippeditemtype(0) != 7)
  ; do something
endif

EndEvent
-- Kahmul 15:54, 11 April 2012 (EDT)

Thanks to Kahmul the following seams to work well (as akProjectile doesn't actually mean arrows)

Event OnHit(ObjectReference Attacker, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)

PlayerRef = Game.GetPlayer()
Bool boHitByMagic = FALSE  ; True if likely hit by Magic attack.
Bool boHitByMelee = FALSE  ; True if likely hit by Melee attack.
Bool boHitByRanged = FALSE ; True if likely his by Ranged attack.

IF akAggressor != PlayerRef && PlayerRef.IsInCombat() && akAggressor.IsHostileToActor(PlayerRef)
; The above is really to rule out run of the mill physical traps.

	IF ((akAggressor .GetEquippedItemType(0) == 8) || (akAggressor .GetEquippedItemType(1) == 8) \
		|| (akAggressor .GetEquippedItemType(0) == 9) || (akAggressor .GetEquippedItemType(1) == 9))  && akProjectile != None
		boHitByMagic = TRUE
	ELSEIF (akAggressor .GetEquippedItemType(0) != 7) && akProjectile == None
		boHitByMelee = TRUE
	ELSEIF (akAggressor .GetEquippedItemType(0) == 7)
		boHitByRanged = TRUE
	ENDIF
ENDIF
-- Leon Fenten 01:30, 14th May 2012

What is going on with the Example section?[edit source]

Okay, uh, I'm gonna be blunt. Most of the stuff in the "example" section makes no sense. It's essentially claiming that both of the following are true at the same time:

  • When multiple OnHit events are generated by an enchanted weapon, the akSource argument is always the weapon.
  • When multiple OnHit events are generated by an enchanted weapon, the akSource argument is only the weapon once, and the others are the enchantments... but they test as weapons, even though they're not only not weapons, but also verifiably not the actual weapon being used.

Not to mention the fact that the last example should be completely wrong: we're casting a variable to a Weapon form and then comparing it to an Enchantment form. If Papyrus variables for weapons with predefined enchantments auto-cast to those enchantments (why would they?!), then this would match all of the OnHit events for an enchanted weapon; if they don't cast like that, then it would match no events.

As is, the information given is completely contradictory to basically everything else on this wiki concerning Papyrus's type system, and contradictory to other content in this very article. I'm removing it until it can be verified and clearly and coherently explained. DavidJCobb (talk) 2021-03-03T17:45:19 (EST)

The last note you removed about the aksource thing could've been written a little better indeed, but I'm 100% sure the contributor was saying that using aksource = weapon is incorrect and will cause a compiler error as it's incorrect syntax for the condition statement and you must either cast to the type or use a comparison operation("==").--Rasikko (talk) 2021-03-04T00:08:54 (EST)

This should be correct:

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, \
  bool abBashAttack, bool abHitBlocked)
  Debug.Trace("We were hit by " + akAggressor)
EndEvent


To avoid the hits from enchantments running the code block one must compare the akSource to the actual reference that hit the actor/object. For instance, say we have a weapon with 2 enchantments called "Fire/Ice Sword." When hit with this sword the hit registers as 3 separate hits, but you have code such as:

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, \
  bool abBashAttack, bool abHitBlocked)

if(akSource as Weapon)
  Variable1 -= 100
EndEvent

This would actually subtract 300 from Variable1 since the event was called 3 times simultaneously, even though the akSource has been cast as a weapon papyrus counts the hit from the enchantments as "weapons" too so the enchantments are reference as (akSource as Weapon) as well. So the solution is to be more explicit.

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, \
  bool abBashAttack, bool abHitBlocked)

Form RightHandSword = akAggressor.GetEquippedWeapon(0); this gets the sword that the enemy had in their right hand and stores it as an object variable

if((akSource as weapon) == RightHandSword

;do code stuff

EndEvent

This will still call the event 3 times, but the code will only fire once when (akSource as weapon) == RightHandSword

  • 1st hit: Sword: (akSource as weapon) == RightHandSword - fires code
  • 2nd hit: Enchant1: (akSource as weapon) == RightHandSword - nothing happens
  • 3rd hit: Enchant2: (akSource as weapon) == RightHandSword - nothing happens

If you had the exact same script but only want the code to run when the actor/object that has the script with the OnHit Event is hit with a certain enchantment, regardless of the sword then:


Enchantment Property ''TheEnchantment'' Auto

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, \
  bool abBashAttack, bool abHitBlocked)

if((akSource as enchantment) == ''TheEnchantment''

;do code stuff

EndEvent

With this code the Actor/Object with the OnHitEvent script could be hit by 5 different weapons but the onhit event will only fire when the weapon has TheEnchantment and it will only fire once.

Sein schatten (talk) 2021-05-13T04:04:31 (EDT)