Jump to content

New idea for FXDustDropRandomScript by Inki


VaultDuke

Recommended Posts

(I'm posting this here because Inki wanted to get the word around, but had no time to pursue the idea any further himself. Maybe this is interesting for the script gurus around here)

Once upon a time I took a closer look at the good old FXDustDropRandomScript and noticed something minor but curious, which might be worth mentioning once, as it may be unlikely, that many people would notice it.
 
It would seem that duster animations fail, if the one, that has been most recently run, is repeated, which sometimes occurs when they are fully randomized.
 
Perhaps some animation wizard might be able to address this somehow directly at the source, but in my personal version of the script, I decided to work around it. That script is included below as an example of one way to address the issue, although I am sure you might do it differently, were you to consider it an issue worth addressing in the first place. Note 3) in the script's comments is the relevant one.

Scriptname FXDustDropRandomScript extends ObjectReference

Sound property MySFX auto
Explosion property FallingDustExplosion01 auto

EVENT OnCellAttach()
    RegisterForSingleUpdate(Utility.RandomFloat(10.0, 30.0))    ; Note 1a)
    GoToState("A")                            ; Note 2)
endEVENT

EVENT OnUpdate()
    bool Was3 = IsActivationBlocked()                ; Note 3), Note 4)
    int RndI = Utility.RandomInt(0,2)                ; Note 4)
    if Is3DLoaded()                            ; Note 5)
        MySFX.Play(Self)
        if RndI
            if Was3
                PlayAnimation("PlayAnim02")
                BlockActivation(False)
            else
                PlayAnimation("PlayAnim03")
                BlockActivation(True)
            endif
        else
            PlayAnimation("PlayAnim01")
            Utility.Wait(0.5)
            PlaceAtMe(FallingDustExplosion01)
            Utility.Wait(3.0)
            PlayAnimation("PlayAnim02")
            BlockActivation(False)
        endif
        float RndF = Utility.RandomFloat(10.0, 30.0)        ; Note 1b)
        if GetState()
            RegisterForSingleUpdate(RndF)
        endif
    endif
endEVENT

EVENT OnCellDetach()
    if GetState()
    else                                ; Note 6)
        int M = 10
        while M
            Utility.Wait(0.2)
            if GetState()
                M = 0
            else
                M -= 1
            endif
        endwhile
    endif
    GoToState("")
    UnregisterForUpdate()
endEVENT


;/ Comments

Note 1)    Just in case Utility.RandomFloat() might (very) theoretically be a latent function call,
    this ordering of instructions ensures, that there is absolutely zero chance of anything
    intervening between state checking/changing and update registering, even if it means,
    that Utility.RandomFloat() gets called once unnecessarily when re-registering ceases (1b).
Note 2)    State "A" is used to indicate, that the duster is active and running. A script variable
    could be used instead, but using the state variable avoids storing an additional variable
    at each    script instance. For the same reason, use is made of the BlockActivation flag,
    as it is available. The benefit from this is admittedly almost infinitesimal, so it is
    ultimately a question of style and preference. In a script optimized with the papyrus
    assembly language, there is no efficiency downside to using the state variable, which
    normally is accessed through function calls, even if they are relatively fast and efficient.
Note 3)    The BlockActivation flag is used to store information about whether the last animation run
    ended with "PlayAnim02" or "PlayAnim03", so it can be avoided at the start of the next run.
    Apparently, these animations fail, when the last one to have been previously run is repeated,
    for whatever reason that might be. The thinking here is, that we still wish to have the
    more complicated animation sequence occurring in one case out of three, even if then in two
    cases out of three, the appropriate animation is pre-determined by the previous run.
Note 4)    There are many ways to sequence actions here. This sequencing, where Was3 and RndI are
    evaluated separately at the beginning, allows for a single occurrance in the script of
    Is3DLoaded() immediately followed by Play(), which again is almost immediately followed by
    PlayAnimation() calls without any delayed function calls in between.
    As a side effect, Was3 may get evaluated unnecessarily in one case out of three.
Note 5)    If Is3DLoaded() returns False, the script becomes passive, as re-registration ceases. However,
    unlike in the corresponding USKP script, the state variable is not adjusted to reflect this.
    That allows the eventual OnCellDetach() event, which expects the script to be in the "A" state
    to be processed efficiently along its default branch. See also the following note.
