Scriptname aaaUDDragonAIScript extends activemagiceffect  

Spell property aaaUDDragonAISpell auto
Spell Property aaaUDStaggerResistSpell auto
Spell Property aaaUDHeadBroken auto
Spell Property aaaUDTailBroken auto
Spell Property AbDragonFire auto
Spell Property AbDragonFrost auto
Spell property aaaUD3ShoutSpell auto
Spell property aaaUDSwingShoutSpell auto
Spell property Meteor auto
Spell property IceMeteor auto
Spell property EnrageSpell auto
Spell property AbAlduinInvulnerability auto
Spell property aaaUDMarkedForDeathSpell auto
Spell property FireCircleSpell auto
Spell property StompExplosion auto

Ingredient property DragonClaw  auto
Ingredient property DragonBoneMeal  auto

Hazard property IceHazard auto
Activator property FXEmptyActivator auto
Activator property SteamActivator auto
Explosion property DelayBomb auto
Explosion property TailRollingExplosion auto
Explosion property RockExplosion auto
Explosion property IceFormShout auto
Explosion property ForceShout auto
Explosion property FearShout auto
ImpactDataSet property FXDragonTailstompImpactSet auto
Sound property aaaUDNPCDragonKillMove auto

GlobalVariable Property aaaUDDiminishReturns auto
GlobalVariable Property aaaUDDragonHPMult auto
ActorBase property aaaUDSpectralDragon auto

Actor selfActor
Actor player
bool bOnce = true
int DontFlyRate = 0
int EnrageCount = 0
int StaggerCount = 0
float StaggerStartTime
float preHP 
float diffHP
float HPFront
float HPBack
float HPLeft
float HPRight
float HPratio = 0.9
string Type
string Node

Event OnEffectStart(Actor akTarget, Actor akCaster)
	selfActor = akTarget
	player = Game.GetPlayer()

	if selfActor.IsDead()
		self.dispel()
	endif

	Type = DragonType()
;	debug.notification("Type:" +Type)

	selfActor.ForceAV("DamageResist", DamageResistCalc())
	selfActor.ForceAV ("health", (selfActor.GetBaseActorValue("health") * aaaUDDragonHPMult.GetValue()))

	preHP	= selfActor.getActorValue("health")
	HPFront	= selfActor.getActorValue("health") * 0.4
	HPBack	= selfActor.getActorValue("health") * 0.25
	HPLeft	= selfActor.getActorValue("health") * 0.3
	HPRight	= selfActor.getActorValue("health") * 0.3

	Regist()

EndEvent

Event OnCombatStateChanged(Actor akTarget, int aeCombatState)
	if (aeCombatState == 0)
		selfActor.removespell(aaaUDDragonAISpell)
		if DragonType() != "NoFlight"
			selfActor.SetAllowFlying(true)
		endif
	endif
EndEvent

Function Regist()

	registerForAnimationEvent(selfActor, "DragonLandEffect")
	registerForAnimationEvent(selfActor, "DragonForcefulLandEffect")
	registerForAnimationEvent(selfActor, "endGroundAttack")
	registerForAnimationEvent(selfActor, "Voice_SpellFire_Event")
	registerForAnimationEvent(selfActor, "SoundPlay.VOCShoutDragon02BRuMaar")
	registerForAnimationEvent(selfActor, "SoundPlay.VOCShoutDragon03BSlenNus")
	registerForAnimationEvent(selfActor, "SoundPlay.VOCShoutDragon01BRoDah")
	registerForAnimationEvent(selfActor, "MarkedForDeathEvent")
	registerForAnimationEvent(selfActor, "MeleeAttackEvent")
	registerForAnimationEvent(selfActor, "TailRollingEvent")
	registerForAnimationEvent(selfActor, "EnRageEvent")

;	registerForKey(208) ; down
;	registerForKey(200) ; up
Endfunction

string Function DragonType() 
	if selfActor.HasSpell(AbAlduinInvulnerability)
		return "Alduin"
	elseif !selfActor.IsAllowedToFly()
		return "NoFlight"
	elseif selfActor.HasSpell(AbDragonFire)
		return "Fire"
	elseif selfActor.HasSpell(AbDragonFrost)
		return "Frost"
	else
		return "Other"
	endif
EndFunction

