Jump to content

[LE] Looking for advice on Serana's Levelling script.


Recommended Posts

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 Actor


Keyword Property VampireKeyword auto

Event OnInit()
RegisterForUpdateGameTime(24)
EndEvent

Event OnUpdateGameTime()
If IsInCombat() == False
CurrentLevel = GetLevel()
If CurrentLevel > LastLevel
If CurrentLevel >= Stage5
; currently undefined, set LastLevel to shut down
LastLevel = Stage5
ElseIf Currentlevel >= Stage4
RemoveSpell( crVampireDrain02 )
RemoveSpell( crVampireDrain03 )
RemoveSpell( crVampireDrain04 )
RemoveSpell( crVampireDrain04 )
RemoveSpell( RaiseZombieLeftHand )
RemoveSpell( ReanimateCorpseLeftHand )
RemoveSpell( IceSpikeLeftHand )
RemoveSpell( LightningBoltLeftHand )

if (HasKeyword(VampireKeyword))
AddSpell( crVampireDrain06 )
endif
AddSpell( RevenantLeftHand )
AddSpell( IceStormLeftHand )
AddSpell( ChainLightningLeftHand )

ElseIf CurrentLevel >= Stage3
RemoveSpell( crVampireDrain02 )
RemoveSpell( crVampireDrain03 )
RemoveSpell( crVampireDrain04 )
RemoveSpell( RaiseZombieLeftHand )
RemoveSpell( ReanimateCorpseLeftHand )

if (HasKeyword(VampireKeyword))
AddSpell( crVampireDrain05 )
endif
AddSpell( LightningBoltLeftHand )
AddSpell( RevenantLeftHand)

ElseIf CurrentLevel >= Stage2
RemoveSpell( crVampireDrain02 )
RemoveSpell( crVampireDrain03 )
RemoveSpell( RaiseZombieLeftHand )

if (HasKeyword(VampireKeyword))
AddSpell( crVampireDrain04 )
endif
AddSpell( LightningBoltLeftHand )

ElseIf CurrentLevel >= Stage1
RemoveSpell( crVampireDrain02 )
RemoveSpell( RaiseZombieLeftHand )

if (HasKeyword(VampireKeyword))
AddSpell( crVampireDrain03 )
endif
AddSpell( ReanimateCorpseLeftHand )

EndIf
LastLevel = CurrentLevel
EndIf
EndIf
EndEvent

Event OnCombatStateChange(actor akTarget, int CombatState)
if CombatState == 2
CurrentHealth = GetActorValue("Health")
if CurrentHealth <= 0
RestoreActorValue("Health", -CurrentHealth + 1.0)
endIf
endIf
EndEvent

Float Property CurrentHealth Auto
Int Property CurrentLevel Auto
Int Property LastLevel Auto

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

SPELL Property crVampireDrain02 Auto
SPELL Property crVampireDrain03 Auto
SPELL Property crVampireDrain04 Auto
SPELL Property crVampireDrain05 Auto
SPELL Property crVampireDrain06 Auto

SPELL Property IceSpikeLeftHand Auto
SPELL Property ReanimateCorpseLeftHand Auto
SPELL Property LightningBoltLeftHand Auto
SPELL Property RevenantLeftHand Auto
SPELL Property IceStormLeftHand Auto
SPELL Property ChainLightningLeftHand Auto
SPELL Property RaiseZombieLeftHand Auto

 

Link to comment
Share on other sites

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

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...