Scriptname zBloodNPC extends activemagiceffect  

VisualEffect property BloodVisual auto

Keyword property DecapKeyword auto
Keyword property WeapTypeBattleaxe auto
Keyword property WeapTypeBow auto
Keyword property WeapTypeDagger auto
Keyword property WeapTypeGreatsword auto
Keyword property WeapTypeMace auto
Keyword property WeapTypeSword auto
Keyword property WeapTypeWarAxe auto
Keyword property WeapTypeWarHammer auto
Keyword property ActorTypeAnimal auto
Keyword property ActorTypeGiant auto

Race property AlduinRace auto
Race property DragonRace auto
Race property WerewolfBeastRace auto

ImpactDataSet Property BloodFX01 auto
ImpactDataSet Property BloodFX02 auto
ImpactDataSet Property BloodFX03 auto
ImpactDataSet Property BloodFX04 auto
ImpactDataSet Property BigBloodFX01 auto
ImpactDataSet Property SmallBloodFX01 auto
ImpactDataSet Property SmallBloodFX02 auto
ImpactDataSet Property SmallBloodFX03 auto
ImpactDataSet Property SmallBloodFX04 auto
ImpactDataSet Property BloodFXPool01 auto
ImpactDataSet Property BloodFXPool02 auto
ImpactDataSet Property BloodFXPool03 auto
ImpactDataSet Property BloodFXPool04 auto
ImpactDataSet Property BloodFXDrop01 auto
ImpactDataSet Property BloodFXDrop02 auto
ImpactDataSet Property BloodFXDrop03 auto

Actor target
Actor caster
Race AggressorRace
float healthcurrent
float mindamage
float randomLocationX = 0.0
float randomLocationY = 0.0
bool bKillmoved
bool isValidHit = false
string asNodeName = "NPC Spine2 [Spn2]"
int picktexture

EVENT OnEffectStart(Actor akTarget, Actor akCaster)
	target = akTarget
	caster = akCaster
	healthcurrent = target.GetAV("Health") as float
	mindamage = 0.15 * target.GetBaseAV("Health")   ;must do at least 15% damage
EndEvent

EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
bool bBleedingCooldown = false
float damage
float health
int extrabloodchance

   AggressorRace = (akAggressor as Actor).GetRace()
		;Debug.Notification("Outside Hit detected")
   
   ;;; The conditional check is now scripted so bleeding effects can be used out of a killmove without bugs (magic causing bleeding and so)
   if (akSource.HasKeyword(WeapTypeBattleaxe) || akSource.HasKeyword(WeapTypeBow) || akSource.HasKeyword(WeapTypeDagger) || akSource.HasKeyword(WeapTypeGreatsword) || akSource.HasKeyword(WeapTypeMace) || akSource.HasKeyword(WeapTypeSword) || akSource.HasKeyword(WeapTypeWarAxe) || akSource.HasKeyword(WeapTypeWarHammer)) || (AggressorRace == DragonRace || AggressorRace == AlduinRace || AggressorRace == WerewolfBeastRace || akAggressor.HasKeyword(ActorTypeAnimal) || akAggressor.HasKeyword(ActorTypeGiant))
		isValidHit = true
   
	;;; Apply the bleeding on different nodes if the victim has them
	if target.HasNode("NPC Spine2 [Spn2]")			;; humanoids
		asNodeName = "NPC Spine2 [Spn2]"
	elseif target.HasNode("NPC Spine2")					;; Falmer
		asNodeName = "NPC Spine2"
	elseif target.HasNode("NPC Ribcage")					;; Bear
		asNodeName = "NPC Ribcage"
	elseif target.HasNode("Canine_Ribcage")				;; Dog, wolf
		asNodeName = "Canine_Ribcage"
	elseif target.HasNode("Sabrecat_Ribcage[Spn4]")	;; Sabrecat
		asNodeName = "Sabrecat_Ribcage[Spn4]"
	elseif target.HasNode("[body]")						;; Spider
		asNodeName = "[body]"
	else													;; Just in case, default
		asNodeName = "NPC Spine2 [Spn2]"
	endif
   
	extrabloodchance = Utility.RandomInt(1, 3)
	health = target.GetAVPercentage("Health")
	damage =  healthcurrent - target.GetAV("Health") as float
			
	if abHitBlocked == false && bBleedingCooldown == false
		bBleedingCooldown = true
				
		; extra blood for low health
		if (health <= 0.4) && (health >= 0.1) && (extrabloodchance == 1) && bKillmoved == false
			randomHitTextureRandomLocationHIT()
		EndIf
		
		if damage > mindamage
	
			if akAggressor == Game.GetPlayer()
				randomHitTexture()			
			
			elseif extrabloodchance <= 2
				randomHitTexture()	
				
			endif

		else
			randomHitTextureSmall()
			
		endif
				
	endif
	utility.wait(0.5)
	bBleedingCooldown = false
