1
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1098 lines
47 KiB

ScriptName DLC2MQ06MiraakBossBattle extends ReferenceAlias
{This is the Main Fight Control Script for the Miraak Boss fight at the end of the DLC}
;This script is a bit of a beast so I tried to break it up into many smaller functions
;In general, the ProcessOnUpdateOROnHitEvent Function is the major update loop
;There are several times where the sprint or teleport functions wait for a bool to be true
; These are set by the end of the scene they start or by the magic effect on the shout
; A timer was added as a safety measure in case something went wrong
; This was a pain to set up so tinker with it at your own peril
;The tentacle attacks that were originally part of the fight were disabled since it felt a bit too chaotic
;There are many properties like SelfActor and SelfRef, which might seem unnecessary
; This is to cut down on unneeded casting for clarity and performance
; better to cast it as an actor and store that once, then keep casting it over and over
;General Actor Properties
Quest property DLC2MQ06 Auto
Actor property SelfActor auto hidden
ObjectReference property SelfRef auto hidden
Actor property PlayerActor auto hidden
ActorBase property selfBase auto hidden
Actor property ActorDragon1 auto hidden
Actor property ActorDragon2 auto hidden
Actor property ActorDragon3 auto hidden
Faction Property DLC2TameDragonFaction auto
Actor property TameDragon auto hidden
ReferenceAlias property Dragon1 auto
ReferenceAlias property Dragon2 auto
ReferenceAlias property Dragon3 auto
ReferenceAlias property TameDragonAlias auto
;Initialization Properties
bool property scriptVariablesInitialized = false auto hidden
bool property initialized = false auto hidden
MusicType property DLC2MUSCombatBoss Auto
float property currentTime auto hidden
bool property isMounted auto hidden
int property DragonBeingRidden = 1 auto hidden
bool property DragonRiddenWasFlying auto hidden
bool property DragonRiddenIsFlying auto hidden
bool property Dragon1isFlying auto hidden
bool property Dragon2isFlying auto hidden
bool property Dragon3isFlying auto hidden
bool property Dragon1isDead = false auto hidden
bool property Dragon2isDead = false auto hidden
bool property Dragon3isDead = false auto hidden
int property playerPosition = 0 auto hidden ;Didn't end up using this
{This property tells us where the player is, generally
0 = Center
1 = 2 o'clock
2 = 3 o'clock
3 = 5 o'clock
4 = 7 o'clock
5 = 9 o'clock
6 = 11 o'clock}
;Dragon Markers
objectReference property DLC2MQ06DragonLandingMarkerFar auto
objectreference Property DLC2MQ06DragonKillLandingMarker002 auto
objectreference Property DLC2MQ06DragonKillLandingMarker003 auto
bool Property CanSprintInCombat = True auto
bool property TameDragonShouldNeverLand = True auto
bool property fireMiraakKill = false auto
{Default = true}
;--------------------------------------------------------------
;Initialization Block
;---------------------------------------
Function InitializeMiraakBattle()
if (!scriptVariablesInitialized)
; debug.Trace(self + ": INITIALIZING MIRAAK BATTLE")
InitializeScriptVariables()
EndIf
EndFunction
Function InitializeScriptVariables()
; debug.Trace(self + ": Initializing Script Vars")
SetMiraakCombatLevel()
currentTime = Utility.GetCurrentRealTime()
TentacleTimer = currentTime + TentacleTimeDelayInit
TimeToSwapCombatStyle = currentTime + MaxTimeInMagicCombatStyle
;TimeOfLastTeleport = currentTime
SelfActor = Self.GetActorRef()
SelfActor.StartDeferredKill()
selfBase = SelfActor.GetActorBase()
SelfRef = (SelfActor as objectreference)
PlayerActor = Game.GetPlayer() as Actor
ActorDragon1 = Dragon1.GetActorRef()
ActorDragon2 = Dragon2.GetActorRef()
ActorDragon3 = Dragon3.GetActorRef()
DLC2TameDragonOrbitMarker.moveto(SelfActor)
SelfBase.SetEssential(False)
SetRewardGear()
((Self as referenceAlias) as DLC2MiraakCombatMagicLevelingScript).SetMiraakCombatLevel()
scriptVariablesInitialized = True
tentacleController = (DLC2MQBossTentacleControllerRef as DLC2MQBossTentacleController)
DLC2MiraakStreakE.Play(selfActor, -1)
;sets mirakk fade speed
selfActor.SetSubGraphFloatVariable("fDampRate", fadeSpeedFast) ;sets how fast miraak fades in and out
CheckDragons()
if TameDragonShouldNeverLand
SetTameDragonCanLand(canLand = false)
endif
EndFunction
Event OnCombatStateChanged(Actor akTarget, int aeCombatState)
if (!initialized)
initialized = True
if (!scriptVariablesInitialized)
InitializeScriptVariables()
EndIf
currentTime = Utility.GetCurrentRealTime()
;TimeOfLastCombatStyleSwap = currentTime
;TimeOfLastTeleport = currentTime
; ;Debug.Trace("Start the music!")
DLC2MUSCombatBoss.Add()
GoToState("Ready")
OnUpdate()
EndIf
EndEvent
;--------------------------------------------------------------
;States Block
;--------------------------------------------------------------
;Normal Combat State
Auto State Ready
Event onBeginState()
; Debug.Trace(self + ": Starting Ready State")
EndEvent
;This is empty, but it uses the default onHit and ProcessOnUpdateOROnHitEvent
;Other states will clear these so they do not run.
EndState
;Busy State, in case needed
State Busy
Event onBeginState()
; Debug.Trace(self + ": Starting Busy State")
EndEvent
Event OnHit(ObjectReference aggressor, Form weap, Projectile proj, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
;Do Nothing
EndEvent
Function ProcessOnUpdateOROnHitEvent(ObjectReference aggressor, Form weap)
;Do Nothing
EndFunction
EndState
State Done
Event onBeginState()
; Debug.Trace(self + ": Starting Done State")
EndEvent
Event OnHit(ObjectReference aggressor, Form weap, Projectile proj, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
;Do Nothing
EndEvent
Function ProcessOnUpdateOROnHitEvent(ObjectReference aggressor, Form weap)
;Do Nothing
EndFunction
Function OnUpdate()
;Do Nothing
endFunction
EndState
State runningMiraakDeathState
Event onBeginState()
; Debug.Trace(self + ": Starting runningMiraakDeathState State")
EndEvent
Event OnHit(ObjectReference aggressor, Form weap, Projectile proj, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
;Do Nothing
EndEvent
Function ProcessOnUpdateOROnHitEvent(ObjectReference aggressor, Form weap)
;Do Nothing
EndFunction
Function OnUpdate()
if fireMiraakKill
goToState("Done")
MiraakDeath()
else
RegisterForSingleUpdate(1)
endif
endFunction
endState
;--------------------------------------------------------------
;Main Battle Loops: OnHit and OnUpdate
;---------------------------------------
;Every second, we check to see if we need to update Miraaks's state.
Function OnUpdate()
If !runningMiraakDeathEvent
ProcessOnUpdateOROnHitEvent(None, None)
RegisterForSingleUpdate(1)
EndIf
EndFunction
;On hit, check to see which state we're in and respond accordingly.
Event OnHit(ObjectReference aggressor, Form weap, Projectile proj, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
ProcessOnUpdateOROnHitEvent(aggressor, weap)
EndEvent
;*****************************************************************************;
;We have to handle both types of events in this single function to prevent interleaving errors from asynchronus events.
; This is where we kick off all the events
;*****************************************************************************;
Function ProcessOnUpdateOROnHitEvent(ObjectReference aggressor, Form weap)
if !runningMiraakDeathEvent
GoToState("Busy")
endif
float healthPercentage = SelfActor.GetAVPercentage("Health")
currentTime = Utility.GetCurrentRealTime()
isMounted = game.getPlayer().IsOnMount()
CurrentCombatStyle = DLC2MQ06MiraakCombatStyle.GetValue() as int
;If all three dragons are not dead, check dragons
if !Dragon1isDead && !Dragon2isDead && !Dragon3isDead
CheckDragons()
endif
If !scriptVariablesInitialized
;if we aren't initialized don't do anything
elseif FightIsOver
GoToState("runningMiraakDeathState")
else
if totalDragonsKilled == 0 && healthPercentage <= dragonDrainThreshold1 && !runningDragonKillEvent && !sprintBusy
runningDragonKillEvent = True
; debug.Trace(self + ": DRAGON KILL EVENT 1")
sprintBusy = True
RunDragonKillEvent()
elseif totalDragonsKilled == 1 && healthPercentage <= dragonDrainThreshold2 && !runningDragonKillEvent && !sprintBusy
runningDragonKillEvent = True
; debug.Trace(self + ": DRAGON KILL EVENT 2")
sprintBusy = True
RunDragonKillEvent()
elseif totalDragonsKilled == 2 && healthPercentage <= dragonDrainThreshold3 && !runningDragonKillEvent && !sprintBusy
runningDragonKillEvent = True
; debug.Trace(self + ": DRAGON KILL EVENT 3")
sprintBusy = True
RunDragonKillEvent()
elseif totalDragonsKilled == 3 && healthPercentage <= finalKillThreshold && !runningDragonKillEvent && !runningMiraakDeathEvent && !sprintBusy
runningMiraakDeathEvent = true
; debug.Trace(self + ": MIRAAK KILL EVENT")
sprintBusy = True
RunMiraakDeathEvent()
ElseIf CanSprintInCombat && (aggressor == Game.GetPlayer()) && currentTime > (lastSprintTime + minTimebetweenSprints) && !sprintBusy && !runningDragonKillEvent && !runningMiraakDeathEvent && healthPercentage >= minSprintHealthThreshold
; ;Debug.Trace("Miraak: Registered normal hit.")
TimerPreviousHit06 = TimerPreviousHit05
TimerPreviousHit05 = TimerPreviousHit04
TimerPreviousHit04 = TimerPreviousHit03
TimerPreviousHit03 = TimerPreviousHit02
TimerPreviousHit02 = TimerPreviousHit01
TimerPreviousHit01 = currentTime
if selfActor.getDistance(playerActor) < 1000 && (TimerPreviousHit01 - TimerPreviousHit06 < 8)
sprintBusy = True
SprintAway(pickClosest = false)
PickNewCombatStyle()
ElseIf selfActor.getDistance(playerActor) >= 1000 && (TimerPreviousHit01 - TimerPreviousHit04 < 6)
sprintBusy = True
SprintAway(pickClosest = true)
PickNewCombatStyle()
EndIf
Endif
;If (!SelfActor.IsInCombat())
; SelfActor.StartCombat(Game.GetPlayer())
;EndIf
;Make sure Miraak doesn't fall below ~50 health
;If he does he won't run his packages correctly
if !runningMiraakDeathEvent
;This should keep miraak above negative health
CheckMiraakHealthAndModIfNeeded()
endif
;Combat Style Swap
if !runningDragonKillEvent && !runningMiraakDeathEvent
if TimeToSwapCombatStyle <= currentTime && !IsMounted
; debug.Trace(self + ": Timer up - Time To Swap Combat Style")
PickNewCombatStyle()
elseif IsMounted && DragonRiddenWasFlying != DragonRiddenIsFlying
; debug.Trace(self + ": FlyingState change - Time To Swap Combat Style")
PickNewCombatStyle()
endif
endif
;Check if it is okay to do tentacle attacks
; okay = no alive dragons on the ground, and player not mounted
;We decided the tentacle attacks were too much, but they can be turned back on
;by setting the DoTentacleAttacks property to true
if DoTentacleAttacks
if Dragon1isFlying || Dragon1isDead
if Dragon2isFlying || Dragon2isDead
if Dragon3isFlying || Dragon3isDead
if !isMounted && !runningMiraakDeathEvent && !runningDragonKillEvent
;This is where we kick off tentacle attacks
if TentacleTimer <= currentTime ;&& "Player is on the ground"
; debug.Trace(self + ": Time for Tentacle Attack")
int TargetArea = utility.randomInt(-1,6)
; debug.Trace(self + ": Tentacle Target Area = " + TargetArea)
TriggerTentacleAttack(TargetArea)
TentacleTimer = currentTime + TentacleTimeDelay
endif
EndIf
EndIf
endif
endif
Endif
endif
if !runningMiraakDeathEvent && !runningDragonKillEvent
GoToState("Ready")
endif
EndFunction
Function CheckDragons()
bool TameDragonFound = false
if !Dragon1isDead
Dragon1isFlying = ActorDragon1.isFlying()
if !TameDragonFound && ActorDragon1.IsInFaction(DLC2TameDragonFaction)
TameDragon = ActorDragon1
TameDragonFound = true
EndIf
EndIf
if !Dragon2isDead
Dragon2isFlying = ActorDragon2.isFlying()
if !TameDragonFound && ActorDragon2.IsInFaction(DLC2TameDragonFaction)
TameDragon = ActorDragon2
TameDragonFound = true
EndIf
EndIf
if !Dragon3isDead
Dragon3isFlying = ActorDragon3.isFlying()
if !TameDragonFound && ActorDragon3.IsInFaction(DLC2TameDragonFaction)
TameDragon = ActorDragon3
TameDragonFound = true
EndIf
EndIf
if !TameDragonFound
TameDragon = None
DragonRiddenWasFlying = False
DragonRiddenIsFlying = False
else
DragonRiddenWasFlying = DragonRiddenIsFlying
DragonRiddenIsFlying = TameDragon.IsFlying()
endif
TameDragonAlias.ForceRefTo(TameDragon)
EndFunction
;--------------------------------------------------------------
;Dragon Kill Functions
;--------------------------------------------------------------
;Properties for Dragon Drain Events and overall combat Tracking
float property dragonDrainThreshold1 = 0.3 auto hidden
float property dragonDrainThreshold2 = 0.3 auto hidden
float property dragonDrainThreshold3 = 0.3 auto hidden
float property minSprintHealthThreshold = 0.5 auto hidden
float property finalKillThreshold = 0.1 auto hidden
int property totalDragonsKilled = 0 auto hidden
bool property runningDragonKillEvent = false auto hidden
bool property runningMiraakDeathEvent = false auto hidden
bool property FightIsOver = false auto hidden
spell property DLC2MiraakDragonKillSpell auto
Scene Property DLC2MQ06MiraakKillDragonScene Auto
ReferenceAlias Property DragonToKillAlias Auto
Actor Property DragonToKill auto hidden
spell property DLC2MiraakFakeShoutSpell auto
bool property waitingForDragonKillSceneToEnd auto hidden
bool property PreferToKillPlayerDragon = False auto
Quest Property DLC2TameDragon auto
;DLC2TameDragonScript is the script used
; We call ReleaseDragon() when we kill the tamed dragon
Function MiraakStealsSoul()
; debug.Trace(self + ": MIRAAK STEALS DRAGON SOUL")
totalDragonsKilled += 1
; update MQ06 to use in conditions
(GetOwningQuest() as DLC2MQ06Script).MiraakDragonsKilled = totalDragonsKilled
selfActor.RestoreActorValue("health", 1000)
; debug.Trace(self + ": END FIGHT DRAGONS KILLED = " + totalDragonsKilled)
endFunction
Function RunDragonKillEvent()
;int sceneWaitSafety = 0
objectReference dragonKillLandingMarker
; debug.Trace(self + ": RUNNING DRAGON KILL EVENT")
;Select which dragon we are going to kill
PickDragonToKill()
; debug.Trace(self + ": DragonToKill = " + DragonToKill)
if totalDragonsKilled == 0
dragonKillLandingMarker = DLC2MQ06DragonKillLandingMarker002
ElseIf totalDragonsKilled == 1
dragonKillLandingMarker = DLC2MQ06DragonKillLandingMarker003
Elseif totalDragonsKilled == 2
dragonKillLandingMarker = DLC2MQ06DragonLandingMarkerFar
endif
;If this is the tamed dragon and the player is not riding it, release the dragon.
if DragonToKill == TameDragon && !isMounted
(DLC2TameDragon as DLC2TameDragonScript).ReleaseDragon()
endif
; Set Dragon to Kill alias
DragonToKill.SetForcedLandingMarker(dragonKillLandingMarker)
DragonToKill.SetAllowFlying(false)
SetDragonNoLand()
;;;;;;;;!!!!
DragonToKill.StartDeferredKill()
if DragonToKill.isflying()
DragonToKill.damageAV("health", 5000)
endif
DragonToKillAlias.ForceRefTo(DragonToKill)
;Move Miraak to safe room
objectReference teleportAwayTarget = PickTeleportMarkerNearby()
SelfActor.AddSpell(DLC2MiraakEtherealFXSpell)
selfActor.SetGhost(true)
SprintToTargetAndTeleportAway(teleportAwayTarget)
EndFunction
Function SetDragonNoLand()
if !Dragon1isDead && ActorDragon1 != DragonToKill
ActorDragon1.SetAV("Variable07", 1)
ActorDragon1.EvaluatePackage()
endif
if !Dragon2isDead && ActorDragon2 != DragonToKill
ActorDragon2.SetAV("Variable07", 1)
ActorDragon2.EvaluatePackage()
endif
if !Dragon3isDead && ActorDragon3 != DragonToKill
ActorDragon3.SetAV("Variable07", 1)
ActorDragon3.EvaluatePackage()
endif
endFunction
Function SetDragonsCanLand()
if !Dragon1isDead && ActorDragon1 != TameDragon
ActorDragon1.SetAV("Variable07", 0)
ActorDragon1.EvaluatePackage()
endif
if !Dragon2isDead && ActorDragon1 != TameDragon
ActorDragon2.SetAV("Variable07", 0)
ActorDragon2.EvaluatePackage()
endif
if !Dragon3isDead && ActorDragon1 != TameDragon
ActorDragon3.SetAV("Variable07", 0)
ActorDragon3.EvaluatePackage()
endif
endFunction
bool TameDragonCanLandCurrently
Function SetTameDragonCanLand(bool canLand = true)
TameDragonCanLandCurrently = canLand
if !TameDragon.isDead()
if canLand
ActorDragon1.SetAV("Variable07", 0)
else
ActorDragon1.SetAV("Variable07", 1)
endif
ActorDragon1.EvaluatePackage()
EndIf
endFunction
Actor Function PickDragonToKill()
DragonToKill = NONE
if PreferToKillPlayerDragon
;If we prefer to kill the player's dragon...
DragonToKill = TameDragon
elseif totalDragonsKilled < 2
;Pick a dragon that is not the player's tamed dragon
if !Dragon1isDead && ActorDragon1 != TameDragon
DragonToKill = ActorDragon1
elseif !Dragon2isDead && ActorDragon2 != TameDragon
DragonToKill = ActorDragon2
elseif !Dragon3isDead && ActorDragon3 != TameDragon
DragonToKill = ActorDragon3
EndIf
else ;There is only one dragon left, pick which ever it is
if !Dragon1isDead ;&& ActorDragon1 != TameDragon
DragonToKill = ActorDragon1
elseif !Dragon2isDead ;&& ActorDragon2 != TameDragon
DragonToKill = ActorDragon2
elseif !Dragon3isDead ;&& ActorDragon3 != TameDragon
DragonToKill = ActorDragon3
EndIf
endif
endFunction
Function DragonKillSceneEnded()
waitingForDragonKillSceneToEnd = False
; debug.Trace(self + ": Dragon Kill Scene has ended")
if !DragonToKill.isDead()
DragonToKill.EndDeferredKill()
DragonToKill.damageAV("health", 10000)
endif
self.getActorRef().RemoveSpell(DLC2MiraakFakeShoutSpell)
;while !DragonToKill.isDead()
; utility.wait(2.0)
;endwhile
while selfActor.GetAVPercentage("health") < 0.9
utility.wait(0.5)
endwhile
;selfBase.SetEssential(True)
selfActor.SetGhost(False)
SelfActor.RemoveSpell(DLC2MiraakEtherealFXSpell)
SetDragonsCanLand()
runningDragonKillEvent = false
GoToState("Ready")
endFunction
;This function tracks with dragons have already been killed
Function TrackDragonDeath(int DragonNumber)
; Debug.trace(Self + "TrackDragonDeath >> DragonKilled = " + DragonNumber)
if DragonNumber == 1
Dragon1isDead = True
if DragonToKill == ActorDragon1 && waitingForDragonKillSceneToEnd
DragonKillSceneEnded()
EndIf
elseif DragonNumber == 2
Dragon2isDead = True
if DragonToKill == ActorDragon2 && waitingForDragonKillSceneToEnd
DragonKillSceneEnded()
EndIf
elseif DragonNumber == 3
Dragon3isDead = True
if DragonToKill == ActorDragon3 && waitingForDragonKillSceneToEnd
DragonKillSceneEnded()
EndIf
endif
endFunction
;--------------------------------------------------------------
;Miraak Kill Functions
;--------------------------------------------------------------
;MiraakDeathSequence Properties
VisualEffect Property DragonAbsorbEffect Auto
VisualEffect Property DragonAbsorbManEffect Auto
sound property NPCDragonDeathSequenceWind auto
sound property NPCDragonDeathSequenceExplosion auto
EffectShader Property DragonPowerAbsorbFXS Auto
Spell Property DLC2KillMiraakSpell auto
GlobalVariable Property DLC2SoulStealCount Auto
objectReference property MQ06MiraakDeathMarker auto
idle property IdleDLC02MiraakDeathFinish auto
Armor Property DLC2MiraakSkeleton Auto ; miraaks skeleton for death fx
ObjectReference property DLC2MQ06CenterPoolRef auto
ObjectReference property DLC2MQ06CenterPoolFakeRef auto
VisualEffect Property DLC2MiraakAbsorbManE Auto ;..autofills
VisualEffect Property DLC2MiraakAbsorbE Auto ;...autofills
EffectShader Property DLC2MiraakBitsFXS Auto
EffectShader Property DLC2MiraakBitsLite2FXS Auto
EffectShader Property DLC2MiraakSmokeFXS Auto
EffectShader Property DLC2MiraakMagicFXS Auto
Armor Property DLC2MiraakSkinHider auto
Sound Property QSTMiraakDeathBurnMarker auto
Function RunMiraakDeathEvent()
;runningMiraakDeathEvent == True
; Debug.Trace(self + ": RunMiraakDeathEvent")
GoToState("runningMiraakDeathState")
;Enable the fake water plane in the center and disable the real one
;Thjs is necessary for Miraak to be able to enter the furniture while under the platform
;DLC2MQ06CenterPoolFakeRef.enable(abFadeIn = false)
;DLC2MQ06CenterPoolRef.disable(abFadeout = True)
objectReference teleportAwayTarget = PickTeleportMarkerNearby()
SelfActor.AddSpell(DLC2MiraakEtherealFXSpell)
selfActor.SetGhost(true)
SprintToTargetAndTeleportAway(teleportAwayTarget)
endFunction
Event MiraakDeath()
; Debug.Trace(self + ": MiraakDeath")
; This is the bit that plays the absorb stuff, needed to move it up for Miraak
;display dragon absorb effect art. One part on dragon one part on player.
;mirak fades down
DLC2MiraakBitsLite2FXS.Play(selfActor)
utility.wait(1)
selfActor.playSubgraphAnimation("SkinFadeOutLong")
QSTMiraakDeathBurnMarker.Play(SelfActor)
DLC2MiraakBitsFXS.Play(selfActor)
utility.wait(0.1)
selfActor.playSubgraphAnimation("stage2")
utility.wait(3)
DLC2MiraakMagicFXS.Play(selfActor)
DLC2MiraakMagicFXS.Stop(selfActor)
utility.wait(3)
selfActor.Playidle(IdleDLC02MiraakDeathFinish)
DLC2MiraakBitsLite2FXS.Stop(selfActor)
DLC2MiraakBitsFXS.Stop(selfActor)
DragonAbsorbEffect.Play(SelfActor, 8, PlayerActor) ;***DLC2: CHANGED FROM GetPlayer() to AbsorbActor
;; dragonRef.placeAtME(MAGDragonPowerAbsorbExplosion)
DragonAbsorbManEffect.Play(PlayerActor, 8, SelfActor) ;***DLC2: CHANGED FROM GetPlayer() to AbsorbActor
NPCDragonDeathSequenceWind.play(SelfActor)
NPCDragonDeathSequenceExplosion.play(SelfActor)
utility.wait(1.0)
;;;;;;;;;;;;;Start of what actually kills Miraak;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;The Combat Spell Apllied here ends the Deferred Kill
selfActor.SetGhost(false)
;equip the skin hider so we don't see bare hands & feet
SelfActor.Equipitem(DLC2MiraakSkinHider)
;This is the spell that actually KILLS Miraak
PlayerActor.doCombatSpellApply(DLC2KillMiraakSpell, selfActor)
;Tell the Tentacle furniture to finish playing and retract
MQ06MiraakDeathMarker.PlayAnimation("TPlay02")
; Sounds for when the wispy particles being to fly at the player.
;;;;;;;;;THis is the end of the actual kill stuff
utility.wait(10)
DLC2MiraakSmokeFXS.Play(selfActor)
utility.wait(3)
DLC2MiraakSmokeFXS.Stop(selfActor)
utility.wait(2)
selfActor.playSubgraphAnimation("stage3")
;utility.wait(3.0)
DLC2MUSCombatBoss.Remove()
;Make it rain!!! (souls)
PlayerActor.ModActorValue("DragonSouls", 3 + DLC2SoulStealCount.GetValueInt() + totalDragonsKilled)
DragonPowerAbsorbFXS.Stop(PlayerActor) ;***DLC2: CHANGED FROM GetPlayer() to AbsorbActor
endEvent
;--------------------------------------------------------------
;Fight Utility Functions
;---------------------------------------
;;;;;;;;;;;;;;;;CombatStyle Functions;;;;;;;;;;;;;;;;;;;;;
;Combat Style Properties
weapon property MiraakSword auto hidden
;weapon property DLC2MiraakApocryphaSword auto
weapon property MiraakStaff auto hidden
Spell Property DLC2LightningStormRightHand auto
objectreference property Sword1 auto hidden
objectreference property Staff auto hidden
objectreference property DLC2TameDragonOrbitMarker auto
float TimeToSwapCombatStyle = 0.0
float MaxTimeInMagicCombatStyle = 30.0
float MaxTimeInStaffCombatStyle = 10.0
float MaxTimeInMeleeCombatStyle = 30.0
GlobalVariable property DLC2MQ06MiraakCombatStyle auto
{This variable controls which combat style Miraak is using.
This is set via combat override Package.
It also is used to adjust his spells and equipment when changing combat style.
0 = Staff
1 = Magic (noStaff)
2 = Melee
3 = AntiAir (Kill Players flying Dragon)}
int property CurrentCombatStyle auto hidden
Function PickNewCombatStyle()
; debug.Trace(self + ": Running SwapMiraakCombatStyle")
CurrentCombatStyle = DLC2MQ06MiraakCombatStyle.GetValue() as int
int NewCombatStyle = CurrentCombatStyle
if isMounted && TameDragon && DragonRiddenIsFlying
ChangeMiraakCombatStyle(3);Use AntiAir
else
;Ensure we are using a new combat style
While NewCombatStyle == CurrentCombatStyle
NewCombatStyle = utility.RandomInt(0,2)
endWhile
ChangeMiraakCombatStyle(NewCombatStyle)
endif
endFunction
Function ChangeMiraakCombatStyle(int NewCombatStyle = 1)
; debug.Trace(self + ": Running ChangeMiraakCombatStyle NewCombatStyle = " + NewCombatStyle)
if NewCombatStyle == 0 ;Staff
;Set the global that changes his combat override packages
DLC2MQ06MiraakCombatStyle.SetValue(0)
;Remove Spells & Equipment
if Sword1
selfActor.removeItem(sword1)
SelfActor.UnequipItem(sword1)
endif
SelfActor.RemoveSpell(DLC2LightningStormRightHand)
SelfActor.UnEquipSpell(DLC2LightningStormRightHand, 1)
;Add Spells & Equipment
Staff = SelfActor.EquipItem(MiraakStaff)
;Reset the combat Timer
TimeToSwapCombatStyle = currentTime + MaxTimeInStaffCombatStyle
elseif NewCombatStyle == 1 ;Magic (NoStaff)
;Set the global that changes his combat override packages
DLC2MQ06MiraakCombatStyle.SetValue(1)
;Remove Spells & Equipment
if Sword1
SelfActor.UnequipItem(sword1)
selfActor.removeItem(sword1)
endif
if Staff
SelfActor.UnequipItem(Staff)
selfActor.removeItem(Staff)
endif
SelfActor.RemoveSpell(DLC2LightningStormRightHand)
SelfActor.UnEquipSpell(DLC2LightningStormRightHand, 1)
;Add Spells & Equipment
;Reset the combat Timer
TimeToSwapCombatStyle = currentTime + MaxTimeInMeleeCombatStyle
elseif NewCombatStyle == 2 ;Melee
;Set the global that changes his combat override packages
DLC2MQ06MiraakCombatStyle.SetValue(2)
;Remove Spells & Equipment
SelfActor.RemoveSpell(DLC2LightningStormRightHand)
SelfActor.UnEquipSpell(DLC2LightningStormRightHand, 1)
if Staff
SelfActor.UnequipItem(Staff)
selfActor.removeItem(Staff)
endif
;Add Spells & Equipment
sword1 = SelfActor.EquipItem(MiraakSword)
;Reset the combat Timer
TimeToSwapCombatStyle = currentTime + MaxTimeInMagicCombatStyle
ElseIf NewCombatStyle == 3 ;AntiAir
;Set the global that changes his combat override packages
DLC2MQ06MiraakCombatStyle.SetValue(3)
;Remove Spells & Equipment
if Sword1
SelfActor.UnequipItem(sword1)
selfActor.removeItem(sword1)
endif
if Staff
SelfActor.UnequipItem(Staff)
selfActor.removeItem(Staff)
endif
;Add Spells & Equipment
SelfActor.AddSpell(DLC2LightningStormRightHand)
;Reset the combat Timer
TimeToSwapCombatStyle = currentTime + 10.0
Else
; debug.Trace(self + ": ChangeCombatStyle was passed invalid int >> " + NewCombatStyle)
endif
SelfActor.EvaluatePackage()
endFunction
Function CheckMiraakHealthAndModIfNeeded()
float miraakHealth = selfActor.getActorValue("health")
if miraakHealth < 10.0
if miraakHealth < 0.0
miraakHealth = 0 - miraakHealth
EndIf
selfActor.RestoreActorValue("Health", 10.0 + miraakHealth)
endif
EndFunction
;;;;;;;;;;;;;;;;End of CombatStyle Functions;;;;;;;;;;;;;;;;;;;;;
;Setting this inside the script to avoid interleaving errors
Function setPlayerPositionVariable(int newPosition)
playerPosition = newPosition
endFunction
;;;;;;;;;;;;;;;;Sprint Functions;;;;;;;;;;;;;;;;;;;;;
;Whirlwind Sprint Properties
ReferenceAlias Property SprintTarget auto
Scene Property DLC2MQ06MiraakSprintScene auto
bool Property waitingForSprintSceneToEnd auto hidden
objectreference[] Property DLC2MQ06SprintTargets auto
Spell Property DLC2MiraakEtherealFXSpell auto
Function SprintAway(bool pickClosest = false)
objectreference Target
Target = PickSprintAwayTarget(pickClosest)
;FadeInSprintFX()
; ;debug.Trace(self + ": Sprinting to Target= " + Target)
SprintTarget.ForceRefTo(Target)
SelfActor.AddSpell(DLC2MiraakEtherealFXSpell)
selfActor.SetGhost(true)
DLC2MQ06MiraakSprintScene.start()
endFunction
Function SprintToTarget(objectreference Target)
; ;debug.Trace(self + ": Sprinting to Target= " + Target)
;FadeInSprintFX()
;utility.wait(0.2)
int sceneWaitSafety = 0
waitingForSprintSceneToEnd = True
SprintTarget.ForceRefTo(Target)
DLC2MQ06MiraakSprintScene.start()
;/
While waitingForSprintSceneToEnd && sceneWaitSafety < 20
utility.Wait(0.2)
; debug.Trace(self + ": Waiting for Sprint Scene To End >> " + sceneWaitSafety)
sceneWaitSafety += 1
CheckMiraakHealthAndModIfNeeded()
endWhile
/;
;FadeInSprintFX()
endFunction
Function SprintToTargetAndTeleportAway(objectreference Target)
int sceneWaitSafety = 0
; debug.Trace(self + ": SprintToTargetAndTeleportAway Target= " + Target)
teleportBusy = true
SprintToTarget(Target)
;/
waitingForSprintSceneToEnd = True
While waitingForSprintSceneToEnd && sceneWaitSafety < 4
utility.Wait(1.0)
; debug.Trace(self + ": Waiting for Sprint Scene To End >> " + sceneWaitSafety)
sceneWaitSafety += 1
CheckMiraakHealthAndModIfNeeded()
endWhile
/;
;TeleportAway()
endFunction
Function SprintSceneEnded()
;utility.wait(0.1)
;FadeOutSprintFX()
; Debug.Trace(self + ": SprintSceneEnded")
lastSprintTime = currentTime
if waitingForSprintSceneToEnd
waitingForSprintSceneToEnd = False
TeleportAway()
elseif !runningMiraakDeathEvent && !runningDragonKillEvent
SelfActor.RemoveSpell(DLC2MiraakEtherealFXSpell)
selfActor.SetGhost(false)
waitingForSprintSceneToEnd = False
endif
sprintBusy = False
; debug.Trace(self + ": Sprint Scene has ended")
endFunction
ObjectReference Function PickSprintAwayTarget(bool pickClosest = false)
ObjectReference NewSprintTarget
;Identify the closest teleport point, offset from it +/-2, and go there.
int closestPoint = 0
int i = 0
float ClosestDistance = 6000.0
float Distance = 0.0
float MinDistance = 2000.0
int listLength = DLC2MQ06SprintTargets.Length - 1
; Debug.Trace(self + "DLC2MQ06SprintTargets length = " + listLength)
if pickClosest
While (i < listLength)
Distance = playerActor.getDistance(DLC2MQ06SprintTargets[i])
if (Distance < ClosestDistance)
NewSprintTarget = DLC2MQ06SprintTargets[i]
ClosestDistance = Distance
EndIf
i = i + 1
EndWhile
else
Distance = 0.0
While Distance < MinDistance
i = utility.RandomInt(0, DLC2MQ06SprintTargets.Length)
NewSprintTarget = DLC2MQ06SprintTargets[i]
Distance = playerActor.getDistance(NewSprintTarget)
EndWhile
endif
return NewSprintTarget
EndFunction
;;;;;;;;;;;;;;;;End of Sprint Functions;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;Teleport Functions;;;;;;;;;;;;;;;;;;;;;
;Teleport Properties
objectreference property DLC2MiraakFightTeleportMarkerMid auto
objectreference property DLC2MiraakFightTeleportMarker01 auto
objectreference property DLC2MiraakFightTeleportMarker02 auto
objectreference property DLC2MiraakFightTeleportMarker03 auto
objectreference property DLC2MiraakFightTeleportMarker04 auto
objectreference property DLC2MiraakFightTeleportMarker05 auto
objectreference property DLC2MiraakFightTeleportMarker06 auto
objectreference property DLC2MQ06FightFallTeleportMarker auto
objectreference property DLC2MQ06KillSceneFallTeleportMarker auto
FormList Property DLC2MQ06TeleportTargetFL auto
objectreference property DLC2MQ06MiraakSaferoom auto
Explosion Property DLC2MQ06MiraakTeleportExplosion auto
Explosion Property DLC2MiraakAwayExplosion auto
Explosion Property DLC2MiraakBackExplosion auto
Scene property DLC2MQ06PlayerFallRecoveryScene auto
Scene property DLC2MQ06MiraakFallRecoveryScene auto
;objectReference[] property TeleportPoints auto
;Static property MiraakTeleportMarker Auto
float fadeSpeedDefault = 0.03 ; this is the default value of fDampRate fades over about 2 seconds
float fadeSpeedFast = 0.05 ; about 1 second fade time
VisualEffect Property DLC2MiraakStreakE Auto ;streak art...autofills
bool teleportFromOffCliff = false
bool teleportBusy
Function TeleportMiraakFromOffCliff()
; Debug.Trace(self + ": TeleportMiraakFromOffCliff>> ")
; Debug.Trace("runningMiraakDeathEvent = " + runningMiraakDeathEvent + " > runningDragonKillEvent = " + runningDragonKillEvent)
if !teleportBusy
teleportFromOffCliff = true
if runningMiraakDeathEvent && !SelfActor.isDead()
TeleportMiraak(DLC2MQ06KillSceneFallTeleportMarker)
else
TeleportAway()
endif
endif
EndFunction
Function TeleportPlayerFromOffCliff()
; Debug.Trace(self + ": TeleportPlayerFromOffCliff")
game.GetPlayer().PlaceAtMe(DLC2MQ06MiraakTeleportExplosion)
DLC2MQ06FightFallTeleportMarker.PlaceAtMe(DLC2MQ06MiraakTeleportExplosion)
game.GetPlayer().MoveTo(DLC2MQ06FightFallTeleportMarker)
EndFunction
Function TeleportMiraak(objectReference teleportTarget)
; Debug.Trace(self + ": TeleportMiraak to >> " + teleportTarget)
teleportTarget.PlaceAtMe(DLC2MiraakBackExplosion)
utility.wait(0.1)
selfActor.moveto(teleportTarget)
;miraak fades up
;utility.wait(0.05)
If !SelfActor.isDead()
selfActor.playSubgraphAnimation("SkinFadeIn")
endif
teleportBusy = false
endFunction
Function TeleportAway()
; Debug.Trace(self + ": TeleportAway>>")
; Debug.Trace("runningMiraakDeathEvent = " + runningMiraakDeathEvent + " > runningDragonKillEvent = " + runningDragonKillEvent)
teleportBusy = true
selfActor.PlaceAtMe(DLC2MiraakAwayExplosion)
selfActor.moveto(DLC2MQ06MiraakSaferoom)
;If we are in the MiraakDeathEvent move to the furniture and start the scene
if runningMiraakDeathEvent
; Debug.Trace(self + ": TeleportAway >>> runningMiraakDeathEvent")
selfActor.equipItem(DLC2MiraakSkeleton)
SelfActor.RemoveSpell(DLC2MiraakEtherealFXSpell)
DLC2MiraakStreakE.Stop(selfActor)
SelfActor.Moveto(MQ06MiraakDeathMarker)
DLC2MQ06.SetStage(500)
teleportBusy = false
elseif runningDragonKillEvent
; Debug.Trace(self + ": TeleportAway >>> runningDragonKillEvent")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;!!!!
while DragonToKill.isflying() && !DragonToKill.isDead()
utility.wait(1.0)
; debug.Trace(self + ": DragonKill waiting for landing")
endWhile
self.getActorRef().AddSpell(DLC2MiraakFakeShoutSpell)
waitingForDragonKillSceneToEnd = True
DLC2MQ06MiraakKillDragonScene.Start()
TeleportMiraak(DLC2MiraakFightTeleportMarkerMid)
elseif teleportFromOffCliff
; Debug.Trace(self + ": TeleportAway >>> teleportFromOffCliff")
teleportFromOffCliff = false
utility.Wait(0.2)
TeleportMiraak(DLC2MQ06FightFallTeleportMarker)
if !SelfActor.isDead()
DLC2MQ06MiraakFallRecoveryScene.Start()
endif
teleportBusy = false
endif
EndFunction
Function TeleportPlayerToTarget(objectreference teleportTarget)
; Debug.Trace(self + ": TeleportPlayerToTarget")
teleportTarget.PlaceAtMe(DLC2MQ06MiraakTeleportExplosion)
Game.getPlayer().moveto(teleportTarget)
DLC2MQ06PlayerFallRecoveryScene.Start()
endFunction
ObjectReference Function PickTeleportMarkerNearby()
ObjectReference closestMarker = Game.FindClosestReferenceOfAnyTypeInList(DLC2MQ06TeleportTargetFL, selfRef.getPositionX(), selfRef.getPositionY(), selfRef.getPositionZ(), 6000.0)
if (closestMarker == None)
; Debug.Trace(self + ": Could not pick nearby Teleport point!!!")
EndIf
return closestMarker
EndFunction
;;;;;;;;;;;;;;;;End of Teleport Functions;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;Tentacle Attack Functions;;;;;;;;;;;;;;;;;;;;;
;The following functions are for talking to the tentacle attack controller
;Properties for Tentacle Controller
DLC2MQBossTentacleController property tentacleController auto hidden
objectreference property DLC2MQBossTentacleControllerRef auto
float property TentacleTimer auto hidden
float property TentacleTimeDelayInit = 15.0 auto hidden
float property TentacleTimeDelay = 15.0 auto hidden
bool property DoTentacleAttacks = false auto
Function TriggerTentacleAttack(int TargetArea)
if TargetArea == -1 ;Attack FULL
TriggerTentacleAttackFull(bClockwise = false, fAttackTimer = 0.5)
elseif TargetArea >= 0 && TargetArea <= 6
TriggerTentacleAttackSingle(TargetArea, bClockwise = false, fAttackTimer = 0.5)
EndIf
EndFunction
Function TriggerTentacleAttackFull(bool bClockwise = false, float fAttackTimer = 0.5)
;Set properties then register for single update
; RegisterForSingleUpdate is used to kick off new thread
tentacleController.fullSweep = true
tentacleController.clockwise = bClockwise
tentacleController.attackTimer = fAttackTimer
tentacleController.RegisterForSingleUpdate(0.1)
endFunction
Function TriggerTentacleAttackSingle(int itargetArea = 1, bool bClockwise = false, float fAttackTimer = 0.5)
;Set properties then register for single update
; RegisterForSingleUpdate is used to kick off new thread
tentacleController.targetArea = itargetArea
tentacleController.clockwise = bClockwise
tentacleController.attackTimer = fAttackTimer
tentacleController.RegisterForSingleUpdate(0.1)
endFunction
;;;;;;;;;;;;;;;;Miraak Combat Leveling Function;;;;;;;;;;;;;;;;;;;;;
;Weapons
Int Property Stage1 = 37 Auto hidden
Int Property Stage2 = 44 Auto hidden
Int Property Stage3 = 51 Auto hidden
Int Property Stage4 = 58 Auto hidden
Int Property Stage5 = 65 Auto hidden
Weapon Property DLC2MKMiraakFightSword1 auto
Weapon Property DLC2MKMiraakFightSword2 auto
Weapon Property DLC2MKMiraakFightSword3 auto
Weapon Property DLC2MKMiraakFightSword4 auto
Weapon Property DLC2MKMiraakFightSword5 auto
Weapon Property DLC2MKMiraakFightSword6 auto
Weapon Property DLC2MKMiraakFightStaff1 auto
Weapon Property DLC2MKMiraakFightStaff2 auto
Weapon Property DLC2MKMiraakFightStaff3 auto
Weapon Property DLC2MKMiraakFightStaff4 auto
Weapon Property DLC2MKMiraakFightStaff5 auto
Weapon Property DLC2MKMiraakFightStaff6 auto
Function SetMiraakCombatLevel()
Actor miraak = GetActorRef()
;Pick the leveled gear that Miraak will use and store it
if (miraak.GetLevel() >= Stage5)
MiraakSword = DLC2MKMiraakFightSword6
MiraakStaff = DLC2MKMiraakFightStaff6
elseif (miraak.GetLevel() >= Stage4)
MiraakSword = DLC2MKMiraakFightSword5
MiraakStaff = DLC2MKMiraakFightStaff5
ElseIf (miraak.GetLevel() >= Stage3)
MiraakSword = DLC2MKMiraakFightSword4
MiraakStaff = DLC2MKMiraakFightStaff4
ElseIf (miraak.GetLevel() >= Stage2)
MiraakSword = DLC2MKMiraakFightSword3
MiraakStaff = DLC2MKMiraakFightStaff3
ElseIf (miraak.GetLevel() >= Stage1)
MiraakSword = DLC2MKMiraakFightSword2
MiraakStaff = DLC2MKMiraakFightStaff2
Else ;base gear
MiraakSword = DLC2MKMiraakFightSword1
MiraakStaff = DLC2MKMiraakFightStaff1
EndIf
EndFunction
;;;;;;;;;;;;;;;;End Miraak Combat Leveling Function;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;Set Reward Gear Function;;;;;;;;;;;;;;;;;;;;;
;Ended up doing this thorough DeathItems but kept the old script here
;This function controls if we give the player light or heavy mask
GlobalVariable Property DLC2MQ06MaskHeavyChance auto
GlobalVariable Property DLC2MQ06MaskLightChance auto
Function SetRewardGear()
if playerActor.getActorValue("Heavyarmor") > playerActor.getActorValue("LightArmor")
DLC2MQ06MaskHeavyChance.SetValue(0)
DLC2MQ06MaskLightChance.SetValue(100)
else
DLC2MQ06MaskLightChance.SetValue(0)
DLC2MQ06MaskHeavyChance.SetValue(100)
endif
EndFunction
Function SwapToRewardGear()
EndFunction
;;;;;;;;;;;;;;;;End Reward Gear Function;;;;;;;;;;;;;;;;;;;;;
;Hit Timestamps
float TimerPreviousHit01 = 0.0 ;Timestamps that record when the player hits Miraak with an attacked.
float TimerPreviousHit02 = 0.0 ;Used to approximately detect when he's been 'cornered' so he can escape.
float TimerPreviousHit03 = 0.0
float TimerPreviousHit04 = 0.0
float TimerPreviousHit05 = 0.0
float TimerPreviousHit06 = 0.0
float TimerOfRecord = 0.0 ;Timer used to determine when Miraak was cornered.
float minTimebetweenSprints = 10.0
float lastSprintTime = 0.0
bool sprintBusy = false
ObjectReference Property MQ06MiraakDeathTeleportMarker Auto