cumbrianlad Posted January 5, 2020 Share Posted January 5, 2020 Edit: answered c/o ReDragon2013 That's 'DLC1SeranalevelingScript' Hi. I was going to add levelled spells to a custom animal follower, so I thought I could just copy and alter Serana's script to suit. It's fine but I couldn't understand why each stage removes every spell she's ever had before and then adds the new ones appropriate to that level. To me, that's unnecessary. I get removing the spells that she currently has before adding the new ones if there's no point in her having the old ones. Am I missing something? If so, I'll leave it as it is, except to alter the spell properties and make sure the AddSpell and RemoveSpell functions all have the new properties. If not, I'll remove the 'unnecessary' lines from my script. There's an obvious error in the original, too. She does not have her vampireDrain05 spell removed when it needs to be. I won't be replicating that! I think the unofficial patch people have corrected that.Scriptname DLC1SeranaLevelingScript extends ActorKeyword Property VampireKeyword autoEvent OnInit()RegisterForUpdateGameTime(24)EndEventEvent OnUpdateGameTime()If IsInCombat() == FalseCurrentLevel = GetLevel()If CurrentLevel > LastLevelIf CurrentLevel >= Stage5; currently undefined, set LastLevel to shut downLastLevel = Stage5ElseIf Currentlevel >= Stage4RemoveSpell( crVampireDrain02 )RemoveSpell( crVampireDrain03 )RemoveSpell( crVampireDrain04 )RemoveSpell( crVampireDrain04 )RemoveSpell( RaiseZombieLeftHand )RemoveSpell( ReanimateCorpseLeftHand )RemoveSpell( IceSpikeLeftHand )RemoveSpell( LightningBoltLeftHand )if (HasKeyword(VampireKeyword))AddSpell( crVampireDrain06 )endifAddSpell( RevenantLeftHand )AddSpell( IceStormLeftHand )AddSpell( ChainLightningLeftHand )ElseIf CurrentLevel >= Stage3RemoveSpell( crVampireDrain02 )RemoveSpell( crVampireDrain03 )RemoveSpell( crVampireDrain04 )RemoveSpell( RaiseZombieLeftHand )RemoveSpell( ReanimateCorpseLeftHand )if (HasKeyword(VampireKeyword))AddSpell( crVampireDrain05 )endifAddSpell( LightningBoltLeftHand )AddSpell( RevenantLeftHand)ElseIf CurrentLevel >= Stage2RemoveSpell( crVampireDrain02 )RemoveSpell( crVampireDrain03 )RemoveSpell( RaiseZombieLeftHand )if (HasKeyword(VampireKeyword))AddSpell( crVampireDrain04 )endifAddSpell( LightningBoltLeftHand )ElseIf CurrentLevel >= Stage1RemoveSpell( crVampireDrain02 )RemoveSpell( RaiseZombieLeftHand )if (HasKeyword(VampireKeyword))AddSpell( crVampireDrain03 )endifAddSpell( ReanimateCorpseLeftHand )EndIfLastLevel = CurrentLevelEndIfEndIfEndEventEvent OnCombatStateChange(actor akTarget, int CombatState)if CombatState == 2CurrentHealth = GetActorValue("Health")if CurrentHealth <= 0RestoreActorValue("Health", -CurrentHealth + 1.0)endIfendIfEndEventFloat Property CurrentHealth AutoInt Property CurrentLevel AutoInt Property LastLevel AutoInt Property Stage1 = 20 AutoInt Property Stage2 = 28 AutoInt Property Stage3 = 38 AutoInt Property Stage4 = 48 AutoInt Property Stage5 = 99 AutoSPELL Property crVampireDrain02 AutoSPELL Property crVampireDrain03 AutoSPELL Property crVampireDrain04 AutoSPELL Property crVampireDrain05 AutoSPELL Property crVampireDrain06 AutoSPELL Property IceSpikeLeftHand AutoSPELL Property ReanimateCorpseLeftHand AutoSPELL Property LightningBoltLeftHand AutoSPELL Property RevenantLeftHand AutoSPELL Property IceStormLeftHand AutoSPELL Property ChainLightningLeftHand AutoSPELL Property RaiseZombieLeftHand Auto Link to comment Share on other sites More sharing options...
ReDragon2013 Posted January 5, 2020 Share Posted January 5, 2020 You wrote: "I couldn't understand why each stage removes every spell she's ever had before and then adds the new ones appropriate to that level. To me, that's unnecessary."You are right, its unnecessary. But keep in mind this script is also attached to Harkon and Valerica.Years ago a have rewritten this a bit, maybe useful for you.DLC1SeranaLevelingScript Scriptname DLC1SeranaLevelingScript extends Actor {v1.4 ReDragon 2014} ; handles leveling of spells for Seranas family, new event OnGetUp() ; https://forums.nexusmods.com/index.php?/topic/8291728-looking-for-advice-on-seranas-levelling-script/ Float PROPERTY CurrentHealth auto Hidden Int PROPERTY CurrentLevel auto Hidden Int PROPERTY LastLevel auto Hidden Keyword PROPERTY VampireKeyword auto Spell PROPERTY crVampireDrain02 auto Spell PROPERTY crVampireDrain03 auto Spell PROPERTY crVampireDrain04 auto Spell PROPERTY crVampireDrain05 auto Spell PROPERTY crVampireDrain06 auto Spell PROPERTY IceSpikeLeftHand auto ; 0 is 'DLC1IceSpikeRightHand' Spell PROPERTY RaiseZombieLeftHand auto ; 0 Spell PROPERTY LightningBoltLeftHand auto ; 2 Spell PROPERTY RevenantLeftHand auto ; 3 is 'RevenantRightHand' Spell PROPERTY IceStormLeftHand auto ; 4 is 'DLC1IceStormRightHand' Spell PROPERTY ChainLightningLeftHand auto ; 4 Spell PROPERTY ReanimateCorpseLeftHand auto ; 1 is 'ReanimateCorpseRightHand' *** I change this ; property by my mod "dawnguard_0K_Serana.esp" to new spell 'ReanimateCorpse_Serana' *** ; --- Additional properties because logfile error ------------- Perk PROPERTY AugmentedFrost auto Perk PROPERTY Bladesman60 auto Perk PROPERTY Bladesman90 auto Perk PROPERTY DarkSouls auto Perk PROPERTY HackAndSlash60 auto Perk PROPERTY HackAndSlash90 auto Perk PROPERTY MageArmor30 auto Perk PROPERTY MageArmor50 auto Perk PROPERTY MagicResistance30 auto Perk PROPERTY MagicResistance50 auto Perk PROPERTY Necromancy auto Perk PROPERTY SavageStrike auto Perk PROPERTY WindWalker auto String sn ; Added by ReDragon 2014 ; -- EVENTs -- 5 + "Dead" EVENT OnInit() myF_GetName() Debug.Trace(self+" OnInit() - v1.4 is running for "+sn+", that is level " +self.GetLevel()) ENDEVENT EVENT OnCombatStateChange(Actor akTarget, Int CombatState) ; CombatState will have the following values: ; 2 = searching, ; 1 = in combat, ; 0 = not in combat ; akTarget: "The actor that this actor (on which runs the script) is targeting. ; May be <None> if this actor is leaving combat." IF (CombatState == 2) CurrentHealth = self.GetActorValue("Health") ELSE RETURN ; - STOP - ENDIF ;--------------------- IF (CurrentHealth <= 0) RestoreActorValue("Health", -CurrentHealth + 1.0) ;############# myF_Info(7) ;############# ENDIF ENDEVENT EVENT OnGetUp(ObjectReference akFurniture) IF (CurrentLevel == self.GetLevel()) RETURN ; - STOP - same level ENDIF ;--------------------- ;; Debug.Trace(self+" OnGetUp() - " +sn+ " leaves the furniture " +akFurniture) myF_Spells() ENDEVENT EVENT OnUpdateGameTime() UnRegisterForUpdateGameTime() ; remove old instance, almost vanilla "RegisterForUpdateGameTime(24.0)" IF self.IsDead() ; just in case, if Harkon is already dead gotoState("Dead") ; ### STATE ### // dead // myF_Info(0) ENDIF ENDEVENT EVENT OnDeath(Actor akKiller) ; ### UDGP 2.0.3 ### gotoState("Dead") ; ### STATE ### // dead // Debug.Trace(self+" OnDeath() - Actor was killed by " +akKiller+ " __-| R.I.P. |-__") ENDEVENT ;=============================================== state Dead ;========= EVENT OnGetUp(ObjectReference akFurniture) ENDEVENT ;======= endState ; -- FUNCTIONs -- 7 ;----------------------- FUNCTION myF_Info(Int i) ;----------------------- IF (i == 7) Debug.Trace("DLC1SeranaLevelingScript: Bring " +sn+ " back to life! " +self) RETURN ; - STOP - ENDIF IF (i == 0) Debug.Trace(self+" OnUpdateGameTime() - Actor is already dead! __-| R.I.P. |-__") RETURN ; - STOP - ENDIF IF (i == 1) Debug.Trace(sn+": Updating spells on level " +self.GetLevel()+ " " +self) ;=0= show all valid Spells for this actor ; -------------------------------------------------- Debug.Trace(sn+" 0 IceSpikeLeftHand = " + IceSpikeLeftHand as String) ; 0,1,2,3 Debug.Trace(sn+" 0 RaiseZombieLeftHand = " + RaiseZombieLeftHand as String) Debug.Trace(sn+" 0 crVampireDrain02 = " + crVampireDrain02 as String) Debug.Trace(sn+" 1 ReanimateCorpseLeftHand = " + ReanimateCorpseLeftHand as String) ; 1,2 Debug.Trace(sn+" 1 crVampireDrain03 = " + crVampireDrain03 as String) Debug.Trace(sn+" 2 LightningBoltLeftHand = " + LightningBoltLeftHand as String) ; 2,3 Debug.Trace(sn+" 2 crVampireDrain04 = " + crVampireDrain04 as String) Debug.Trace(sn+" 3 RevenantLeftHand = " + RevenantLeftHand as String) ; 3,4 Debug.Trace(sn+" 3 crVampireDrain05 = " + crVampireDrain05 as String) Debug.Trace(sn+" 4 IceStormLeftHand = " + IceStormLeftHand as String) Debug.Trace(sn+" 4 ChainLightningLeftHand = " + ChainLightningLeftHand as String) Debug.Trace(sn+" 4 crVampireDrain06 = " + crVampireDrain06 as String) ENDIF ENDFUNCTION ;-------------------------------- Bool FUNCTION myF_IsBad(Spell sp) ;-------------------------------- RETURN ((sp as String) == "None") || ((sp as String) == "[SPELL <None>]") ; best way to avoid logfile errors ENDFUNCTION ;------------------------------- FUNCTION myF_TryASpell(Spell sp) ; -- ADD -- ;------------------------------- IF myF_IsBad(sp) Debug.Trace(sn+" won't add invalid spell, {" + sp + "}") RETURN ; - STOP - ENDIF ;--------------------- bool bOk = AddSpell(sp) IF ( bOK ) Debug.Trace(sn+" " +sp+ " has been added.") ELSE Debug.Trace(sn+" has this " +sp+ " already.") ENDIF ENDFUNCTION ;------------------------------- FUNCTION myF_TrySpellR(Spell sp) ; -- REMOVE -- ;------------------------------- IF myF_IsBad(sp) ;; Debug.Trace(sn+" cannot remove invalid spell, {" + sp + "} " + self) RETURN ; - STOP - ENDIF ;--------------------- bool bOk = RemoveSpell(sp) IF ( bOK ) Debug.Trace(sn+" " +sp+ " has been removed.") ENDIF ENDFUNCTION ; script ;Actor Serana ; Game.GetForm(0x02002B6C) DLC1SeranaRef [02002B74] ;Actor Harkon ; Game.GetForm(0x02003BA7) DLC1HarkonRef [02003BA8] ;Actor Valerica ; Game.GetForm(0x02003B8B) DLC1ValericaRef [02003B8E] ;--------------------- FUNCTION myF_GetName() ;--------------------- int i = self.GetFormID() ; for example: i = 0x02002B74 int p = 0 WHILE (i > 0x00010000) i -= 0x01000000 ; 0x(02)002B74 - 0x(01)000000 = 0x(01)002B74, etc. p = p + 1 ENDWHILE ;;; p = p * 0x01000000 ; actual position of dawnguard.esm in Skyrim load order IF (i == 0x00002B74) sn = "Serana" ELSEIF (i == 0x00003BA8) sn = "Harkon" ELSEIF (i == 0x00003B8E) sn = "Valerica" ELSE sn = "unknown" ENDIF ENDFUNCTION ;----------------------- Bool FUNCTION myF_Wait() ;----------------------- IF (sn == "") myF_GetName() ; if OnInit() goes fail ENDIF int i = 10 WHILE (i > 0) i = i - 1 IF (self.GetBaseObject() == None) || self.IsDead() Return False ENDIF ; ---------- IF !self.Is3DLoaded() Utility.Wait(2.0) ELSEIF Game.GetPlayer().IsInCombat() || self.IsInCombat() Utility.Wait(12.0) i = i + 1 ELSE IF (sn == "Serana") Utility.Wait(1.0) ; a little pause, so we have no overlap in debug output ELSEIF (sn == "Harkon") Utility.Wait(2.0) ELSEIF (sn == "Valerica") Utility.Wait(3.0) ENDIF myF_Info(1) Return TRUE ENDIF ; ---------- ENDWHILE Return False ENDFUNCTION Int PROPERTY Stage1 = 20 auto Int PROPERTY Stage2 = 28 auto Int PROPERTY Stage3 = 38 auto Int PROPERTY Stage4 = 48 auto Int PROPERTY Stage5 = 99 auto ;-------------------- FUNCTION myF_Spells() ;-------------------- IF (LastLevel == -1) RETURN ; - STOP - ENDIF LastLevel = -1 ; ThreadLock ON ;------------------------------------------- IF !myF_Wait() LastLevel = currentLevel ; OFF RETURN ; - STOP - ENDIF CurrentLevel = self.GetLevel() ; Do not forget this !!! ;------------------------- ;=1= add the spells depends on level of NPC ; -------------------------------------------------- spell spVampDrain int iStage IF ( CurrentLevel < Stage1 ) ; level 1..19 spVampDrain = crVampireDrain02 iStage = 0 myF_TryASpell(RaiseZombieLeftHand) ; 0 ; ---------------------------------------------------- ELSEIF ( CurrentLevel < Stage2 ) ; level 20..27 spVampDrain = crVampireDrain03 iStage = 1 myF_TryASpell(ReanimateCorpseLeftHand) ; 1 ; ---------------------------------------------------- ELSEIF ( CurrentLevel < Stage3 ) ; level 28..37 spVampDrain = crVampireDrain04 iStage = 2 myF_TryASpell(ReanimateCorpseLeftHand) ; 1 myF_TryASpell(LightningBoltLeftHand) ; 2 ; ---------------------------------------------------- ELSEIF ( CurrentLevel < Stage4 ) ; level 38..47 spVampDrain = crVampireDrain05 iStage = 3 myF_TryASpell(LightningBoltLeftHand) ; 2 myF_TryASpell(RevenantLeftHand) ; 3 ; ---------------------------------------------------- ELSE ;IF ( CurrentLevel < Stage5 ) ; level 48..98 spVampDrain = crVampireDrain06 iStage = 4 myF_TryASpell(RevenantLeftHand) ; 3 myF_TryASpell(IceStormLeftHand) ; 4 myF_TryASpell(ChainLightningLeftHand) ; 4 ;IF( CurrentLevel >= Stage5 ) ; level 99+ currently no action, shutdown only ;ENDIF ENDIF ;=2= remove non vampire spells depends on level ; ---------------------------------------------------- IF (iStage > 0) myF_TrySpellR( RaiseZombieLeftHand ) ; 0 ENDIF IF (iStage < 1) || (iStage > 2) myF_TrySpellR( ReanimateCorpseLeftHand ) ; 1+2 ENDIF IF (iStage < 2) || (iStage > 3) myF_TrySpellR( LightningBoltLeftHand ) ; 2+3 ENDIF IF (iStage < 3) myF_TrySpellR( RevenantLeftHand ) ; 3+4 ENDIF IF (iStage < 4) myF_TrySpellR( IceStormLeftHand ) ; 4 myF_TrySpellR( ChainLightningLeftHand ) ; 4 ENDIF ;=3= remove/add vampireDrain spells depends on level ; ---------------------------------------------------- IF (spVampDrain) && self.HasKeyword(VampireKeyword) IF (iStage != 0) myF_TrySpellR( crVampireDrain02 ) ; 02 ENDIF IF (iStage != 1) myF_TrySpellR( crVampireDrain03 ) ; 03 ENDIF IF (iStage != 2) myF_TrySpellR( crVampireDrain04 ) ; 04 ENDIF IF (iStage != 3) myF_TrySpellR( crVampireDrain05 ) ; 05 ENDIF IF (iStage != 4) myF_TrySpellR( crVampireDrain06 ) ; 06 ENDIF Utility.Wait(0.1) myF_TryASpell(spVampDrain) ENDIF ;=4= remove/add the iceSpike spell with special condition ; ---------------------------------------------------- myF_TrySpellR( Game.GetForm(0x000c969c) as Spell ) ; IceSpikeRightHand // only Serana should be affected from that IF ( iStage < 4 ) ; if level below 48 then try to add spell "IceSpike" taken from properties myF_TryASpell(IceSpikeLeftHand) ELSE myF_TrySpellR( IceSpikeLeftHand ) ; elseif level is greater than 48 remove the spell if having ENDIF LastLevel = CurrentLevel ; OFF ENDFUNCTION Additional information taken from CK for these three NPC on that this script should run only Harkon as DLC1Harkon PROPERTIES ------ 0 IceSpikeLeftHand = None ; do not add this spell here 0 RaiseZombieLeftHand = RaiseZombieLeftHand (000C969E) 1 ReanimateCorpseLeftHand = ReanimateCorpseLeftHand (000CAB65) 2 LightningBoltLeftHand = None 3 RevenantLeftHand = RevenantLeftHand (000CAB66) 4 ChainLightningLeftHand = None 4 IceStormLeftHand = None crVampireDrain02 = DLC1HarkonDrain02Alt (0201A938) * r crVampireDrain03 = DLC1HarkonDrain03Alt (0201A939) * rightHand all 5 Drain spells crVampireDrain04 = DLC1HarkonDrain04Alt (0201A93A) * r crVampireDrain05 = DLC1HarkonDrain05Alt (0201A93B) * r crVampireDrain06 = DLC1HarkonDrain06Alt (0201A93C) * r Valerica as DLC1Valerica -------- 0 IceSpikeLeftHand = IceSpikeLeftHand (00040000) (default spell on start) 0 RaiseZombieLeftHand = RaiseZombieLeftHand (000C969E) (def.) 1 ReanimateCorpseLeftHand = ReanimateCorpseLeftHand (000CAB65) 2 LightningBoltLeftHand = LightningBoltLeftHand (000400AB) 3 RevenantLeftHand = RevenantLeftHand (000CAB66) 4 ChainLightningLeftHand = ChainLightningLeftHand (0007D99C) 4 IceStormLeftHand = IceStormLeftHand (000A1992) crVampireDrain02 = crVampireDrain02 (000F5B59) crVampireDrain03 = crVampireDrain03 (000F5B5A) leftHand all 5 Drain spells crVampireDrain04 = crVampireDrain04 (000F5B5B) crVampireDrain05 = crVampireDrain05 (0008D5C3) crVampireDrain06 = crVampireDrain06 (0008D5C7) Serana as DLC1Serana ------ 0 by Default = IceSpikeRightHand sp = Game.GetForm(0x000c969c) as Spell *** removed in script *** 0 IceSpikeLeftHand = DLC1IceSpikeRightHand (02014CC5) * r DLC1 (script property) 0 RaiseZombieLeftHand .= DLC1RaiseZombieRightHand (02011F35) * r DLC1 1 ReanimateCorpseLeftHand = ReanimateCorpseRightHand (0010105F) * r (ReanimateCorpse_Serana leftHand) 2 LightningBoltLeftHand .= LightningBoltRightHand (000C96A2) * r 3 RevenantLeftHand .= RevenantRightHand (00101060) * r 4 ChainLightningLeftHand .= ChainLightningLeftHand (0007D99C) 4 IceStormLeftHand .= DLC1IceStormRightHand (02014CC6) * r DLC1 crVampireDrain01 = DLC1SeranaDrain01 (02011F33) *** special for curing, probably *** crVampireDrain02 = DLC1SeranaDrain02 (02011F32) leftHand all 6 Drain spells crVampireDrain03 = DLC1SeranaDrain03 (02011F31) crVampireDrain04 = DLC1SeranaDrain04 (02011F30) crVampireDrain05 = DLC1SeranaDrain05 (02011F2F) crVampireDrain06 = DLC1SeranaDrain06 (02011F2C) MagicEffects for my new spell "ReanimateCorpse_Serana" to make different reanimate corpse between Serana and other NPCs ReanimateFFTargetActor25_Serana Hit Effect Art = Reanimate TargetFX Hit Shader = ReanimateFXShader (default) -> GhostFXShader -> LifeDetectedUndead ReanimateSeconadryTargetActor_Serana Hit Shader = GhostWolfSpiritFXShader Link to comment Share on other sites More sharing options...
cumbrianlad Posted January 5, 2020 Author Share Posted January 5, 2020 ReDragon2013, thanks ever so much for that! I will now happily remove the extra lines from my script. The scripts you attached were useful, not least that on reading them, I realised that I could do with adding some perk properties, so that my actor (a Dwarven 'stealth' spider) can have the 'crExtraDamage' perks as it levels up. Link to comment Share on other sites More sharing options...
Recommended Posts