Scriptname _00E_Phasmalist_ApparationAlias extends ReferenceAlias { OBSOLETE. Left for backward save compatibility. See _00E_Phasmalist_NewApparitionAlias. } ; on Abilities/_00E_A3_PhasmalistApparation ; script that controls the apparation stats calculation and initialization. Additionally, it is responsible for the control of the apparation 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 apparations, ; which might create memory leaks because of persistence; ; Additionally, temporary or accidental changes do not cumulate ; and lead to problems ; balancing data float Property apparationManaRate = 1 AutoReadOnly Hidden float Property playerStatsMultiplier = 0.20 AutoReadOnly Hidden float Property playerConjSkillMultiplier = 0.10 AutoReadOnly Hidden float Property playerEnchSkillMultiplier = 0.15 AutoReadOnly Hidden float Property fArcaneFeverLevel01 = 7.00 AutoReadOnly Hidden float Property fArcaneFeverLevel02 = 6.00 AutoReadOnly Hidden float Property fArcaneFeverLevel03 = 5.00 AutoReadOnly Hidden int Property fArcaneFeverModWarrior = -1 AutoReadOnly Hidden int Property fArcaneFeverModRanger = 0 AutoReadOnly Hidden int Property fArcaneFeverModHybrid = 0 AutoReadOnly Hidden int Property fArcaneFeverModMage = 1 AutoReadOnly Hidden int Property ghostlyMageBoostDestructionPowerMod1 = 7 AutoReadOnly Hidden int Property ghostlyMageBoostDestructionPowerMod2 = 15 AutoReadOnly Hidden int Property ghostlyMageBoostDestructionPowerMod3 = 25 AutoReadOnly Hidden int Property ghostlyMageBoostMagicka1 = 15 AutoReadOnly Hidden int Property ghostlyMageBoostMagicka2 = 40 AutoReadOnly Hidden int Property ghostlyMageBoostMagicka3 = 75 AutoReadOnly Hidden int Property ghostlyRangerBoostArchery1 = 7 AutoReadOnly Hidden int Property ghostlyRangerBoostArchery2 = 17 AutoReadOnly Hidden int Property ghostlyRangerBoostArchery3 = 30 AutoReadOnly Hidden int Property ghostlyRangerBoostCritChance1 = 7 AutoReadOnly Hidden int Property ghostlyRangerBoostCritChance2 = 15 AutoReadOnly Hidden int Property ghostlyRangerBoostCritChance3 = 25 AutoReadOnly Hidden int Property ghostlyWarriorBoostMelee1 = 7 AutoReadOnly Hidden int Property ghostlyWarriorBoostMelee2 = 17 AutoReadOnly Hidden int Property ghostlyWarriorBoostMelee3 = 30 AutoReadOnly Hidden int Property ghostlyWarriorBoostArmorSkill1 = 7 AutoReadOnly Hidden int Property ghostlyWarriorBoostArmorSkill2 = 17 AutoReadOnly Hidden int Property ghostlyWarriorBoostArmorSkill3 = 30 AutoReadOnly Hidden int Property iCallApparitionKeyCode = 34 Auto Hidden Explosion Property enterWorldExplosion auto Perk Property _00E_Class_Phasmalist_P04_Talent_SummonApparation auto Perk Property _00E_Class_Phasmalist_P04_Talent_SummonApparation2 auto Perk Property _00E_Class_Phasmalist_P04_Talent_SummonApparation3 auto Static Property XMarker Auto Perk Property _00E_Class_Phasmalist_P08a auto Perk[] Property _00E_Class_Phasmalist_P05a_ABC auto ; ghostly mage {ghostly mage perks, this array should have 3 elements for all 3 perks} Perk[] Property _00E_Class_Phasmalist_P05b_ABC auto ; ghostly ranger {ghostly ranger perks, this array should have 3 elements for all 3 perks} Perk[] Property _00E_Class_Phasmalist_P05c_ABC auto ; ghostly warrior {ghostly warrior perks, this array should have 3 elements for all 3 perks} Location Property _00E_Dreamworld_Location auto Keyword Property _00E_Phasmalist_NoSummonLocation auto Message Property _00E_Phasmalist_NoSummoningMessage auto Keyword Property _00E_Phasmalist_NoSummonLocationTown auto Message Property _00E_Phasmalist_CurrentlyEquipped auto Message Property _00E_Phasmalist_NoSummoningMessageTown auto Sound Property MAGAlterationInvisibilityIn Auto Sound Property MAGAlterationInvisibilityOut Auto Perk Property _00E_Class_Phasmalist_P08b auto ; apparations can exist in towns EffectShader Property _00E_Phasmalist_ApparitionShaderFXS Auto ImageSpaceModifier Property _00E_ArkanistenfieberIMOD Auto ImageSpaceModifier Property _00E_Phasmalist_ApparitionEnterWorldIMOD Auto Sound Property _00E_FS_IncreaseArcaneFeverM Auto ;Sound Property _00E_FS_Phasmalist_EnterWorld_Male Auto ;Sound Property _00E_FS_Phasmalist_EnterWorld_Female Auto _00E_GUI_ActorHealthBar Property _ActorHealthBarShower Auto _00E_GUI_ActorHealthBar Property ActorHealthBarShower _00E_GUI_ActorHealthBar Function Get() If (_ActorHealthBarShower == None) _ActorHealthBarShower = Game.GetFormFromFile(0x01024b66, "Enderal - Forgotten Stories.esm") as _00E_GUI_ActorHealthBar EndIf return _ActorHealthBarShower EndFunction EndProperty Message Property _00E_BlitzheilungArkanistenfieber_sFeverIncreased Auto GlobalVariable Property _00E_Phasmalist_IsApparationSummoned Auto Keyword Property _00E_FS_Magic_Summon auto ; the apparation should not be able to learn certain spells Keyword Property _00E_FS_Magic_Mystical auto int currentBoostMagicka ; this is set in adjustBoost() to have the attribute set correctly in the stats calculation _00E_Phasmalist_TrinketSC equippedTrinket Actor Property PlayerREF Auto Formlist Property _00E_AllAmmos Auto ; for a description, look to the function failsaveRefillOnLoad() of this script Actor failsave_content ; functions that are called from the trinkets to keep track of the currently equipped trinket -------------------------------------------------------------------------------------------- function onTrinketEquipped(_00E_Phasmalist_TrinketSC trinket) equippedTrinket = trinket Endfunction function onTrinketUnequipped(_00E_Phasmalist_TrinketSC trinket) unsummonIfExists() If trinket == equippedTrinket equippedTrinket = None EndIf Endfunction _00E_Phasmalist_TrinketSC function getEquippedTrinket() return equippedTrinket Endfunction ; summon and unsummon ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ function unsummon(bool silent = false) {Unsummons the phasmalist apparation content of this alias; should be used instead of delete()} Actor SelfREF = self.GetActorReference() If (!silent) SelfREF.placeAtMe(enterWorldExplosion) addArcaneFever() EndIf ; empty function? ;(SelfREF.getActorBase() as _00E_Phasmalist_ApparationSC).onUnsummon(SelfREF) SelfREF.removeAllItems((SelfREF.GetActorBase() as _00E_Phasmalist_ApparationSC).inventoryContainer, false, true) SelfREF.disable() _00E_Phasmalist_IsApparationSummoned.setValue(0) _RemoveApparationHealthBar() SelfREF.delete() self.clear() failsave_content = None SendModEvent("Phasmalist_ApparationUnSummon") Endfunction function unsummonIfExists() If getRef() unsummon() EndIf Endfunction ; utility functions ---------------------------------------------------------------------------------------------------------------------------------------------------------- Function _RemoveApparationHealthBar() ActorHealthBarShower.RemoveActors(self.getActorReference()) EndFunction Function _AddApparationHealthBar() ActorHealthBarShower.AddActors(self.getActorReference()) EndFunction ; local helper functions --------------------------------------------------------------------------------------------------------------------------------------------------------------- function addArcaneFever() float healthLostPercentage = 0 If self.getActorReference().isDead() healthLostPercentage = 1 Else healthLostPercentage = 1 - self.getActorReference().GetActorValuePercentage("health") EndIf int TalentLevel = _00E_TalentLibrary.GetPlayerTalentLevel(_00E_Class_Phasmalist_P04_Talent_SummonApparation, _00E_Class_Phasmalist_P04_Talent_SummonApparation2, _00E_Class_Phasmalist_P04_Talent_SummonApparation3) float maxArcaneFeverAdd = 0 If (TalentLevel == 1) maxArcaneFeverAdd = fArcaneFeverLevel01 ElseIf (TalentLevel == 2) maxArcaneFeverAdd = fArcaneFeverLevel02 Else maxArcaneFeverAdd = fArcaneFeverLevel03 EndIf If getEquippedTrinket().type == 0 maxArcaneFeverAdd = maxArcaneFeverAdd + fArcaneFeverModWarrior ElseIf getEquippedTrinket().type == 1 maxArcaneFeverAdd = maxArcaneFeverAdd + fArcaneFeverModRanger ElseIf getEquippedTrinket().type == 2 maxArcaneFeverAdd = maxArcaneFeverAdd + fArcaneFeverModMage Else maxArcaneFeverAdd = maxArcaneFeverAdd + fArcaneFeverModHybrid EndIf float arcaneFeverAdd = (maxArcaneFeverAdd * healthLostPercentage) as float If arcaneFeverAdd > 0 PlayerREF.ModAV("LastFlattered", -arcaneFeverAdd) _00E_ArkanistenfieberIMOD.ApplyCrossFade() _00E_FS_IncreaseArcaneFeverM.Play(PlayerREF) _00E_BlitzheilungArkanistenfieber_sFeverIncreased.Show(arcaneFeverAdd, -1*PlayerREF.GetAV("LastFlattered")) EndIf Endfunction function adjustBoosts() adjustBoostPerk(_00E_Class_Phasmalist_P05a_ABC, "mage") adjustBoostPerk(_00E_Class_Phasmalist_P05b_ABC, "ranger") adjustBoostPerk(_00E_Class_Phasmalist_P05c_ABC, "warrior") Endfunction function addClassBoost(int level, string boostClass) Actor referenceActor = self.getActorReference() If boostClass == "mage" int boostDestructionPowerMod = 0 If level == 2 boostDestructionPowerMod = ghostlyMageBoostDestructionPowerMod2 currentBoostMagicka = ghostlyMageBoostMagicka2; since magicka is boosted later again, we have to save this boost and apply it later to prevent overwriting old boosts ElseIf level == 3 boostDestructionPowerMod = ghostlyMageBoostDestructionPowerMod3 currentBoostMagicka = ghostlyMageBoostMagicka3 Else boostDestructionPowerMod = ghostlyMageBoostDestructionPowerMod1 currentBoostMagicka = ghostlyMageBoostMagicka1 EndIf ;referenceActor.ForceAV("DestructionPowerMod", referenceActor.GetAV("DestructionPowerMod") + boostDestructionPowerMod) referenceActor.ModAV("DestructionPowerMod", boostDestructionPowerMod) ElseIf boostClass == "ranger" int boostArchery = 0 int boostCritChance = 0 If level == 2 boostArchery = ghostlyRangerBoostArchery2 boostCritChance = ghostlyRangerBoostCritChance2 ElseIf level == 3 boostArchery = ghostlyRangerBoostArchery3 boostCritChance = ghostlyRangerBoostCritChance3 Else boostArchery = ghostlyRangerBoostArchery1 boostCritChance = ghostlyRangerBoostCritChance1 EndIf ;referenceActor.ForceAV("Marksman", referenceActor.GetAV("Marksman") + boostArchery) referenceActor.ModAV("Marksman", boostArchery) ;referenceActor.ForceAV("CritChance", referenceActor.GetAV("CritChance") + boostCritChance) referenceActor.ModAV("CritChance", boostCritChance) ElseIf boostClass == "warrior" int boostMelee = 0 int boostArmorSkill = 0 If level == 2 boostMelee = ghostlyWarriorBoostMelee2 boostArmorSkill = ghostlyWarriorBoostArmorSkill2 ElseIf level == 3 boostMelee = ghostlyWarriorBoostMelee3 boostArmorSkill = ghostlyWarriorBoostArmorSkill3 Else boostMelee = ghostlyWarriorBoostMelee1 boostArmorSkill = ghostlyWarriorBoostArmorSkill1 EndIf ;referenceActor.ForceAV("HeavyArmor", referenceActor.GetAV("HeavyArmor") + boostArmorSkill) referenceActor.ModAV("HeavyArmor", boostArmorSkill) ;referenceActor.ForceAV("LightArmor", referenceActor.GetAV("LightArmor") + boostArmorSkill) referenceActor.ModAV("LightArmor", boostArmorSkill) ;referenceActor.ForceAV("MeleeDamage", referenceActor.GetAV("MeleeDamage") + boostMelee) referenceActor.ModAV("MeleeDamage", boostMelee) EndIf Endfunction function adjustBoostPerk(Perk[] perks, string boostClass) int i = perks.length While i > 0 i = i - 1 If PlayerREF.HasPerk(perks[i]) addClassBoost(i + 1, boostClass) return EndIf EndWhile Endfunction function init() initBehaviour() initNotPersistentStats() Actor referenceActor = self.getActorReference() ;Actor player = Game.getPlayer() float attributeRaisePercentage = playerConjSkillMultiplier * PlayerREF.getActorValue("Conjuration") + playerEnchSkillMultiplier * PlayerREF.getActorValue("Enchanting") attributeRaisePercentage = attributeRaisePercentage / 100 + 1 adjustBoosts() If (PlayerREF.hasPerk(_00E_Class_Phasmalist_P08a)) float maxAttributeValue = PlayerREF.getBaseActorValue("Health") If PlayerREF.getBaseActorValue("Magicka") > maxAttributeValue maxAttributeValue = PlayerREF.getBaseActorValue("Magicka") EndIf If PlayerREF.getBaseActorValue("Stamina") > maxAttributeValue maxAttributeValue = PlayerREF.getBaseActorValue("Stamina") EndIf referenceActor.ForceAV("Health", ((referenceActor.getBaseActorValue("Health") + maxAttributeValue * playerStatsMultiplier) * attributeRaisePercentage) as int) referenceActor.ForceAV("Magicka", ((referenceActor.getBaseActorValue("Magicka") + maxAttributeValue * playerStatsMultiplier) * attributeRaisePercentage) as int + currentBoostMagicka) referenceActor.ForceAV("Stamina", ((referenceActor.getBaseActorValue("Stamina") + maxAttributeValue * playerStatsMultiplier) * attributeRaisePercentage) as int) Else referenceActor.ForceAV("Health", ((referenceActor.getBaseActorValue("Health") + PlayerREF.getBaseActorValue("Health") * playerStatsMultiplier) * attributeRaisePercentage) as int) referenceActor.ForceAV("Magicka", ((referenceActor.getBaseActorValue("Magicka") + PlayerREF.getBaseActorValue("Magicka") * playerStatsMultiplier) * attributeRaisePercentage) as int + currentBoostMagicka) referenceActor.ForceAV("Stamina", ((referenceActor.getBaseActorValue("Stamina") + PlayerREF.getBaseActorValue("Stamina") * playerStatsMultiplier) * attributeRaisePercentage) as int) EndIf Endfunction function initBehaviour() Actor akSelf = self.getActorReference() If akSelf.GetRelationshipRank(PlayerREF) < 3 && akSelf.GetRelationshipRank(PlayerREF) >= 0 akSelf.SetRelationshipRank(PlayerREF, 3) EndIf akSelf.SetPlayerTeammate() akSelf.SetActorValue("Confidence", 4) ; the apparation should never flee akSelf.SetActorValue("Aggression", 0) ; the apparation should not initiate combat (-> stealth playstyle) akSelf.SetActorValue("Sneak", 100) akSelf.SetActorValue("Invisibility", 1) ; make the apparation undetectable when sneaking (-> stealth playstyle) akSelf.IgnoreFriendlyHits() ; make the apparation ignore friendly fire from the PC Endfunction function initNotPersistentStats() Actor akSelf = self.getActorReference() If akSelf akSelf.getActorBase().setCombatStyle(getEquippedTrinket().getUsedCombatStyle()) akSelf.setAV("HealRate", 50) akSelf.setAV("MagickaRate", apparationManaRate) ;failsafe since setav doesn't work sometimes akSelf.forceAV("HealRate", 50) akSelf.forceAV("MagickaRate", apparationManaRate) _AddApparationHealthBar() EndIf Endfunction ; events ----------------------------------------------------------------------------------------------------------------------------------------------------------- function addSpells() int index = self.getActorReference().getNumItems() - 1 While index >= 0 Form item = self.getActorReference().getNthForm(index) If item as book && !item.hasKeyword(_00E_FS_Magic_Summon) && !item.hasKeyword(_00E_FS_Magic_Mystical) If (item as book).getSpell() self.getActorReference().addSpell((item as book).getSpell()) EndIf EndIf index = index - 1 EndWhile Endfunction