Note 6) When OnCellDetach() is called, the script should normally be in the active "A" state due to
    a previous OnCellAttach() call. If this is not so, then just in case a rapid succession of
    OnCellAttch() and OnCellDetach() calls may have become out of sequence, for whatever reason,
    the script waits up to 2 seconds to see if an active state will emerge, which it will then
    shut down. This is most likely pure overcaution, but you never know...


Otimized Papyrus Assembler version:

.info
    .source ""
    .modifyTime 0
    .compileTime 0
    .user ""
    .computer ""
.endInfo
.userFlagsRef
    .flag conditional 1
    .flag hidden 0
.endUserFlagsRef
.objectTable
    .object fxdustdroprandomscript ObjectReference
        .userFlags 0
        .docString ""
        .autoState
        .variableTable
            .variable ::MySFX_var Sound
                .userFlags 0
                .initialValue None
            .endVariable
            .variable ::FallingDustExplosion01_var Explosion
                .userFlags 0
                .initialValue None
            .endVariable
        .endVariableTable
        .propertyTable
            .property MySFX Sound auto
                .userFlags 0
                .docString ""
                .autoVar ::MySFX_var
            .endProperty
            .property FallingDustExplosion01 Explosion auto
                .userFlags 0
                .docString ""
                .autoVar ::FallingDustExplosion01_var
            .endProperty
        .endPropertyTable
        .stateTable
            .state
                .function OnCellAttach
                    .userFlags 0
                    .docString ""
                    .return None
                    .paramTable
                    .endParamTable
                    .localTable
                        .local RndF Float
                        .local Null None
                    .endLocalTable
                    .code
                        CallStatic Utility RandomFloat RndF 10.0 30.0
                        CallMethod RegisterForSingleUpdate Self Null RndF
                        Assign ::State "A"
                    .endCode
                .endFunction
                .function OnUpdate
                    .userFlags 0
                    .docString ""
                    .return None
                    .paramTable
                    .endParamTable
                    .localTable
                        .local Base Form
                        .local ORef ObjectReference
                        .local RndF Float
                        .local RndI Int
                        .local Dmmy Int
                        .local Was3 Bool
                        .local Test Bool
                        .local Null None
                    .endLocalTable
                    .code
                        CallMethod IsActivationBlocked Self Was3
                        CallStatic Utility RandomInt RndI 0 2
                        CallMethod Is3DLoaded Self Test
                        JumpF Test _label24
                        Cast ORef Self
                        CallMethod Play ::MySFX_var Dmmy ORef
                        JumpF RndI _label21
                        JumpT Was3 _label22
                        CallMethod PlayAnimation Self Test "PlayAnim03"
                        CallMethod BlockActivation Self Null True
                        Jump _label23
                    _label21:
                        CallMethod PlayAnimation Self Test "PlayAnim01"
                        CallStatic Utility Wait Null 0.5
                        Cast Base ::FallingDustExplosion01_var
                        CallMethod PlaceAtMe Self ORef Base 1 False False
                        CallStatic Utility Wait Null 3.0
                    _label22:
                        CallMethod PlayAnimation Self Test "PlayAnim02"
                        CallMethod BlockActivation Self Null False
                    _label23:
                        CallStatic Utility RandomFloat RndF 10.0 30.0
                        JumpF ::State _label24
                        CallMethod RegisterForSingleUpdate Self Null RndF
                    _label24:
                    .endCode
                .endFunction
                .function OnCellDetach
                    .userFlags 0
                    .docString ""
                    .return None
                    .paramTable
                    .endParamTable
                    .localTable
                        .local M Int
                        .local Test Bool
                        .local Null None
                    .endLocalTable
                    .code
                    _label31:
                        JumpT ::State _label32
                        CallStatic Utility Wait Null 0.2
                        IAdd M M 1
                        CompareGTE Test M 10
                        JumpF Test _label31
                    _label32:
                        Assign ::State ""
                        CallMethod UnregisterForUpdate Self Null
                    .endCode
                .endFunction
            .endState
        .endStateTable
    .endObject
.endObjectTable

/;

 
And sorry for the rather lengthy code, but for the sake of full disclosure, I decided not to strip out the optimized Papyrus Assembler version, which is the one I actually use. (I sometimes tend to do this, if I dabble with minor scripts, that are widely applied.)

 

original post: http://forums.bethsoft.com/topic/1497829-relz-unofficial-skyrim-patch-thread-41/?p=23636646

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...