float Function DamageResistCalc()
	int Level = selfActor.GetLevel()
	if Level <= 10
		return 50
	elseif Level > 10 && Level <= 20
		return 100
	elseif Level > 20 && Level <= 30
		return 140
	elseif Level > 30 && Level <= 40
		return 180
	elseif Level > 40 && Level <= 50
		return 220
	elseif Level > 50 && Level <= 62
		return 280
	elseif Level > 62
		return 320
	endif
Endfunction

Function Anim(string AnimEventName)
	Debug.SendAnimationEvent(selfActor, AnimEventName)
EndFunction

Function NodeAnim(string AnimEventName, string sNode)
	Debug.SendAnimationEvent(selfActor, AnimEventName)
	Node = sNode
EndFunction

;/ debug 
Event OnKeyDown(Int KeyCode)
if KeyCode ==208	;down

;	aaaUDSwingShoutSpell.Cast(selfActor,selfActor)
;	aaaUD3ShoutSpell.Cast(selfActor,selfActor)
;	Debug.SendAnimationEvent(selfActor, "ForceShout")
;	Debug.SendAnimationEvent(selfActor, "FearShout")
;	debug.notification("iState:" +selfActor.GetAnimationVariablebool("IsDying"))
;	summon()
;	RangedMeteor()
;	MeleeMeteor()
;	DelayBomb()
;	BleedOut()
;	NodeAnim("StampLeft", "NPC LHeel")
;	NodeAnim("StampRight", "NPC RHeel")
;	Anim("TailRolling")

elseif KeyCode == 200	;up
;	FireCircle()
;	Anim("Enrage")
;	Anim("IceFormShout")
;	Anim("MarkedForDeath")
;	SeachFrost()
;	NodeAnim("TailWhipLeft", "NPC Tail3")
;	NodeAnim("TailWhipRight", "NPC Tail3")
;	Debug.SendAnimationEvent(selfActor, "BiteRight")
endif
EndEvent
/;

Event OnAnimationEvent(objectReference deliverator, string eventName)
		if (eventName == "DragonLandEffect") || (eventName == "DragonForcefulLandEffect")
			Land()
		elseIf (eventName == "endGroundAttack")
			GroundAct()
		elseIf  (eventName == "Voice_SpellFire_Event") && !selfActor.IsFlying() && selfActor.GetAnimationVariableint("iState") != 3
			Utility.Wait(0.8)
			selfActor.SetDontMove()
			int count = 0
			While  selfActor.GetAnimationVariableBool("IsShouting") == true || count < 10
				Utility.Wait(0.5)
				count += 1
			endWhile
			selfActor.SetDontMove(false)
			GroundAct()
		elseIf eventName == "SoundPlay.VOCShoutDragon02BRuMaar"
			Shout(FearShout)
		elseIf eventName == "SoundPlay.VOCShoutDragon03BSlenNus"
			Shout(IceFormShout)
		elseIf eventName == "SoundPlay.VOCShoutDragon01BRoDah"
			Shout(ForceShout)
		elseIf eventName == "MarkedForDeathEvent"
			MarkedForDeath()
		elseIf eventName == "MeleeAttackEvent"
			MeleeAttack()
		elseIf eventName == "TailRollingEvent"
			TailRolling()
		elseIf eventName == "EnRageEvent"
			Shout(FearShout)
		endif

EndEvent


Function Land()
	selfActor.SetAllowFlying(false)
;	debug.notification("land")
	if bOnce
		Utility.Wait(2.0)
		Anim("FearShout")
		bOnce = false
	endif
EndFunction

Function GroundAct()
	if !selfActor.IsFlying() && !selfActor.IsInKillMove()
		AddBehavior()
		int randomFly = Utility.RandomInt(0, 100)
		if (randomFly <= 60 + DontFlyRate)
			selfActor.SetAllowFlying(false)
		else
			selfActor.SetAllowFlying(true)
		endif
	endif
EndFunction 


