Jump to content

Question on Scripts updating in a savegame


BigBizkit

Recommended Posts

Hi,

 

I have a script X attached to an object in the game. It uses some integer properties set to specific values.

 

Now, I go into the game and run the script (it's OnActivate) and everything works fine. And I save the game.

 

Now, I go into the CK and change some values of the integers, maybe add lines etc. Basically, I edit the script and save.

 

Now, when I load the previous savegame, the script does not seem to be updated. It still treats the integer values as they were set when the savegame "first saw" the mod.

 

 

Is there a way of forcing such scripts to update without having to uninstall and reinstall the mod? I am asking this in relation to my Pirates mod that I am on the verge of updating. I GUESS if there is no other way, I could copy paste the script and objects in question, essentially creating new instances of them.

 

Thanks

Link to comment
Share on other sites

There's a page about that on the CK Wiki, but here's one option for dealing with the problem.

 

Assume you started with this script.

ScriptName SampleScript extends ObjectReference

MiscObject Property RewardObject Auto  ; Object given to player as a reward

int ActivationCount = 0

Event OnActivate(ObjectReference akActionRef)
    if akActionRef == Game.GetPlayer()
        ActivationCount += 1
        if ActivationCount >= 6
            ActivationCount = 0
            Debug.Notification("You are persistent, here's your reward.")
            Game.GetPlayer().AddItem(RewardObject, 1)
        endif
    endif
EndEvent
If you later wanted to give a different reward item then just changing the RewardObject property wouldn't work but changing the code would. You can also change other things defined inside the events and functions (like rewarding after 8 activates instead of 6).

 

ScriptName SampleScript extends ObjectReference

MiscObject Property RewardObject Auto  ; old unused property (removing generates warnings in log)

MiscObject Property NewRewardObject Auto  ; Object given to player as a reward

int ActivationCount = 0

Event OnActivate(ObjectReference akActionRef)
    if akActionRef == Game.GetPlayer()
        ActivationCount += 1
        if ActivationCount >= 8
            ActivationCount = 0
            Debug.Notification("You are persistent, here's your reward.")
            Game.GetPlayer().AddItem(NewRewardObject, 1)
        endif
    endif
EndEvent
New properties will get filled and the code inside functions and events can be changed, but existing properties won't get updated.

 

If you want more detailed advice, you'll have to post actual scripts and describe the changes you want to make.

Link to comment
Share on other sites

Alright, this is my messy yet functional script that generates the encounters at sea.

Scriptname aaTelescope extends ObjectReference  

Message Property aaTelescopeMSGTraders Auto  
Message Property aaTelescopeMSGNothing Auto  
Message Property aaTelescopeMSGRndPirates Auto  
Message Property aaTelescopeMSGIMPERIAL Auto  
Message Property aaTelescopeMSGStormcloaks Auto  
Message Property aaTelescopeMSGKatariah1 Auto  
Message Property aaTelescopeMSGSEASNAKE Auto  
Message Property aaTelescopeMSGNoShips Auto  

GlobalVariable property aaNavalBattleStarted auto
GlobalVariable property aaRerollTimes auto


Objectreference Property XMarkerTraders Auto  
Objectreference Property XMarkerTradersRUM Auto  
Objectreference Property XMarkerTradersGOLD Auto  
Objectreference Property XMarkerTradersCARPETS Auto  
Objectreference Property XMarkerTradersFOOD Auto  

Objectreference Property XMarkerRNDPirates Auto  
Objectreference Property XMarkerRNDPirateGOLD Auto  
actor Property Nalcaryo Auto  
faction property ShipCrewFaction auto

Objectreference Property XMarkerIMPERIAL Auto  
Objectreference Property XMarkerIMPERIALGOLD Auto  

Objectreference Property XMarkerStormcloaks Auto  
Objectreference Property XMarkerStormcloaksFUR Auto  
Objectreference Property XMarkerStormcloaksHEALTH Auto  


Objectreference Property aaXKatariah1 Auto  
Objectreference Property aaXKatariah1LL Auto  
Objectreference Property aaXKatariah1rl Auto  
objectreference property aaXKatariah1MainTreasureMarker auto
Objectreference Property aaXKatariah1TrDiamond auto
Objectreference Property aaXKatariah1TrRAVEN Auto  
Objectreference Property aaXKatariah1TrCROWNfull auto
Objectreference Property aaXKatariah1TrCROWNhalf Auto  
Objectreference Property aaXKatariah1TrMOON auto
Objectreference Property aaXKatariah1TrMajCUP Auto  
Objectreference Property aaXKatariah1TrMajGoblet Auto  

Objectreference Property aaXSeaSnakeMarker Auto  
actor Property Dudecomb Auto  


ImageSpaceModifier Property FadeToBlackImod  Auto  
ImageSpaceModifier Property FadeToBlackHoldImod  Auto  
ImageSpaceModifier Property FadeToBlackBackImod  Auto  

int property SeeNOTHINGchance auto
int property SeeTRADERSchance auto
int property SeeRNDPIRATESchance auto
int property SeeIMPERIALchance auto
int property SeeSTORMCLOAKSchance auto
int property SeeKatariah1chance auto
int property SeeSEASNAKEchance auto



referencealias[] property CrewAlias auto
faction property aaShipCrewFRONTrowFaction auto
objectreference[] property aaXFrontRowMarker auto
Objectreference Property XCaptain Auto  
Objectreference Property XPlayer Auto  

objectreference property aaDoorLower auto
objectreference property aaDoorUpper auto
objectreference property aaDoorBack auto
objectreference property aaDoorCaptain auto

Event OnActivate(ObjectReference akActionRef)

if aaRerollTimes.GetValue() <= 0
aaTelescopeMSGNoShips.Show()

else

if aaNavalBattleStarted.GetValueInt() == 0



        int EnemyShip = Utility.RandomINT(0, 100)





if EnemyShip >= (100 - SeeNothingCHANCE)
    aaTelescopeMSGNothing.Show()                              ; ------------> you see nothing 25%

        aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)



elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance)         ;-----------> you see traders 25%
    int Option = aaTelescopeMSGTraders.Show()      
    if Option == 0                                                                ;-------> attack traders
;    FadeOut ()
    XMarkerTraders.ENable()

        int TraderLoot = Utility.RandomINT(0, 100)
        if TraderLoot >= 75
            XMarkerTradersRUM.ENable()                    ; they have RUM 25%
        elseif TraderLoot >= 50                              ; they have CARPETS 25%
            XMarkerTradersCARPETS.ENable()
        elseif TraderLoot >= 15                                   ; they have FOOD 35%
            XMarkerTradersFOOD.ENable()
        elseif TraderLoot < 15                                   ; they have GOLD 15%
            XMarkerTradersGOLD.ENable()
        endif

BoardingCrew ()

    ;    FadeIn ()
;    Utility.Wait(3.5)
;    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
;    FadeToBlackHoldImod.Remove()
    elseif Option == 1
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)
    endif

elseif EnemyShip >=  (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance)                                     ;-----------> you see RND-Pirates 50%
    int Option = aaTelescopeMSGRndPirates.Show()      
    if Option == 0                                                                ;-------> attack them
;    FadeOut ()
    XMarkerRNDPirates.ENable()
            XMarkerRNDPIrateGold.ENable()  
        int NalcaryoChance = Utility.RandomINT(0, 100)

                    if NalcaryoChance >= 50 && Nalcaryo.IsInFaction(ShipCrewFaction) == 0      ; enable Nalcaryo 50% and only if not in crew, if he is crew, he won't get disabled anyway
                        Nalcaryo.ENable()        
                    endif         

    BoardingCrew ()
   
    ;    FadeIn ()
;    Utility.Wait(3.5)
;    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
;    FadeToBlackHoldImod.Remove()
    elseif Option == 1
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)
    endif

elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance - SeeImperialchance)                                     ;-----------> you see IMPERIALS
    int Option = aaTelescopeMSGIMPERIAL.Show()      
    if Option == 0                                                                ;-------> attack them
;    FadeOut ()
    XMarkerIMPERIAL.ENable()
            XMarkerIMPERIALGold.ENable()  

        BoardingCrew ()

    ;    FadeIn ()


;    Utility.Wait(3.5)
;    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
;    FadeToBlackHoldImod.Remove()
    elseif Option == 1
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)


    endif



;---------------------------------------------------------STORMCLOAKS---------------------------------------------------------



elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance - SeeImperialchance - SeeStormCloaksChance)                                     ;-----------> you see STORMCLOAKS
    int Option = aaTelescopeMSGStormcloaks.Show()      
    if Option == 0                                                                ;-------> attack them