endif	

		healthcurrent = target.GetAV("Health") as float

		;;; the cloak spell adds the effects to player too, so they duplicate if we don't exclude him as aggressor
		;;; I think it's safer to use the combat hit spell for the player to play the effects, I have to test if using this method (without the perk with combat hit spell) is reliable on him.
		if target.isInKillMove()
			bKillmoved = true
			;;; Add bugfix spell to fix bug that makes npc bleed if hit by player while in killmove
			;;;BugfixSpell.Cast(target, target)
		else
			if AggressorRace != DragonRace || AggressorRace != AlduinRace		;;; dragon races are excluded because they cause the target to bleed with their breath

				bloodDrops()

			endif
		endif
		
EndEvent

EVENT OnDying(Actor akKiller)
int picktexturepool
int iBleeding
int random
float Spasm
bool bBleedingHead

	random = Utility.RandomInt(3, 5)

	if bKillmoved == true && akKiller != target    ;;; akKiller != target is a strange conditional, but it fixes the bleeding bug if killer is hit while in killmove by a npc (this is not the same as the bug if hit by player)
		while iBleeding < random
			;;; === Normal killmoves, tested and working ===
			if !target.WornHasKeyword(DecapKeyword)	
				randomHitTextureRandomLocation()
				iBleeding += 1
				;utility.wait(0.2)
			else    
				;;; === Decapitation killmoves,  tested and working ===
				;;; Increase the bleeding time
				 if bBleedingHead == false
					random = Utility.RandomInt(8, 11)
					bBleedingHead == true
				endif

				;if iBleeding < 5 ;reduced blood decal amount for npcs
					randomHitSplatterHEAD()
				;endif
				
				BloodVisual.Play(target as ObjectReference, 0.2)
				iBleeding += 1
				if iBleeding < 8
					;;; Apply a little havok impulse along the Z axis to simulate the victim having spasms
					Spasm = (target.GetMass() / Utility.randomint(8, 10))
					target.ApplyHavokImpulse(0.0, 0.0, 1.0, Spasm)
					utility.wait(1)
				else
					utility.wait(2)
				endif
			endif

		endWhile
		
		;;; === Bleeding if decapitated but not by a killmove (People decapitated by the executioner)
		elseif target.WornHasKeyword(DecapKeyword) && target != None
				random = Utility.RandomInt(12, 16)

					while iBleeding < random
						randomHitSplatterHEAD()
						BloodVisual.Play(target as ObjectReference, 0.2)
						iBleeding += 1
						if iBleeding < 8
							;;; Apply a little havok impulse along the Z axis to simulate the victim having spasms
							Spasm = (target.GetMass() / Utility.randomint(8, 10))
							target.ApplyHavokImpulse(0.0, 0.0, 1.0, Spasm)
							utility.wait(1)
						else
							utility.wait(2)
						endif
				endWhile
		endif
	
	;Blood Pooling
	if (isValidHit == true || bKillmoved == true) && target.IsDead()
		picktexturepool = Utility.RandomInt(0,3)
		iBleeding = 0
		random = Utility.RandomInt(4, 6)
			while iBleeding < random && target != None 
				utility.wait(3)
				if  picktexturepool == 0
					target.PlayImpactEffect(BloodFXPool01, asNodeName, 0, 0, -1, 512, false, true)
				
				elseif picktexturepool == 1
					target.PlayImpactEffect(BloodFXPool02, asNodeName, 0, 0, -1, 512, false, true)
				
				elseif picktexturepool == 2
					target.PlayImpactEffect(BloodFXPool03, asNodeName, 0, 0, -1, 512, false, true)
				
				elseif picktexturepool == 3
					target.PlayImpactEffect(BloodFXPool04, asNodeName, 0, 0, -1, 512, false, true)
					
				endif
				iBleeding += 1
			endWhile
	endif	
	
