xNVSE / NVSE

New Vegas Script Extender (NVSE)
https://git.io/JfSAo
712 stars 56 forks source link

SetScript seems to be broken. #12

Closed DuskWulf closed 3 years ago

DuskWulf commented 3 years ago

When setting SetScript on the base object of a creature that has a unique reference, the code runs when introduced to a clean game (either a save that hasn't seen that mod yet or a new game), but if one saves, closes the game, then reloads the script is no longer set on the actor.

Here's my use case in an initialisation script tied to a quest that starts enabled:

    If GetGameRestarted
        SetScript INHIBPrimmPowderGangerOverrideSCRIPT, PrimmPowderGangerOutside
        SetScript INHIBPrimmPowderGangerOverrideSCRIPT, LvlPowderGangerGunNVBisonSteve01
        SetScript INHIBPrimmPowderGangerOverrideSCRIPT, LvlPowderGangerNVBisonSteve01Sleeping
        SetScript INHIBPrimmPowderGangerOverrideSCRIPT, LvlPowderGangerNVBisonSteve01Flamer
        SetScript INHIBPrimmPowderGangerOverrideSCRIPT, PrimmPowderGangerRifle
    EndIf

And here's the script that's being set:

scn INHIBPrimmPowderGangerOverrideSCRIPT

short noCount
short maxDone

BEGIN OnLoad
    Print "Testing OnLoad."

    If GetDead == 1
        Disable

    ElseIf nvPrimmDeputyConv.iTownState == 1
        Let noCount := 1

        Kill
    EndIf

    If maxDone == 0
        Print "maxDone 0"

        If IsInInterior == 1
            Print "Interior +1"

            Let INHIBOnUpdateQUEST.primmCleanupInsideMax += 1

            Let maxDone := 1

        Else
            Print "Exterior +1"

            Let  INHIBOnUpdateQUEST.primmCleanupOutsideMax += 1

            Let maxDone := 1
        EndIf
    EndIf
END

BEGIN OnDeath
    Print "Testing OnDeath."

    If noCount == 0
        If IsInInterior == 1
            Let INHIBOnUpdateQUEST.primmCleanupInsideCount += 1

        Else
            Let  INHIBOnUpdateQUEST.primmCleanupOutsideCount += 1
        EndIf
    EndIf
END

BEGIN GameMode
   Print "Testing GameMode."
END

On the clean load the script functions perfectly, it does all that it's intended to do and shows the prints. However, post-reload, not even the prints work. It's as though the actors are using their original scripts and not the one that it's supposed to be replaced by.

I read in one thread that SetScript was broken in NVSE v4.5-ish so I don't know what's causing my problem. I created a thread on Nexus Mods about it and it was suggested that I raise an issue here to see if this is a problem with NVSE itself still.

Sorry to be a bother.

Edit:

I've been investigating this since I want to be as much help as I can if I'm going to ask for help. So here's what I have...

Clean save: Everything works okay. Reload, walk to Primm: Works rarely. Reload, fast travel to Primm. Works rarely. Reload, coc to Primm: Never works.

Here's where it gets interesting...

Start the game, get to Primm (via any means), save in Primm, load save... Everything works??? Close game, restart game, load Primm save... Nothing works. Reload Primm save... Works????

Okay, I... What? I think... Is it only setting the scripts after the actors have loaded but only if the save isn't clean/reloaded? That seems to be the behaviour I'm observing, I think? I'm pretty new to this so I can't say for sure but... that fits the evidence, maybe????

So if you're introducing the code to a clean save or reloading the game after the game has already started then everything works, but on a fresh load that isn't a clean save it only sets the scripts after the actors have loaded????

???

This is all I have for you. This is weird. My mod Full and Empty exhibits the same behaviour with milkable brahmin as well since I use SetScript there too, if you want something to test for yourself.

Eidt:

Of course, I'm making an assumption there. It could be that on first load of a non-clean save it simply does nothing, not that it only works on actors that have loaded. It might just do nothing, that's just a hunch.

To fix this, I'd say look into what's happening when loading a saved game which isn't clean. So use Full and Empty as an example and stand near some brahmin. You'll see this...

First load in clean: Milkable brahmin. Close game, start game, new load in not clean: Non-milkable brahmin. Any new load ins: Non-milkable brahmin. Load in, then reload the same save: Milkable brahmin.

Edit:

Using excessive saves, loads, clean saves, and so, so many debug prints I may have another theory but... I'm tired, confused, and without knowing how it works I can only guess.

When SetScript is called, it stores that exact script into the save. If the game is saved, closed, the script is updated, and the game opened and loaded, for the most part it won't update the script. Sometimes, on the load of a save, for some reason, it will. This means that even though the script in the mod is changed and new, the one used by SetScript isn't that script.

A breakthrough with this happened when I was using debug prints and I had a "Wait a minute, that debug print isn't worded that way right now." I quickly loaded up my esp in notepad (the quickest way for me to check without waiting for FNVEdit/GECK to load, don't judge) and checked the script. It was updated in my mod but not in the game. That means that SetScript seems to take a copy of the script, store it in the save, then not update it?

I guess???

I don't know if any of this is helpful, only that SetScript isn't behaving properly.

korri123 commented 3 years ago

Could you hand me a save file (.fos and .nvse), an .esp where everything has been stripped except script code that is functioning incorrectly and instructions on how I can repeat the bug? Thanks.

DuskWulf commented 3 years ago

Sure! I'll set that up and get that to you.

DuskWulf commented 3 years ago

PrimmProblems.zip

Objects loaded for this save:

FalloutNV.esm PrimmRep.esp

Kept it to the bare minimum. This is a testing character, barely out the gate. You could likely test this with a new save.

I cleaned up the esp, made it presentable and cut it down to just what you'd need to avoid overload regarding extraneous stuff. It still exhibits the same problem. Basically, I'm trying to script a Primm reputation system and the major hurdle is the SetScript issue.

To reproduce:

Sorry this took so long. I wanted to get it down to pretty much exactly what it should be so it serves as a proper example of the problem.

korri123 commented 3 years ago

Hi, thanks for providing the .zip.

The problem stems from you updating the script of a base form from which placed references have already been created from. When the GetGameRestarted block gets run, all the references have already been created from the base forms you're updating, so they retain the original scripts until the game loads again.

You have two options here:

DuskWulf commented 3 years ago

I'll try MenuMode 4, thanks!

Edited:

That did it! THANK YOU! You're very clever and I appreciate it. Yeah, I get what you're saying about how it works but I figured because it worked on my clean save it'd work anyway, when it started not working it baffled me. I guess that was just a blip.

The way you've explained it, and the example you gave? Yes. Thank you! That worked perfectly and I understand why. I really appreciate that, really do. There's a big project I'm working on that's very important to me (for my partner, though I will be dropping it on the Nexus when it's done) so I would've been devastated to have a setback when I'm this close to being done with it.

Thank you very much!!

If I might make a suggestion? I can't edit the GECK Wiki, but this might be good information to have on the SetScript article. Both your explanation and the suggestion of MenuMode 4.

Anyway, you rock.

korri123 commented 3 years ago

Glad it worked out! I already added the info to the wiki on the SetScript article :) (see the warnings section)

Good luck with your mod.