;    FadeOut ()
    XMarkerSTORMCLOAKS.ENable()

        int StormCloakLOOT = Utility.RandomINT(0, 100)
        if StormCloakLOOT >= 50
            XMarkerStormcloaksFUR.ENable()                    
        elseif StormCloakLOOT < 50                              
            XMarkerStormcloaksHEALTH.ENable()
        endif


        BoardingCrew ()

    ;    FadeIn ()


;    Utility.Wait(3.5)
;    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
;    FadeToBlackHoldImod.Remove()
    elseif Option == 1
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)
    endif



;---------------------------------------------------------KATARIAH1---------------------------------------------------------



elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance - SeeImperialchance - SeeStormCloaksChance - SeeKatariah1Chance)                                     ;-----------> you see IMPERIALS
    int Option = aaTelescopeMSGKatariah1.Show()      
    if Option == 0                                                                ;-------> attack them
;    FadeOut ()
    aaXKatariah1.ENable()
    aaXKatariah1LL.ENable()     ;-----------base loot right and left
    aaXKatariah1rL.ENable()
    aaXKatariah1MainTreasureMarker.ENable()
    Utility.Wait(0.1)
    aaXKatariah1MainTreasureMarker.ENable()
    Utility.Wait(0.1)
    aaXKatariah1MainTreasureMarker.ENable()

        int Katariah1 = Utility.RandomINT(1, 6)
        if Katariah1 == 1
            aaXKatariah1TrDiamond.ENable()                    
        elseif Katariah1 == 2
            aaXKatariah1TrRAVEN.ENable()             
        elseif Katariah1 == 3
            aaXKatariah1TrCROWNfull.ENable()    
        elseif Katariah1 == 4
            aaXKatariah1TrCROWNhalf.ENable()    
        elseif Katariah1 == 5
            aaXKatariah1TrMOON.ENable()    
        elseif Katariah1 == 6
            aaXKatariah1TrMajCUP.ENable()           
        elseif Katariah1 == 7
            aaXKatariah1TrMajGoblet.ENable()           
        endif


        BoardingCrew ()

    ;    FadeIn ()


;    Utility.Wait(3.5)
;    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
;    FadeToBlackHoldImod.Remove()
    elseif Option == 1
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)
    endif

;---------------------------------------------------------SEASNAKE---------------------------------------------------------



elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance - SeeImperialchance - SeeStormCloaksChance - SeeKatariah1Chance - SeeSeaSnakeChance)                                     ;-----------> you see IMPERIALS
    int Option = aaTelescopeMSGSeaSnake.Show()      
    if Option == 0                                                                ;-------> attack them
    aaXSeaSnakeMarker.ENable()
        int DudecombChance = Utility.RandomINT(0, 100)

                    if DudecombChance >= 50 && Dudecomb.IsInFaction(ShipCrewFaction) == 0      ; enable Dudecomb 50% and only if not in crew, if he is crew, he won't get disabled anyway
                        Dudecomb.ENable()        
                    endif         

        BoardingCrew ()

    elseif Option == 1 ; there is no other option but ok
    aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)
    endif



endif ;-------------> EnemyShip-check

else                                 ;----------Naval Battle Started
    aaTelescopeMSGNoShips.Show()

endif

endif ; --------> Reroll

EndEvent



Function BoardingCrew ()

    Game.GetPlayer().MoveTo(XCaptain)
    Game.GetPlayer().MoveTo(XPlayer)
    aaNavalBattleStarted.SetValue(1)
    aaDoorLower.Lock()
    aaDoorUpper.Lock()
    aaDoorBack.Lock()
aaDoorCaptain.Lock()

if XMarkerTraders.IsDisabled() == 0 ; if TRADERS

    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index])
            endif
        index += 1
    endwhile

elseif XMarkerRNDPirates.IsDisabled() == 0 ; if PIRATE
    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index+8])
            endif
        index += 1
    endwhile

elseif XMarkerIMPERIAL.IsDisabled() == 0 ; if IMPERIAL
    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index+16])
            endif
        index += 1
    endwhile

elseif XMarkerStormcloaks.IsDisabled() == 0 ; if STORMCLOAKS
    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index+24])
            endif
        index += 1
    endwhile