EndEvent

;NORMAL HIT
	FUNCTION randomHitTexture() 
		picktexture = Utility.RandomInt(0,3); pick a texture to use
		
		if picktexture == 0
			target.PlayImpactEffect(BloodFX01, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 1
			target.PlayImpactEffect(BloodFX02, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 2
			target.PlayImpactEffect(BloodFX03, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 3
			target.PlayImpactEffect(BloodFX04, asNodeName, 0, 0, -1, 512, false, true)
			return
			endif
	endFUNCTION
	
;KILLMOVES
	FUNCTION randomHitTextureRandomLocation() 
		picktexture = Utility.RandomInt(0,3); pick a texture to use
		randomLocationX = Utility.RandomFloat(-2.5, 2.5)
		randomLocationY = Utility.RandomFloat(-2.5, 2.5)	
			
		if picktexture == 0
			target.PlayImpactEffect(BloodFX01, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
			return
		
		elseif picktexture == 1
			target.PlayImpactEffect(BloodFX02, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
			return
		
		elseif picktexture == 2
			target.PlayImpactEffect(BloodFX03, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
			return
		
		elseif picktexture == 3
			target.PlayImpactEffect(BloodFX04, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
			return
		endif
	endFUNCTION
	
;SMALL HIT
	FUNCTION randomHitTextureSmall()
		picktexture = Utility.RandomInt(0,3); pick a texture to use	
		
		if picktexture == 0
			target.PlayImpactEffect(SmallBloodFX01, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 1
			target.PlayImpactEffect(SmallBloodFX02, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 2
			target.PlayImpactEffect(SmallBloodFX03, asNodeName, 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 3
			target.PlayImpactEffect(SmallBloodFX04, asNodeName, 0, 0, -1, 512, false, true)
			return
		endif
		
	endFUNCTION
	
;BLOOD DROPS
	FUNCTION bloodDrops()
		while target.IsBleedingOut() && target != None
			picktexture = Utility.RandomInt(0, 2)
			randomLocationX = Utility.RandomFloat(-0.3, 0.3)
			randomLocationY = Utility.RandomFloat(-0.3, 0.3)
				if  picktexture == 0 && target != None
					target.PlayImpactEffect(BloodFXDrop01, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
					
				elseif picktexture == 1 && target != None
					target.PlayImpactEffect(BloodFXDrop02, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)

				elseif picktexture == 2 && target != None
					target.PlayImpactEffect(BloodFXDrop03, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)

				endif	

			;target.PlayImpactEffect(BloodImpactFXSmall, asNodeName, 0, 0, 0, 512, false, true)
			utility.wait(1)				
		endwhile
	endFUNCTION
	
;HEAD DECAP
	FUNCTION randomHitSplatterHEAD() 
		picktexture = Utility.RandomInt(0,3) ;pick a texture to use
		
		if picktexture == 0
			target.PlayImpactEffect(BloodFX01, "NPC Neck [Neck]", 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 1
			target.PlayImpactEffect(BloodFX02, "NPC Neck [Neck]", 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 2
			target.PlayImpactEffect(BloodFX03, "NPC Neck [Neck]", 0, 0, -1, 512, false, true)
			return
		
		elseif picktexture == 3
			target.PlayImpactEffect(BloodFX04, "NPC Neck [Neck]", 0, 0, -1, 512, false, true)
			return
		endif
		
	endFUNCTION

;ON HIT EXTRA
	FUNCTION randomHitTextureRandomLocationHIT() 
		randomLocationX = Utility.RandomFloat(-0.3, 0.3)
		randomLocationY = Utility.RandomFloat(-0.3, 0.3)
		
			target.PlayImpactEffect(BigBloodFX01, asNodeName, randomLocationX, randomLocationY, -1, 512, false, true)
		
	endFUNCTION
