VaultDuke Posted May 28, 2014 Share Posted May 28, 2014 (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 ObjectReferenceSound property MySFX autoExplosion property FallingDustExplosion01 autoEVENT OnCellAttach() RegisterForSingleUpdate(Utility.RandomFloat(10.0, 30.0)) ; Note 1a) GoToState("A") ; Note 2)endEVENTEVENT 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 endifendEVENTEVENT 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;/ CommentsNote 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now