elseif aaXKatariah1.IsDisabled() == 0 ; if KATARIAH1
    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index+32])
            endif
        index += 1
    endwhile


elseif aaXSeaSnakeMarker.IsDisabled() == 0 ; if SEASNAKE
    int index = 0
    while index < 9
            if CrewAlias[index].GetActorRef().ISInFaction(aaShipCrewFRONTrowFaction)
            CrewAlias[index].GetActorRef().MoveTo(aaXFrontRowMarker[index+24]) ; same as for STORMCLOAKS
            endif
        index += 1
    endwhile

endif

EndFunction




Function FadeOut ()
    aaNavalBattleStarted.SetValue(1)
    FadeToBlackImod.Apply()
    Utility.Wait(1.5)
    FadeToBlackImod.PopTo(FadeToBlackHoldImod)



EndFunction

Function FadeIn ()
    Utility.Wait(2.5)
    FadeToBlackHoldImod.PopTo(FadeToBlackBackImod)
    FadeToBlackHoldImod.Remove()

EndFunction





The annotations about the percentages are outdated, I assure you I have set the "chances" to values that add up to 100.

 

OK let me explain a bit. The EnemyShip roll determines what ship you "see" through the telescope. I use the SeeSOMETHINGChance integer properties there so I could easily adjusts the probabilities by setting the integer properties.

 

The Seasnake encounter is new, every property with Seasnake in it and the part from :

 

;-----------------------------------------------------SEASNAKE---------------------------------------------------------



elseif EnemyShip >= (100 - SeeNothingCHANCE - SeeTRADERSchance - SeeRNDPIRATESchance - SeeImperialchance - SeeStormCloaksChance - SeeKatariah1Chance - SeeSeaSnakeChance)

 

 

..........to the end of the check is newly added.

 

The problem so to speak is, that the savegame remembers the SeeSomethingChance integers as they were set before. All available encounter (SeeSomethingChances) chances in summation are always = 100. When I added the SEASNAKE encounter, I lowered all the other "chances" by 10, and set the new SeasnakeChance to 60 (and it works that way in a "new" savegame). Since the "old" savegame "remembers" the integer properties to be set to the values from before, the condition for the SeaSnake encounter can never be true because the one above will always fire before it.

 

What you said would mean that I could easily circumvent this problem by replacing the SeeSomethingChances with actual numbers. That would mean I had to set them every time I add an encounter manually.

 

That being said, I am pretty sure there is a smarter way to achieve what I was going for (that being x% chance for A, y% chance for b, z% chance for c and x+y+z = 100),

 

edit: I guess if I just use Global Variables instead of the integers, there would not be a problem. That way, users could set them to values they like. Is there a way to prevent that the values in summation become bigger than 100 though? I can only think of a solution pertaining to limiting users to certain presets for the probabilities, rather than them setting the values as they want.

Edited by BigBizkit
Link to comment
Share on other sites

The value of global variables are also stored in the save game file, so that wouldn't help at all. And player's can change script properties from the console so globals really don't have any advantage here.

 

If it's just a matter of getting those values updated, the easy way would be to write a function to change all of those properties to a set of new values when some trigger condition holds true. From that point on you would be making any changes in that function instead of the CK, but the changes would still all be in one easy to find location. You could also use that function as a sanity check to make sure they really do add up to 100 (in case the player changed them through the console) and set them to something sensible.

 

 

So with these properties I would do something like this:

 

...

Function CheckTheEncounterChances()
    ; ensure the chances get new values after the update
    if (SeeSEASNAKEchance == 0) ; see if the new one is unset
        SeeNOTHINGchance = 10
        SeeTRADERSchance = 6
        SeeRNDPIRATESchance = 6
        SeeIMPERIALchance = = 6
        SeeSTORMCLOAKSchance = 6
        SeeKatariah1chance = 6
        SeeSEASNAKEchance = 60  ; that's pretty often
    endif
    ; now make sure everything is set up as a percentage
    int total = SeeNOTHINGchance + SeeTRADERSchance + SeeRNDPIRATESchance + SeeIMPERIALchance + SeeSTORMCLOAKSchance + SeeKatariah1chance + SeeSEASNAKEchance
    if total != 100  ; someone messed up so space them out proportionally
        SeeSEASNAKEchance = 100 * SeeSEASNAKEchance / 100
        SeeTRADERSchance = 100 * SeeTRADERSchance / 100
        SeeRNDPIRATESchance = 100 * SeeRNDPIRATESchance / 100
        SeeIMPERIALchance = 100 * SeeIMPERIALchance / 100
        SeeSTORMCLOAKSchance = 100 * SeeSTORMCLOAKSchance / 100
        SeeKatariah1chance = 100 * SeeKatariah1chance / 100
        SeeNOTHINGchance = 100 - SeeSEASNAKEchance - SeeTRADERSchance - SeeRNDPIRATESchance - SeeIMPERIALchance - SeeSTORMCLOAKSchance - SeeKatariah1chance
        ; the last one gets everything left to avoid rounding error problems
    endif