Function AddBehavior()
	Actor Target = selfActor.GetCombatTarget()
	float distance = Target.GetDistance(selfActor)
	float headingAngle = selfActor.GetHeadingAngle(Target)
	int i = Utility.RandomInt(0, 100)

	if i <= 5
		if Type == "Frost"
			Anim("IceFormShout")
		else
			Anim("ForceShout")
		endif
	elseif i <= 15
		aaaUDSwingShoutSpell.Cast(selfActor,selfActor)
	elseif i <=20 && Type == "Alduin"
		Summon()
	elseif distance < 550.0
		if i <= 25 
			Anim("TailRolling")
		elseif i <=35 
			MeleeMeteor()
		elseif i <= 40 && selfActor.GetLevel() >= 40
			Anim("MarkedForDeath")
		elseif i <=45 && Type == "Alduin"
			FireCircle()
		elseif Math.abs(headingAngle) < 36.0
			Anim("BiteRight")
		elseif headingAngle > 90.0 && headingAngle < 130.0
			NodeAnim("StampRight", "NPC RHeel")
		elseif headingAngle < -90.0 && headingAngle > -130.0
			NodeAnim("StampLeft", "NPC LHeel")
		elseif headingAngle  > 129.0 && headingAngle < 180.0 ;rightback
			NodeAnim("TailWhipRight", "NPC Tail3")
		elseif headingAngle < -129.0 && headingAngle > -180.0 ;leftback
			NodeAnim("TailWhipLeft", "NPC Tail3")
		endif
	elseif distance > 620.0 && Math.abs(headingAngle) < 45.0
		if i <= 35
			aaaUD3ShoutSpell.Cast(selfActor,selfActor)
		elseif i <=55
			RangedMeteor()
		elseif i <= 75
			if Type == "Frost"
				SeachFrost()
			else
				DelayBomb()
			endif
		endif
	endif
EndFunction


Function TailRolling()
	ObjectReference Box = selfActor.Placeatme(FXEmptyActivator)
	Box.MovetoNode(selfActor, "NPC COM")
	Box.Placeatme(TailRollingExplosion)
	Box.Delete()
EndFunction


Function MeleeAttack()
	ObjectReference Box = selfActor.Placeatme(FXEmptyActivator)
	Box.MovetoNode(selfActor, Node)
	StompExplosion.RemoteCast(Box,selfActor)
	selfActor.PlayImpactEffect(FXDragonTailstompImpactSet, Node, 0, 0, -1, 512)
	Box.Delete()
EndFunction


Function Shout(explosion shoutexp)
	Utility.Wait(0.1)
	ObjectReference Box = selfActor.Placeatme(FXEmptyActivator)
	Box.MovetoNode(selfActor, "NPC Head MagicNode [Hmag]")
	Box.Placeatme(shoutexp)
	Box.Delete()
EndFunction


Function DelayBomb()
		aaaUDNPCDragonKillMove.Play(selfActor)
		Debug.SendAnimationEvent(selfActor,"BleedoutStartSpecial")

		Actor Target = selfActor.GetCombatTarget()
		int CountCast	= 0
		ObjectReference Box	= selfActor.Placeatme(FXEmptyActivator)
		Utility.Wait(2.0)

		While CountCast < 4
			float Degrees	= Utility.RandomInt(-5,5) * 10
			float AngleZ = Target.GetAngleZ() + Degrees
			float LocX = 180 * math.sin(AngleZ)
			float LocY = 180 * math.cos(AngleZ)
			Box.MoveTo(Target, LocX, LocY, 20)
			ObjectReference Steam = Box.PlaceAtMe(SteamActivator)
			Box.PlaceAtMe(RockExplosion)
			Utility.Wait(1.5)
			Box.PlaceAtMe(DelayBomb)
			Steam.Delete()
			CountCast	+= 1
			Utility.Wait(0.05)
		EndWhile

		Box.Delete()
		Debug.SendAnimationEvent(selfActor,"BleedOutStop")

EndFunction

Function SeachFrost()
	aaaUDNPCDragonKillMove.Play(selfActor)
	Debug.SendAnimationEvent(selfActor,"BleedoutStartSpecial")

	Actor Target = selfActor.GetCombatTarget()
	int CountCast	= 0
	float Distance	= 150
	float TargetDistance = selfActor.GetDistance(Target)
	Int NumTotal = math.Floor(TargetDistance / Distance) + 1
	ObjectReference Box	= selfActor.placeAtMe(FXEmptyActivator)
	Box.MoveTo(selfActor, 200 * math.sin(selfActor.GetAngleZ()), 200 * math.cos(selfActor.GetAngleZ()), 0)

	While CountCast < NumTotal 
		Utility.Wait(0.05)
		float Degrees 		= Box.GetHeadingAngle(Target)
		Box.SetAngle(Box.GetAngleX(), Box.GetAngleY(), Box.GetAngleZ() + Degrees)
		float AngleZ			= Box.GetAngleZ()
		float LocX			= 200 * math.sin(AngleZ)
		float LocY			= 200 * math.cos(AngleZ)
		float z = Target.Z - Box.Z
		Box.MoveTo(Box, LocX, LocY, z)
		Box.PlaceAtMe(IceHazard)
		CountCast	+= 1
		Utility.Wait(0.6)
	EndWhile
	Box.Delete()
	Debug.SendAnimationEvent(selfActor,"BleedOutStop")
