787 lines
28 KiB
Plaintext
787 lines
28 KiB
Plaintext
Scriptname _00E_Phasmalist_NewApparitionAlias extends ReferenceAlias
|
|
; script that controls the apparition stats calculation and initialization. Additionally, it is responsible for the control of the apparition communication while it is summoned
|
|
|
|
; we prefer to place new actors instead of using only one actor
|
|
; due to the problem of keeping track of all apparitions,
|
|
; which might create memory leaks because of persistence;
|
|
; Additionally, temporary or accidental changes do not cumulate
|
|
; and lead to problems
|
|
|
|
; balancing data
|
|
Float Property fApparitionManaRate = 1.0 AutoReadOnly
|
|
|
|
Float Property fPlayerStatsMult = 0.20 AutoReadOnly
|
|
Float Property fPlayerConjSkillMult = 0.10 AutoReadOnly
|
|
Float Property fPlayerEnchSkillMult = 0.15 AutoReadOnly
|
|
|
|
Float Property fArcaneFeverLevel01 = 7.00 AutoReadOnly
|
|
Float Property fArcaneFeverLevel02 = 6.00 AutoReadOnly
|
|
Float Property fArcaneFeverLevel03 = 5.00 AutoReadOnly
|
|
|
|
Float Property fArcaneFeverModWarrior = -1.0 AutoReadOnly
|
|
Float Property fArcaneFeverModRanger = 0.0 AutoReadOnly
|
|
Float Property fArcaneFeverModHybrid = 0.0 AutoReadOnly
|
|
Float Property fArcaneFeverModMage = 1.0 AutoReadOnly
|
|
|
|
Int Property iGhostlyMageBoostDestructionPowerMod1 = 7 AutoReadOnly
|
|
Int Property iGhostlyMageBoostDestructionPowerMod2 = 15 AutoReadOnly
|
|
Int Property iGhostlyMageBoostDestructionPowerMod3 = 25 AutoReadOnly
|
|
|
|
Int Property iGhostlyMageBoostMagicka1 = 15 AutoReadOnly
|
|
Int Property iGhostlyMageBoostMagicka2 = 40 AutoReadOnly
|
|
Int Property iGhostlyMageBoostMagicka3 = 75 AutoReadOnly
|
|
|
|
Int Property iGhostlyRangerBoostArchery1 = 7 AutoReadOnly
|
|
Int Property iGhostlyRangerBoostArchery2 = 17 AutoReadOnly
|
|
Int Property iGhostlyRangerBoostArchery3 = 30 AutoReadOnly
|
|
|
|
Int Property iGhostlyRangerBoostCritChance1 = 7 AutoReadOnly
|
|
Int Property iGhostlyRangerBoostCritChance2 = 15 AutoReadOnly
|
|
Int Property iGhostlyRangerBoostCritChance3 = 25 AutoReadOnly
|
|
|
|
Int Property iGhostlyWarriorBoostMelee1 = 7 AutoReadOnly
|
|
Int Property iGhostlyWarriorBoostMelee2 = 17 AutoReadOnly
|
|
Int Property iGhostlyWarriorBoostMelee3 = 30 AutoReadOnly
|
|
|
|
Int Property iGhostlyWarriorBoostArmorSkill1 = 7 AutoReadOnly
|
|
Int Property iGhostlyWarriorBoostArmorSkill2 = 17 AutoReadOnly
|
|
Int Property iGhostlyWarriorBoostArmorSkill3 = 30 AutoReadOnly
|
|
|
|
Float Property DEFAULT_HEAL_RATE = 50.0 AutoReadOnly
|
|
|
|
Explosion Property _00E_Phasmalist_EnterWorldExp Auto
|
|
|
|
Perk Property _00E_Class_Phasmalist_P03_Talent_SummonApparation_01 Auto
|
|
Perk Property _00E_Class_Phasmalist_P03_Talent_SummonApparation_02 Auto
|
|
Perk Property _00E_Class_Phasmalist_P03_Talent_SummonApparation_03 Auto
|
|
|
|
Static Property XMarker Auto
|
|
|
|
Perk Property _00E_Class_Phasmalist_P08_A_EssenceSplit Auto
|
|
|
|
; Boost perks
|
|
Perk Property _00E_Class_Phasmalist_P05_A_Shamanism_01 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_A_Shamanism_02 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_A_Shamanism_03 Auto
|
|
|
|
Perk Property _00E_Class_Phasmalist_P05_B_Mischief_01 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_B_Mischief_02 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_B_Mischief_03 Auto
|
|
|
|
Perk Property _00E_Class_Phasmalist_P05_C_Violence_01 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_C_Violence_02 Auto
|
|
Perk Property _00E_Class_Phasmalist_P05_C_Violence_03 Auto
|
|
|
|
Message Property _00E_Phasmalist_CurrentlyEquipped Auto
|
|
|
|
ImageSpaceModifier Property _00E_ArkanistenfieberIMOD Auto
|
|
ImageSpaceModifier Property _00E_Phasmalist_ApparitionEnterWorldIMOD Auto
|
|
|
|
Sound Property _00E_FS_IncreaseArcaneFeverM Auto
|
|
|
|
Message Property _00E_Player_sArcaneFeverIncreased Auto
|
|
GlobalVariable Property _00E_Phasmalist_IsApparitionSummoned Auto
|
|
|
|
; The apparition should not be able to learn summon creature and mystical/mythical spells
|
|
FormList Property _00E_PhasmalistApparition_SpellBooks Auto
|
|
FormList Property _00E_PhasmalistApparition_Spells Auto
|
|
|
|
Int iCurrentBoostMagicka ; this is set in adjustBoost() to have the attribute set correctly in the stats calculation
|
|
|
|
Actor Property PlayerREF Auto
|
|
|
|
FormList Property _00E_AllAmmos Auto
|
|
|
|
_00E_Phasmalist_TrinketSC SummonTrinket
|
|
|
|
; Stores the reference of the current apparition while it's properly spawned, not being unsummoned, not dying, etc.
|
|
; Needed for the failsafe in OnLoadGame() and some other shenanigans
|
|
Actor Property AliasFailsafeRef = None Auto Hidden
|
|
|
|
Bool bTeleportHealRate = False
|
|
|
|
|
|
;=====================================================================================
|
|
; SUMMON & SETUP
|
|
;=====================================================================================
|
|
|
|
Function Summon(_00E_Phasmalist_TrinketSC trinket, ObjectReference moveToRef, Bool bPhasmalismTankMode, Bool bSilent)
|
|
Actor akSelf = Self.GetActorReference()
|
|
|
|
SummonTrinket = trinket
|
|
bActivationBusy = bPhasmalismTankMode ; Reset just in case
|
|
bTeleportHealRate = False ; Reset just in case
|
|
_00E_Phasmalist_IsApparitionSummoned.SetValue(1)
|
|
|
|
Setup() ; init stats before any armor buffs are applied
|
|
|
|
If bSilent == False
|
|
_00E_Phasmalist_ApparitionEnterWorldIMOD.Apply()
|
|
EndIf
|
|
|
|
(akSelf.GetActorBase() as _00E_Phasmalist_ApparationSC).inventoryContainer.removeAllItems(akSelf, false, true)
|
|
|
|
If bPhasmalismTankMode == False
|
|
Int i = akSelf.GetNumItems()
|
|
While i > 0
|
|
i -= 1
|
|
Form item = akSelf.GetNthForm(i)
|
|
If item as Book
|
|
_RegisterSpellBook(akSelf, item)
|
|
EndIf
|
|
EndWhile
|
|
EndIf
|
|
|
|
akSelf.BlockActivation()
|
|
|
|
If bPhasmalismTankMode
|
|
akSelf.SetActorValue("Variable01", 1.0)
|
|
akSelf.EnableAI(False)
|
|
Else
|
|
If moveToRef == PlayerREF
|
|
_MoveToPlayer(akSelf, False)
|
|
EndIf
|
|
|
|
GoToState("Working")
|
|
EndIf
|
|
|
|
akSelf.Enable()
|
|
AliasFailsafeRef = akSelf
|
|
|
|
If bPhasmalismTankMode
|
|
; MoveTo needs to be done after Enable or the apparition ends on the neareast navmesh instead of the tank
|
|
akSelf.MoveTo(moveToRef)
|
|
EndIf
|
|
|
|
If bSilent == False
|
|
PlaySummonExplosion(akSelf)
|
|
EndIf
|
|
|
|
SendModEvent("Phasmalist_ApparationSummon")
|
|
EndFunction
|
|
|
|
Function PlaySummonExplosion(ObjectReference markerRef)
|
|
ObjectReference expMarker = _PlaceExplosionEx(_00E_Phasmalist_EnterWorldExp, markerRef, 15.0)
|
|
_DeleteMarker(expMarker)
|
|
EndFunction
|
|
|
|
Int Property BOOST_CLASS_MAGE = 0 AutoReadOnly
|
|
Int Property BOOST_CLASS_RANGER = 1 AutoReadOnly
|
|
Int Property BOOST_CLASS_WARRIOR = 2 AutoReadOnly
|
|
|
|
Function Setup()
|
|
Actor akSelf = Self.GetActorReference()
|
|
|
|
SetupBehaviour(akSelf)
|
|
SetupNotPersistentStats(akSelf)
|
|
|
|
Float fAttributeMult = (fPlayerConjSkillMult * PlayerREF.GetActorValue("Conjuration") + fPlayerEnchSkillMult * PlayerREF.GetActorValue("Enchanting")) / 100.0 + 1.0
|
|
|
|
ApplyClassBoost(akSelf, BOOST_CLASS_MAGE, _00E_Class_Phasmalist_P05_A_Shamanism_01, _00E_Class_Phasmalist_P05_A_Shamanism_02, _00E_Class_Phasmalist_P05_A_Shamanism_03)
|
|
ApplyClassBoost(akSelf, BOOST_CLASS_RANGER, _00E_Class_Phasmalist_P05_B_Mischief_01, _00E_Class_Phasmalist_P05_B_Mischief_02, _00E_Class_Phasmalist_P05_B_Mischief_03)
|
|
ApplyClassBoost(akSelf, BOOST_CLASS_WARRIOR, _00E_Class_Phasmalist_P05_C_Violence_01, _00E_Class_Phasmalist_P05_C_Violence_02, _00E_Class_Phasmalist_P05_C_Violence_03)
|
|
|
|
If PlayerREF.HasPerk(_00E_Class_Phasmalist_P08_A_EssenceSplit)
|
|
Float fMaxAttributeValue = PlayerREF.GetBaseAV("Health")
|
|
Float fPlayerMagicka = PlayerREF.GetBaseAV("Magicka")
|
|
If fPlayerMagicka > fMaxAttributeValue
|
|
fMaxAttributeValue = fPlayerMagicka
|
|
EndIf
|
|
Float fPlayerStamina = PlayerREF.GetBaseAV("Stamina")
|
|
If fPlayerStamina > fMaxAttributeValue
|
|
fMaxAttributeValue = fPlayerStamina
|
|
EndIf
|
|
akSelf.ForceActorValue("Health", ((akSelf.GetBaseAV("Health") + fMaxAttributeValue * fPlayerStatsMult) * fAttributeMult) as int)
|
|
akSelf.ForceActorValue("Magicka", (((akSelf.GetBaseAV("Magicka") + fMaxAttributeValue * fPlayerStatsMult) * fAttributeMult) as int) + iCurrentBoostMagicka)
|
|
akSelf.ForceActorValue("Stamina", ((akSelf.GetBaseAV("Stamina") + fMaxAttributeValue * fPlayerStatsMult) * fAttributeMult) as int)
|
|
|
|
Else
|
|
akSelf.ForceActorValue("Health", ((akSelf.GetBaseAV("Health") + PlayerREF.GetBaseAV("Health") * fPlayerStatsMult) * fAttributeMult) as int)
|
|
akSelf.ForceActorValue("Magicka", (((akSelf.GetBaseAV("Magicka") + PlayerREF.GetBaseAV("Magicka") * fPlayerStatsMult) * fAttributeMult) as int) + iCurrentBoostMagicka)
|
|
akSelf.ForceActorValue("Stamina", ((akSelf.GetBaseAV("Stamina") + PlayerREF.GetBaseAV("Stamina") * fPlayerStatsMult) * fAttributeMult) as int)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function SetupBehaviour(Actor akSelf)
|
|
Int iRelationship = akSelf.GetRelationshipRank(PlayerREF)
|
|
If iRelationship < 3 && iRelationship >= 0
|
|
akSelf.SetRelationshipRank(PlayerREF, 3)
|
|
EndIf
|
|
|
|
akSelf.SetPlayerTeammate()
|
|
akSelf.SetActorValue("Confidence", 4) ; the apparition should never flee
|
|
akSelf.SetActorValue("Aggression", 0) ; the apparition should not initiate combat (-> stealth playstyle)
|
|
akSelf.SetActorValue("Sneak", 100)
|
|
akSelf.SetActorValue("Invisibility", 1) ; make the apparition undetectable when sneaking (-> stealth playstyle)
|
|
akSelf.IgnoreFriendlyHits() ; make the apparition ignore friendly fire from the PC
|
|
EndFunction
|
|
|
|
Function SetupNotPersistentStats(Actor akSelf)
|
|
akSelf.GetActorBase().SetCombatStyle(SummonTrinket.GetUsedCombatStyle())
|
|
|
|
If bTeleportHealRate == False
|
|
akSelf.SetActorValue("HealRate", DEFAULT_HEAL_RATE)
|
|
Else
|
|
akSelf.SetActorValue("HealRate", 0.0)
|
|
EndIf
|
|
akSelf.SetActorValue("MagickaRate", fApparitionManaRate)
|
|
|
|
;failsafe since setav doesn't work sometimes
|
|
If bTeleportHealRate == False
|
|
akSelf.ForceActorValue("HealRate", DEFAULT_HEAL_RATE)
|
|
Else
|
|
akSelf.ForceActorValue("HealRate", 0.0)
|
|
EndIf
|
|
akSelf.ForceActorValue("MagickaRate", fApparitionManaRate)
|
|
EndFunction
|
|
|
|
Function ApplyClassBoost(Actor akSelf, Int iBoostClass, Perk boostPerk1, Perk boostPerk2, Perk boostPerk3)
|
|
If PlayerREF.HasPerk(boostPerk1)
|
|
If PlayerREF.HasPerk(boostPerk3)
|
|
_AddClassBoost(akSelf, iBoostClass, 3)
|
|
ElseIf PlayerREF.HasPerk(boostPerk2)
|
|
_AddClassBoost(akSelf, iBoostClass, 2)
|
|
Else
|
|
_AddClassBoost(akSelf, iBoostClass, 1)
|
|
EndIf
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function _AddClassBoost(Actor akSelf, Int iBoostClass, Int iBoostLevel)
|
|
If iBoostClass == BOOST_CLASS_MAGE
|
|
Int iDestructionPowerMod = 0
|
|
If iBoostLevel == 3
|
|
iDestructionPowerMod = iGhostlyMageBoostDestructionPowerMod3
|
|
iCurrentBoostMagicka = iGhostlyMageBoostMagicka3 ; since magicka is boosted later again, we have to save this boost and apply it later to prevent overwriting old boosts
|
|
ElseIf iBoostLevel == 2
|
|
iDestructionPowerMod = iGhostlyMageBoostDestructionPowerMod2
|
|
iCurrentBoostMagicka = iGhostlyMageBoostMagicka2
|
|
Else
|
|
iDestructionPowerMod = iGhostlyMageBoostDestructionPowerMod1
|
|
iCurrentBoostMagicka = iGhostlyMageBoostMagicka1
|
|
EndIf
|
|
;akSelf.ForceActorValue("DestructionPowerMod", akSelf.GetActorValue("DestructionPowerMod") + iDestructionPowerMod)
|
|
akSelf.ModActorValue("DestructionPowerMod", iDestructionPowerMod)
|
|
ElseIf iBoostClass == BOOST_CLASS_RANGER
|
|
Int iBoostArchery = 0
|
|
Int iBoostCritChance = 0
|
|
If iBoostLevel == 3
|
|
iBoostArchery = iGhostlyRangerBoostArchery3
|
|
iBoostCritChance = iGhostlyRangerBoostCritChance3
|
|
ElseIf iBoostLevel == 2
|
|
iBoostArchery = iGhostlyRangerBoostArchery2
|
|
iBoostCritChance = iGhostlyRangerBoostCritChance2
|
|
Else
|
|
iBoostArchery = iGhostlyRangerBoostArchery1
|
|
iBoostCritChance = iGhostlyRangerBoostCritChance1
|
|
EndIf
|
|
|
|
;akSelf.ForceActorValue("Marksman", akSelf.GetActorValue("Marksman") + iBoostArchery)
|
|
akSelf.ModActorValue("Marksman", iBoostArchery)
|
|
;akSelf.ForceActorValue("CritChance", akSelf.GetActorValue("CritChance") + iBoostCritChance)
|
|
akSelf.ModActorValue("CritChance", iBoostCritChance)
|
|
ElseIf iBoostClass == BOOST_CLASS_WARRIOR
|
|
Int iBoostMelee = 0
|
|
Int iBoostArmor = 0
|
|
If iBoostLevel == 3
|
|
iBoostMelee = iGhostlyWarriorBoostMelee3
|
|
iBoostArmor = iGhostlyWarriorBoostArmorSkill3
|
|
ElseIf iBoostLevel == 2
|
|
iBoostMelee = iGhostlyWarriorBoostMelee2
|
|
iBoostArmor = iGhostlyWarriorBoostArmorSkill2
|
|
Else
|
|
iBoostMelee = iGhostlyWarriorBoostMelee1
|
|
iBoostArmor = iGhostlyWarriorBoostArmorSkill1
|
|
EndIf
|
|
|
|
;akSelf.ForceActorValue("HeavyArmor", akSelf.GetActorValue("HeavyArmor") + iBoostArmor)
|
|
akSelf.ModActorValue("HeavyArmor", iBoostArmor)
|
|
;akSelf.ForceActorValue("LightArmor", akSelf.GetActorValue("LightArmor") + iBoostArmor)
|
|
akSelf.ModActorValue("LightArmor", iBoostArmor)
|
|
; MeleeDamage AV seems to be not working, it's actually always zero
|
|
;akSelf.ForceActorValue("MeleeDamage", akSelf.GetActorValue("MeleeDamage") + iBoostMelee)
|
|
;akSelf.ModActorValue("MeleeDamage", iBoostMelee)
|
|
akSelf.ModActorValue("OneHanded", iBoostMelee)
|
|
akSelf.ModActorValue("TwoHanded", iBoostMelee)
|
|
Else
|
|
Debug.Notification("Phasmalist Control Quest has issues: Unsupported boost class " + iBoostClass)
|
|
EndIf
|
|
Endfunction
|
|
|
|
|
|
;=====================================================================================
|
|
; UNSUMMON & CLEANUP
|
|
;=====================================================================================
|
|
|
|
Function Unsummon(Bool bSilent)
|
|
Actor akSelf = self.GetActorReference()
|
|
|
|
HealthBarManager.Hide(akSelf)
|
|
|
|
GoToState("")
|
|
AliasFailsafeRef = None
|
|
|
|
TransformFromWerewolf(akSelf, True, bSilent)
|
|
|
|
If bSilent == False
|
|
If akSelf.Is3DLoaded()
|
|
akSelf.PlaceAtMe(_00E_Phasmalist_EnterWorldExp)
|
|
EndIf
|
|
AddArcaneFever()
|
|
EndIf
|
|
|
|
_00E_Phasmalist_IsApparitionSummoned.SetValue(0)
|
|
akSelf.RemoveAllItems((akSelf.GetActorBase() as _00E_Phasmalist_ApparationSC).inventoryContainer, False, True)
|
|
akSelf.Disable()
|
|
Self.Clear()
|
|
SummonTrinket = None
|
|
|
|
Utility.wait(1.0)
|
|
akSelf.Delete()
|
|
|
|
SendModEvent("Phasmalist_ApparationUnSummon")
|
|
|
|
EndFunction
|
|
|
|
Function AddArcaneFever()
|
|
Actor akSelf = Self.GetActorReference()
|
|
Float fHealthLostPercentage = 0
|
|
Float fMaxArcaneFeverAdd = 0
|
|
|
|
If akSelf.IsDead()
|
|
fHealthLostPercentage = 1.0
|
|
Else
|
|
fHealthLostPercentage = 1.0 - akSelf.GetActorValuePercentage("health")
|
|
If fHealthLostPercentage > 1.0
|
|
fHealthLostPercentage = 1.0
|
|
EndIf
|
|
EndIf
|
|
|
|
Int iTalentLevel = _00E_TalentLibrary.GetPlayerTalentLevel(_00E_Class_Phasmalist_P03_Talent_SummonApparation_01, _00E_Class_Phasmalist_P03_Talent_SummonApparation_02, _00E_Class_Phasmalist_P03_Talent_SummonApparation_03)
|
|
If iTalentLevel == 1
|
|
fMaxArcaneFeverAdd = fArcaneFeverLevel01
|
|
ElseIf iTalentLevel == 2
|
|
fMaxArcaneFeverAdd = fArcaneFeverLevel02
|
|
Else
|
|
fMaxArcaneFeverAdd = fArcaneFeverLevel03
|
|
EndIf
|
|
|
|
Int iTrinketType = SummonTrinket.type
|
|
If iTrinketType == 0
|
|
fMaxArcaneFeverAdd += fArcaneFeverModWarrior
|
|
ElseIf iTrinketType == 1
|
|
fMaxArcaneFeverAdd += fArcaneFeverModRanger
|
|
ElseIf iTrinketType == 2
|
|
fMaxArcaneFeverAdd += fArcaneFeverModMage
|
|
Else
|
|
fMaxArcaneFeverAdd += fArcaneFeverModHybrid
|
|
EndIf
|
|
|
|
Float fArcaneFeverAdd = fMaxArcaneFeverAdd * fHealthLostPercentage
|
|
If fArcaneFeverAdd > 0
|
|
PlayerREF.ModActorValue("LastFlattered", -fArcaneFeverAdd)
|
|
_00E_ArkanistenfieberIMOD.ApplyCrossFade()
|
|
_00E_FS_IncreaseArcaneFeverM.Play(PlayerREF)
|
|
_00E_Player_sArcaneFeverIncreased.Show(fArcaneFeverAdd, -1 * PlayerREF.GetActorValue("LastFlattered"))
|
|
EndIf
|
|
EndFunction
|
|
|
|
|
|
;=====================================================================================
|
|
; OTHER ACTIONS
|
|
;=====================================================================================
|
|
|
|
Function OnLoadGame()
|
|
; sometimes reloading a save with a summoned apparition from a game state without one can result in the apparationAlias (old alias) being cleared.
|
|
; To fix this, the script additionally keeps track of its content in a variable and refills itself onGameLoad
|
|
If AliasFailsafeRef
|
|
Self.ForceRefTo(AliasFailsafeRef)
|
|
EndIf
|
|
|
|
Actor akSelf = GetActorReference()
|
|
If akSelf
|
|
SetupNotPersistentStats(akSelf)
|
|
_ShowHealthBar()
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function TeleportToPlayer(Bool bTeleportInFront, Bool bSilent)
|
|
Actor akSelf = Self.GetActorReference()
|
|
If akSelf
|
|
; Zero out-of-combat heal rate for teleport and a few seconds after it.
|
|
; This is to prevent the apparition regenerating health IN combat on "Call Apparition" spam.
|
|
UnregisterForUpdate()
|
|
akSelf.ForceActorValue("HealRate", 0.0)
|
|
bTeleportHealRate = True
|
|
|
|
akSelf.Disable()
|
|
_MoveToPlayer(akSelf, bTeleportInFront)
|
|
akSelf.Enable()
|
|
If bSilent == False
|
|
akSelf.PlaceAtMe(_00E_Phasmalist_EnterWorldExp)
|
|
EndIf
|
|
|
|
RegisterForSingleUpdate(2.0)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function SetCombatStyle(CombatStyle newCombatStyle)
|
|
Actor akSelf = Self.GetActorReference()
|
|
If akSelf
|
|
_SetCombatStyle(akSelf, newCombatStyle)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function ShowStatsMenu()
|
|
Actor akSelf = Self.GetActorReference()
|
|
If akSelf
|
|
UIExtensions.initMenu("UIStatsMenu")
|
|
UIExtensions.openMenu("UIStatsMenu", akSelf)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function ShowEquipment()
|
|
Actor akSelf = Self.GetActorReference()
|
|
|
|
If akSelf
|
|
String text = _00E_Phasmalist_CurrentlyEquipped.GetName() + "\n\n"
|
|
|
|
Weapon EquippedWeapon = akSelf.GetEquippedWeapon()
|
|
If EquippedWeapon
|
|
text = text + EquippedWeapon.GetName() + "\n" ;weapon
|
|
If EquippedWeapon.IsBow()
|
|
Form[] arrows = _00E_AllAmmos.ToArray()
|
|
Int i = 0
|
|
Int nArrowCount
|
|
While i < arrows.Length
|
|
nArrowCount = akSelf.GetItemCount(arrows[i])
|
|
If nArrowCount > 0
|
|
text = text + (arrows[i].GetName() + " (" + nArrowCount +")\n")
|
|
EndIf
|
|
i += 1
|
|
EndWhile
|
|
EndIf
|
|
EndIf
|
|
text = _AddWornFormAsString(akSelf, 0x00000200, text) ;shield
|
|
text = _AddWornFormAsString(akSelf, 0x00001000, text) ;circlet
|
|
text = _AddWornFormAsString(akSelf, 0x00000004, text) ;body
|
|
text = _AddWornFormAsString(akSelf, 0x00000008, text) ;hands
|
|
text = _AddWornFormAsString(akSelf, 0x00000080, text) ;feet
|
|
text = _AddWornFormAsString(akSelf, 0x00000020, text) ;amulet
|
|
text = _AddWornFormAsString(akSelf, 0x00000040, text) ;ring
|
|
|
|
Debug.MessageBox(text)
|
|
EndIf
|
|
EndFunction
|
|
|
|
|
|
;=====================================================================================
|
|
; WEREWOLF
|
|
;=====================================================================================
|
|
|
|
FormList Property _00E_Phasmalist_CombatStyleWerewolfList Auto
|
|
Spell Property _00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP Auto
|
|
Idle Property WerewolfTransformBack Auto
|
|
Idle Property IdleWerewolfTransformation Auto
|
|
Explosion Property _00E_FS_Theriantrophist_TransEXP Auto
|
|
Race Property _00E_Theriantrophist_PlayerWerewolfRace Auto
|
|
ObjectReference Property _00E_FS_Affinity_Soulcaller_RemoveAndAddApparationItemsChest Auto
|
|
Idle Property LooseFullBodyStagger Auto
|
|
Armor Property _00E_InvisibleHelmet_Armor Auto
|
|
|
|
Float Property WEREWOLF_TRANSFORM_UNARMED_DAMAGE_BOOST = 20.0 AutoReadOnly
|
|
Float Property WEREWOLF_TRANSFORM_HEALTH_BOOST = 40.0 AutoReadOnly
|
|
|
|
Race WerewolfTranform_OriginalRace = None
|
|
|
|
Bool Function IsTransformedToWerewolf()
|
|
Return (WerewolfTranform_OriginalRace != None)
|
|
EndFunction
|
|
|
|
Function TransformToWerewolf(Actor akSpellTarget)
|
|
ObjectReference expMarker
|
|
|
|
Actor akSelf = GetActorReference()
|
|
If (akSelf == None) || (akSelf != akSpellTarget)
|
|
Return
|
|
EndIf
|
|
|
|
bActivationBusy = True
|
|
|
|
akSelf.SetPlayerTeammate(False)
|
|
akSelf.EvaluatePackage()
|
|
WerewolfTranform_OriginalRace = akSelf.getRace()
|
|
Utility.Wait(0.2)
|
|
akSelf.PlayIdle(IdleWerewolfTransformation)
|
|
Utility.Wait(0.8)
|
|
|
|
_SetCombatStyle(akSelf, _00E_Phasmalist_CombatStyleWerewolfList.GetAt(0) as CombatStyle)
|
|
_00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP.SetNthEffectMagnitude(0, WEREWOLF_TRANSFORM_UNARMED_DAMAGE_BOOST)
|
|
_00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP.SetNthEffectMagnitude(1, WEREWOLF_TRANSFORM_HEALTH_BOOST)
|
|
akSelf.AddSpell(_00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP)
|
|
expMarker = _PlaceExplosionEx(_00E_FS_Theriantrophist_TransEXP, akSelf, 100.0)
|
|
Utility.Wait(0.4) ; Pause to synchronize the explosion with the transformation animation(s)
|
|
akSelf.SetLookAt(akSelf) ; Reset headtracking to prevent the head getting stuck looking sideways after the tranformation
|
|
akSelf.UnequipAll()
|
|
akSelf.SetRace(_00E_Theriantrophist_PlayerWerewolfRace)
|
|
|
|
_DeleteMarker(expMarker)
|
|
Utility.Wait(0.2)
|
|
akSelf.SetPlayerTeammate(True)
|
|
akSelf.EvaluatePackage()
|
|
|
|
bActivationBusy = False
|
|
EndFunction
|
|
|
|
Function TransformFromWerewolf(Actor akSpellTarget, Bool bIsUnsummoned, Bool bSilent)
|
|
Actor akSelf = GetActorReference()
|
|
If (IsTransformedToWerewolf() == False) || (akSelf == None) || (akSelf != akSpellTarget)
|
|
Return
|
|
EndIf
|
|
|
|
bActivationBusy = True
|
|
bTeleportHealRate = False
|
|
|
|
If akSelf.IsDead()
|
|
_TransformFromWerewolfDead(akSelf, bIsUnsummoned, bSilent)
|
|
Else
|
|
_TransformFromWerewolfAlive(akSelf, bIsUnsummoned, bSilent)
|
|
EndIf
|
|
|
|
WerewolfTranform_OriginalRace = None
|
|
|
|
bActivationBusy = False
|
|
EndFunction
|
|
|
|
Function _TransformFromWerewolfDead(Actor akSelf, Bool bIsUnsummoned, Bool bSilent)
|
|
ObjectReference expMarker = None
|
|
|
|
GoToState("")
|
|
|
|
If bSilent == False
|
|
expMarker = _PlaceExplosionEx(_00E_FS_Theriantrophist_TransEXP, akSelf, 15.0)
|
|
EndIf
|
|
; RemoveAllItems is needed here for _TriggerEquipmentUpdate to work
|
|
akSelf.RemoveAllItems(_00E_FS_Affinity_Soulcaller_RemoveAndAddApparationItemsChest)
|
|
akSelf.SetPlayerTeammate(False)
|
|
akSelf.Resurrect()
|
|
_00E_FS_Affinity_Soulcaller_RemoveAndAddApparationItemsChest.RemoveAllItems(akSelf)
|
|
Utility.Wait(0.2) ; Pause for the ragdoll to settle. Without it the apparition appears in the air on SetRace
|
|
_SetCombatStyle(akSelf, SummonTrinket.GetUsedCombatStyle())
|
|
akSelf.RemoveSpell(_00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP)
|
|
If expMarker
|
|
_DeleteMarker(expMarker)
|
|
expMarker = None
|
|
EndIf
|
|
akSelf.SetRace(WerewolfTranform_OriginalRace)
|
|
_TriggerEquipmentUpdate(akSelf, False)
|
|
akSelf.ClearLookAt() ; Reenable headtracking
|
|
|
|
If bIsUnsummoned == False
|
|
GoToState("Working")
|
|
EndIf
|
|
akSelf.Kill()
|
|
EndFunction
|
|
|
|
Function _TransformFromWerewolfAlive(Actor akSelf, Bool bIsUnsummoned, Bool bSilent)
|
|
ObjectReference expMarker = None
|
|
|
|
akSelf.SetPlayerTeammate(False)
|
|
akSelf.EvaluatePackage()
|
|
akSelf.PlayIdle(WerewolfTransformBack)
|
|
akSelf.RemoveSpell(_00E_FS_Affinity_Soulcaller_ApparationWolfBoostSP)
|
|
_SetCombatStyle(akSelf, SummonTrinket.GetUsedCombatStyle())
|
|
If bSilent == False
|
|
expMarker = _PlaceExplosionEx( _00E_FS_Theriantrophist_TransEXP, akSelf, 100.0)
|
|
EndIf
|
|
akSelf.SetRace(WerewolfTranform_OriginalRace)
|
|
_TriggerEquipmentUpdate(akSelf, True)
|
|
If expMarker
|
|
_DeleteMarker(expMarker)
|
|
expMarker = None
|
|
EndIf
|
|
Utility.Wait(0.2)
|
|
akSelf.ClearLookAt() ; Reenable headtracking
|
|
If bIsUnsummoned == False
|
|
SetupBehaviour(akSelf)
|
|
SetupNotPersistentStats(akSelf)
|
|
akSelf.EvaluatePackage()
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function _TriggerEquipmentUpdate(Actor akSelf, Bool bPlayStaggerIdle)
|
|
akSelf.SetPlayerTeammate(True) ; Yes, the apparition has to be a player's teammate for AddItem-EquipItem below to trigger equipment update
|
|
If bPlayStaggerIdle
|
|
akSelf.PlayIdle(LooseFullBodyStagger)
|
|
EndIf
|
|
|
|
akSelf.AddItem(_00E_InvisibleHelmet_Armor, 1, True)
|
|
akSelf.EquipItem(_00E_InvisibleHelmet_Armor, 1)
|
|
akSelf.RemoveItem(_00E_InvisibleHelmet_Armor, 1)
|
|
EndFunction
|
|
|
|
|
|
;=====================================================================================
|
|
; HELPER FUNCTIONS
|
|
;=====================================================================================
|
|
|
|
String Function _AddWornFormAsString(Actor a, int slot, string s)
|
|
Form wornForm = a.GetWornForm(slot)
|
|
If wornForm
|
|
Return s + wornForm.GetName() + "\n"
|
|
EndIf
|
|
Return s
|
|
EndFunction
|
|
|
|
Function _ShowHealthBar()
|
|
Actor akSelf = Self.GetActorReference()
|
|
If akSelf && akSelf.IsDead() == False
|
|
HealthBarManager.Show(akSelf)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Float Property FRONT_TELEPORT_DISTANCE = 72.0 AutoReadOnly
|
|
Float Property BACK_TELEPORT_DISTANCE = 96.0 AutoReadOnly
|
|
|
|
Function _MoveToPlayer(Actor akSelf, Bool bTeleportInFront)
|
|
Float fHeadingAngle = PlayerREF.GetAngleZ()
|
|
If bTeleportInFront
|
|
akSelf.MoveTo(PlayerREF, FRONT_TELEPORT_DISTANCE * Math.sin(fHeadingAngle), FRONT_TELEPORT_DISTANCE * Math.cos(fHeadingAngle), 0, True)
|
|
akSelf.SetAngle(0, 0, fHeadingAngle + 180.0)
|
|
Else
|
|
fHeadingAngle += 180.0
|
|
akSelf.MoveTo(PlayerREF, BACK_TELEPORT_DISTANCE * Math.sin(fHeadingAngle), BACK_TELEPORT_DISTANCE * Math.cos(fHeadingAngle), 0, True)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function _SetCombatStyle(Actor akSelf, CombatStyle newCombatStyle)
|
|
akSelf.StopCombat()
|
|
akSelf.GetActorBase().SetCombatStyle(newCombatStyle)
|
|
EndFunction
|
|
|
|
Spell Function _GetSpellFromSpellBook(Form akBaseItem)
|
|
; The apparition should not be able to learn summon creature and mystical/mythical spells
|
|
Int iSpellBook = _00E_PhasmalistApparition_SpellBooks.Find(akBaseItem)
|
|
If iSpellBook >= 0
|
|
Return (_00E_PhasmalistApparition_Spells.GetAt(iSpellBook) as Spell)
|
|
Else
|
|
Return None
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function _RegisterSpellBook(Actor akSelf, Form akBaseItem)
|
|
Spell bookSpell = _GetSpellFromSpellBook(akBaseItem)
|
|
If bookSpell
|
|
Self.GetActorReference().AddSpell(bookSpell, False)
|
|
EndIf
|
|
EndFunction
|
|
|
|
Function _UnregisterSpellBook(Actor akSelf, Form akBaseItem)
|
|
Spell bookSpell = _GetSpellFromSpellBook(akBaseItem)
|
|
If bookSpell
|
|
Self.GetActorReference().RemoveSpell(bookSpell)
|
|
EndIf
|
|
EndFunction
|
|
|
|
ObjectReference Function _PlaceExplosionEx(Explosion exp, ObjectReference refSpot, Float fOffsetZ)
|
|
ObjectReference expMarker = refSpot.PlaceAtMe(XMarker)
|
|
expMarker.MoveTo(refSpot, 0.0, 0.0, fOffsetZ)
|
|
expMarker.PlaceAtMe(exp)
|
|
Return expMarker
|
|
EndFunction
|
|
|
|
Function _DeleteMarker(ObjectReference refMarker)
|
|
refMarker.Disable()
|
|
refMarker.Delete()
|
|
EndFunction
|
|
|
|
|
|
;=====================================================================================
|
|
; EVENTS
|
|
;=====================================================================================
|
|
|
|
Bool bActivationBusy = False
|
|
|
|
State Working
|
|
|
|
Event OnActivate(ObjectReference akActivator)
|
|
If akActivator == PlayerREF && bActivationBusy == False
|
|
bActivationBusy = True
|
|
|
|
UIExtensions.initMenu("UIWheelMenu")
|
|
UIExtensions.SetMenuPropertyIndexBool("UIWheelMenu", "optionEnabled", 0, true)
|
|
UIExtensions.SetMenuPropertyIndexBool("UIWheelMenu", "optionEnabled", 1, true)
|
|
UIExtensions.SetMenuPropertyIndexBool("UIWheelMenu", "optionEnabled", 4, true)
|
|
UIExtensions.SetMenuPropertyIndexBool("UIWheelMenu", "optionEnabled", 5, true)
|
|
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionText", 0, "$View_Attributes")
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionLabelText", 0, "$View_Attributes")
|
|
|
|
If IsTransformedToWerewolf() == False
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionText", 1, "$Adapt_Combat_Style")
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionLabelText", 1, "$Adapt_Combat_Style")
|
|
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionText", 4, "$Currently_Equipped")
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionLabelText", 4, "$Currently_Equipped")
|
|
EndIf
|
|
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionText", 5, "$Quit")
|
|
UIExtensions.SetMenuPropertyIndexString("UIWheelMenu", "optionLabelText", 5, "$Quit")
|
|
|
|
Int iChoice = UIExtensions.OpenMenu("UIWheelMenu", Self.GetActorReference())
|
|
If iChoice == 0
|
|
ShowStatsMenu()
|
|
ElseIf iChoice == 1
|
|
SummonTrinket.ChooseApparitionCombatStyle()
|
|
ElseIf iChoice == 4
|
|
ShowEquipment()
|
|
EndIf
|
|
|
|
bActivationBusy = False
|
|
EndIf
|
|
EndEvent
|
|
|
|
Event OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
|
|
If akBaseItem as Book
|
|
_RegisterSpellBook(Self.GetActorReference(), akBaseItem)
|
|
EndIf
|
|
EndEvent
|
|
|
|
Event OnItemRemoved(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
|
|
If akBaseItem as Book
|
|
Actor akSelf = Self.GetActorReference()
|
|
If akSelf.GetItemCount(akBaseItem) <= 0
|
|
_UnregisterSpellBook(akSelf, akBaseItem)
|
|
EndIf
|
|
EndIf
|
|
EndEvent
|
|
|
|
Event OnLoad()
|
|
bActivationBusy = False ; Safeguard
|
|
_ShowHealthBar()
|
|
EndEvent
|
|
|
|
Event OnDying(Actor akKiller)
|
|
AliasFailsafeRef = None
|
|
EndEvent
|
|
|
|
Event OnDeath(Actor akKiller)
|
|
AliasFailsafeRef = None
|
|
(GetOwningQuest() as _FS_Phasmalist_ControlQuest).UnsummonApparition()
|
|
EndEvent
|
|
|
|
Event OnCombatStateChanged(Actor akTarget, Int aeCombatState)
|
|
If aeCombatState == 1
|
|
_ShowHealthBar()
|
|
EndIf
|
|
EndEvent
|
|
|
|
Event OnUpdate()
|
|
If bTeleportHealRate
|
|
bTeleportHealRate = False
|
|
GetActorReference().ForceActorValue("HealRate", DEFAULT_HEAL_RATE)
|
|
EndIf
|
|
EndEvent
|
|
|
|
EndState
|