EndFunction

...


Event OnActivate(ObjectReference akActionRef)

if aaRerollTimes.GetValue() <= 0
    aaTelescopeMSGNoShips.Show()
else
    if aaNavalBattleStarted.GetValueInt() == 0
        int EnemyShip = Utility.RandomINT(0, 100)

        CheckTheEncounterChances()             ;;;;;; This make sure the chances are updated and valid each time

        if EnemyShip >= (100 - SeeNothingCHANCE)
           aaTelescopeMSGNothing.Show()                              ; ------------> you see nothing 25%
           aaRerollTimes.SetValue(aaRerollTimes.GetValue() - 1)


...

Leave the new SeaSnake property unfilled in the CK (or set it to 0) and let the script make the changes when the player next tries to use the telescope.

 

When you decide to add a new variable or change things again it's as easy as adding a new variable that you can check and updating the chances in that section of the code.

 

With the code to scale things to 100 you could even just set the probabilities relative to each other without working out the math.

 

So 1, 1, 1, 2, 2, 3, 5 would be perfectly valid for the 7 changes and get converted to 6, 6, 6, 13, 13, 20, 36. I put the scaling of the Nothing chance last so it could absorb the rounding errors and in this example it would be 3% more likely than it should be but sometimes it could be less likely depending on the combination of numbers used.

Link to comment
Share on other sites

That is some great advice there. Thank you for your efforts.

 

1. So the (start) value for a global I set in the ck is also baked into the save for ever (unless changed via console/script I mean)? Ok.

2. I did not know you could access properties in a script via console. I always used globals for something like that. Good to know.

3. The CheckEncounter Function, especially the first if block is basically my solution for updating. Great.

 

4. Maybe it is because I am tired, but I really don't get the "spacing them out proportionally part". Let's say someone messes up and sets them all to 60, except for the Nothing which they set to 0. The check you are suggesting would still leave all the values at 60, and "nothing" would get set to a negative value. I honestly don't get why you would do 100 * x and then / 100. Doesn't it just cancel itself out(?).

 

Could you elaborate on the spacing out / scaling or rephrase it. I don't get it. You make it out to be the sort of auto-adjusting to each other I am looking for but I fail to understand it yet.

 

bonus question: if properties that were once set in a savegame remain that way, and they are not something that you could fill with code such as integers or globals, that means the property is "doomed"? Like in your first post: if I updated several times and always changed the reward to some other item I'd always have to use a new property? (this does not happen in my mod just asking). Would deleting such old but in the savegame already filled properties (which are not used anymore) cause issues other than warnings?

Edited by BigBizkit
Link to comment
Share on other sites

Sorry, it was late and I mistyped.

Those lines should be dividing by total instead

SeeSEASNAKEchance = 100 * SeeSEASNAKEchance / total

since obviously the way I wrote it did absolutely nothing. :blush:

 

You can remove old properties without doing any real harm, but it generates a one-time warning/error message and some people watch their logs and freak out when they see even that.

Link to comment
Share on other sites

Arrr, much better!

 

Thank you very much for your help. I will make sure to implement the function in the next update.

 

You wouldn't know why apparently for some people sometimes not all the statics linked to a X Marker get enabled. I am 500% sure they are all linked properly and the enable fires. But for some markers it won't enable one particular static or sometimes more than one.

 

It happens e.g. for a vanilla static (ApoStand01 or sth, a static from dragonborn). It works fine for me but I've seen it in both video reviews about the mod so it seems to be an issue.

Edited by BigBizkit
Link to comment
Share on other sites

  • Recently Browsing   0 members

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