EndFunction


Function RangedMeteor()
	Debug.SendAnimationEvent(selfActor,"BleedoutStartSpecial")

	Spell MeteorSpell
	if Type == "frost"
		MeteorSpell = IceMeteor
	else
		MeteorSpell = Meteor
	endif

	Actor Target = selfActor.GetCombatTarget()
	int CountCast	= 0
	ObjectReference Box	= selfActor.Placeatme(FXEmptyActivator)
	Box.MoveTo(selfActor, 0, 0, 1500)
	Utility.Wait(1.0)

	While CountCast < 4
		MeteorSpell.RemoteCast(Box, selfActor, Target)
		Utility.Wait(1.0)
		CountCast	+= 1
	EndWhile

	Box.Delete()
	Debug.SendAnimationEvent(selfActor,"BleedOutStop")
EndFunction


Function MeleeMeteor()
	Debug.SendAnimationEvent(selfActor,"BleedoutStartSpecial")

	Spell MeteorSpell
	if Type == "frost"
		MeteorSpell = IceMeteor
	else
		MeteorSpell = Meteor
	endif

	int CountCast	= 0
	ObjectReference Box	= selfActor.Placeatme(FXEmptyActivator)
	ObjectReference TargetBox	= selfActor.Placeatme(FXEmptyActivator)
	float Degrees = -45
	Box.MoveTo(selfActor, 0, 0, 1500)
	Utility.Wait(1.0)

	While CountCast < 4
		float AngleZ = selfActor.GetAngleZ() + Degrees
		float LocX = 500 * math.sin(AngleZ)
		float LocY = 500 * math.cos(AngleZ)
		TargetBox.MoveTo(selfActor, LocX, LocY, 0)
		MeteorSpell.RemoteCast(Box, selfActor, TargetBox)
		Utility.Wait(1.0)
		Degrees += 90
		CountCast	+= 1
	EndWhile

	TargetBox.Delete()
	Box.Delete()
	Debug.SendAnimationEvent(selfActor,"BleedOutStop")
EndFunction


Function MarkedForDeath()
	ObjectReference Box = selfActor.Placeatme(FXEmptyActivator)
	Box.MovetoNode(selfActor, "NPC Head MagicNode [Hmag]")
	aaaUDMarkedForDeathSpell.RemoteCast(box, selfActor, box)
	box.delete()
EndFunction

;=====================================
; Alduin Only
;=====================================
Function Summon()
	selfActor.placeatme(aaaUDSpectralDragon)
	selfActor.placeatme(aaaUDSpectralDragon)
EndFunction

Function FireCircle()
	Debug.SendAnimationEvent(selfActor,"BleedoutStartSpecial")
	int CountCast = 0
	float Degrees = 0
	ObjectReference Box	= selfActor.Placeatme(FXEmptyActivator)
	ObjectReference TargetBox	= selfActor.Placeatme(FXEmptyActivator)
	Utility.Wait(1.0)
	float height = player.z - box.z +80
	float Distance = selfActor.getDistance(player)

	While CountCast < 8
		float AngleZ = selfActor.GetAngleZ() + Degrees
		float LocX = 500 * math.sin(AngleZ)
		float LocY = 500 * math.cos(AngleZ)
		float TLocX = Distance * math.sin(AngleZ)
		float TLocY = Distance  * math.cos(AngleZ)
		Box.MoveTo(selfActor, LocX, LocY, 80)
		TargetBox.MoveTo(selfActor, TLocX, TLocY, height)
		FireCircleSpell.RemoteCast(Box, selfActor, TargetBox)
		Utility.Wait(0.2)
		Degrees += 45
		CountCast	+= 1
	EndWhile

	TargetBox.Delete()
	Box.Delete()
	Debug.SendAnimationEvent(selfActor,"BleedOutStop")
EndFunction

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

;	Regist()		;debug

	diffHP = preHP - (selfActor.getActorValue("health"))
	float hitAngle = selfActor.GetHeadingAngle(akAggressor)

	if hitAngle >= -45 && hitAngle <= 45 && HPfront >= 0.0
		HPfront -= diffHP
		if  HPfront <= 0.0
			;Reduce Damage Resist
			aaaUDHeadBroken.Cast(selfActor)
			GotoState("BleedOut")
		endif

	elseif hitAngle >= 135 &&  hitAngle <= -135 && HPback >= 0.0
		HPback -= diffHP
		if HPback <= 0.0
			; Reduce Attack Damage
			aaaUDHeadBroken.Cast(selfActor)
			selfActor.AddItem(DragonBoneMeal, 1, true)
			GotoState("BleedOut")
		endif

	elseif hitAngle < -45 && hitAngle > -135 && HPleft >= 0.0
		HPleft -= diffHP
		if HPleft <= 0.0
			DontFlyRate += 15
			selfActor.AddItem(DragonClaw, 1, true)
			GotoState("BleedOut")
		endif
	elseif hitAngle > 45 && hitAngle < 135 && HPright >= 0.0
		HPright -= diffHP
		if HPright <= 0.0
			DontFlyRate += 15
			selfActor.AddItem(DragonClaw, 1, true)
			GotoState("BleedOut")
		endif
	endif
	preHP = selfActor.getActorValue("health")

	if selfActor.GetActorValuePercentage("health") <= HPratio && HPratio > 0.0
		Enrage(3)
		HPratio -=0.1
	endif

	if selfActor.GetAnimationVariableBool("IsStaggering") && StaggerCount < 5 && !selfActor.IsFlying()
		if aaaUDDiminishReturns.GetValueInt() == 1
			GotoState("StaggerCountState")
			StaggerStop()
			if StaggerCount == 4
				selfActor.AddSpell(aaaUDStaggerResistSpell)
			endif
		else
			Enrage(1)
		endif
	endif
EndEvent

Function Enrage(int Count)
	EnrageCount += Count
	if EnrageCount >= 9 && !selfActor.IsFlying()
		GotoState("Enrage")
	endif
EndFunction

Function StaggerStop()
	float fTime = 2.1 - (StaggerCount/4)
	if (fTime <= 0.0)
		fTime = 0.05
	endif
	Utility.Wait(fTime)
	debug.SendAnimationEvent(selfActor,"staggerStop")
EndFunction

Event OnUpdate()
;	debug.notification("Reset Resist stagger")
	StaggerCount = 0
	selfActor.RemoveSpell(aaaUDStaggerResistSpell)
EndEvent


;==================================
State BleedOut
;==================================
Event OnBeginState()
	if !selfActor.IsFlying()
		Debug.SendAnimationEvent(selfActor,"BleedoutStart")
		Utility.Wait(5.0)
		Debug.SendAnimationEvent(selfActor,"BleedOutStop")
		Enrage(1)
	endif
EndEvent

Function Enrage(int Count)
EndFunction
Function AddBehavior()
EndFunction

EndState

;==================================
State Enrage
;==================================
Event OnBeginState()
		EnrageCount = 0
		Debug.SendAnimationEvent(selfActor,"Enrage")
		selfActor.AddSpell(aaaUDStaggerResistSpell)
		EnrageSpell.Cast(selfActor)
		Utility.Wait(2.0)
		selfActor.RemoveSpell(aaaUDStaggerResistSpell)
		GotoState("")
EndEvent

Function Enrage(int Count)
EndFunction
Function AddBehavior()
EndFunction

EndState


;==================================
State StaggerCountState
;==================================
Event OnBeginState()
	if StaggerCount == 0
		RegisterForSingleUpdate(40.0)
	endif
	StaggerCount	+= 1
	Utility.Wait(0.5)
	Enrage(1)
;	debug.notification("staggercount:" + StaggerCount)
	GotoState("")
EndEvent

EndState


Event OnDeath(Actor akKiller)
	self.dispel()
EndEvent

Event OnDying(Actor akKiller)
	self.dispel()
EndEvent


Event OnEffectFinish(Actor akTarget, Actor akCaster)
	UnRegisterForUpdate()
	if Type =="NoFlight"
		selfActor.SetAllowFlying(false)
	else 
		selfActor.SetAllowFlying(true)
	endif
EndEvent

