xyz3lt Posted April 1, 2021 Share Posted April 1, 2021 Hello, am new to papyrus and i am looking for a way to store additional variables on Actor. Initially i tried to extend Actor and store my variables this way, that didn't work out because you cant cast Actor as ExtendedActor if there is no instance of ExtendedActor.Then i tried to addSpell(Actor) and retrive effects's 'self' with a callback, this worked pretty well until now, but i have no idea how to retrive effect's variables in conditional system, my guess is you can't do it without declaring additional variables in Main script. (exactly what i am trying to avoid by putting variables in ActiveMagicEffect) So i scraped that aswell.I tried to extend ReferenceAlias as conditional and retrive it with GetVMScriptVariable but after ticking use aliases and selecting alias with attached script conditional variables don't show up.GetVMScriptVariable did work with script attached to random world actor, does it simply not work with aliases? Anyways can i somehow declare a class to store actor together with additional variables, in a way that lets me use said variables in conditional system? I am pretty sure that making a new quest end attaching a simple script filled with variables would work, then just set in Main as property, but i'd have to do it for every actor i am going to use concurrently, (max 7) but it looks like a horrible idea so i want to avoid doing that. Link to comment Share on other sites More sharing options...
ReDragon2013 Posted April 1, 2021 Share Posted April 1, 2021 (edited) Hmm.. not so easy to explain. You wrote: " a way to store additional variables on Actor" Maybe next is helpful.You have a predefined class called "actor".All native events and native/convenient functions (which are available) for this class are declared in the source script "actor.psc".This script is loaded ingame as executable "actor.pex", which means its the compiled version of source script.For example of vanilla actor script, see next:atronachFrostActorSCRIPT Scriptname atronachFrostActorSCRIPT extends Actor {behavior script for Frost Atronachs} ;=============================================== ; PROPERTIES & VARIABLES ;=============================================== ;;; import objectReference ; explosion to place when certain anims trigger it Spell property frostBurst auto ; visual effect shader that lives on the frost atronach EffectShader Property AtronachFrostFXS Auto ; spell to shoot from right arm Spell property FrostSpell auto ;=============================================== ; EVENTS ;=============================================== EVENT OnLoad() AtronachFrostFXS.Play(self) registerForAnimationEvent(self, "FrostImpactBurst") registerForAnimationEvent(self, "FrostShootSpell") endEVENT ;=============================================== EVENT OnAnimationEVENT(ObjectReference deliverator, String eventName) ; debug.trace(self + " caught event: " + eventName + " from " + deliverator) if eventName == "FrostImpactBurst" actor target = self.getCombatTarget() ; debug.trace(self + " is adding frost burst to his attack on " + target) frostBurst.cast(self,target) self.placeAtme(frostBurst) rampRumble(1,0.5,768) endif if eventName == "FrostShootSpell" actor target = self.getCombatTarget() ; debug.trace(self + " is using ranged power attack on " + target) frostSpell.cast(self) endif endEVENT ;=============================================== EVENT OnDeath(Actor myKiller) AtronachFrostFXS.Stop(self) ENDEVENT What can we do, to add an additional property without changing (too much) this script?We change the script Reference from "Actor" to a custom named script, here "atronachFrostActorExtenderScript".As follow: Scriptname atronachFrostActorSCRIPT extends atronachFrostActorExtenderScriptOur new extender script (which is now the parent from atronachFrostActorSCRIPT) looks as follow:atronachFrostActorExtenderScript Scriptname atronachFrostActorExtenderScript extends Actor Conditional GlobalVariable PROPERTY myGlobal auto Conditional ; this have to be created with CK and filled to this script Float PROPERTY myFloat auto Conditional ; [default=0.0] Int PROPERTY myInt auto Conditional ; [default=0] EVENT OnDying(Actor myKiller) ; its triggered, because the child script does not have the same event AtronachFrostFXS.Stop(self) ENDEVENT EVENT OnDeath(Actor myKiller) ; its NOT triggered here, because the child script has a higher priority for this event, its triggered only there AtronachFrostFXS.Stop(self) ENDEVENT Both scripts have to be compiled. And after that the property right filled with CK. Int, Float or String do not need to be filled, but the GlobalVariable is required because of the use of FomID.Every ingame spawned FrostAtronach actor is now using the extender script too. Every script property above can be used in CreationKit conditions like GetVMScriptVariable probably.But the properties are not changed during runtime. We have to change the vanilla script as well a bit more or make changes in parent script like next.atronachFrostActorSCRIPT (changed) Scriptname atronachFrostActorSCRIPT extends atronachFrostActorExtenderScript ; {behavior script for Frost Atronachs} ; https://forums.nexusmods.com/index.php?/topic/9838963-getting-conditional-variables-and-classes/ ; explosion to place when certain anims trigger it Spell property frostBurst auto ; visual effect shader that lives on the frost atronach EffectShader Property AtronachFrostFXS Auto ; spell to shoot from right arm Spell property FrostSpell auto ; -- EVENTs -- 3 EVENT OnLoad() AtronachFrostFXS.Play(self) registerForAnimationEvent(self, "FrostImpactBurst") registerForAnimationEvent(self, "FrostShootSpell") endEVENT EVENT OnAnimationEVENT(ObjectReference deliverator, String eventName) ; debug.trace(self + " caught event: " + eventName + " from " + deliverator) if eventName == "FrostImpactBurst" actor target = self.getCombatTarget() ; debug.trace(self + " is adding frost burst to his attack on " + target) frostBurst.cast(self,target) self.placeAtme(frostBurst) rampRumble(1,0.5,768) endif if eventName == "FrostShootSpell" actor target = self.getCombatTarget() ; debug.trace(self + " is using ranged power attack on " + target) frostSpell.cast(self) endif endEVENT EVENT OnDeath(Actor myKiller) int i = parent.myInt parent.myInt = i + 1 ; increase the dead counter of frostatronachs by using int float f = parent.myGlobal.GetValue() parent.myGlobal.SetValue(f + 1.0) ; increase .. by using globalVar AtronachFrostFXS.Stop(self) ENDEVENT Edited April 1, 2021 by ReDragon2013 Link to comment Share on other sites More sharing options...
xyz3lt Posted April 1, 2021 Author Share Posted April 1, 2021 (edited) Initially i tried to extend Actor and store my variables this way, that didn't work out because you cant cast Actor as ExtendedActor if there is no instance of ExtendedActor.Since i don't think you can dynamically make and instance of ExtendedActor i scratched that idea. Thanks for reply but i already did that and it doesn't do what i want it to.I dont want to give ExtendedActor to any single instance. Rather "ExtendedActor A = someActor as ExtendedActor". ActiveMagicEffect applied with addSpell() does work perfectly with exception that i cant use TESV conditional system with it. (no way of using GetVMQuestVariable or GetVMScriptVariable since there are no static references)And since conditional system doesn't seem to interact with reference aliases at all that idea was abandoned aswell. Currently i am begining to think i'll have to use the dirty quest hack that i mention in post above. All of the variables will be stored on actor as factions(4 factions total i think), then i'll get booleans and stuff from those. I need to make a class that holds actor reference, and all of the extracted variables, as to why code below should show it pretty well. bool Function Process(EA A1, EA A2) ;EA = ExtendedActor (not necesarilly extends Actor) dynamic if A1.bA && A2.bB == 1 ;just one function for 2 potential inputs if A1.bB == 1 ;bA and bB are some booleans return true ;problem is i cant access A1.bA from conditional system endif endif return false endFunction bool Function Process1() ;no actor extension here if baA1 && bbA2 == 1 ;but all vars are accessible from conditional system GetVMQuestVariable if bbA1 == 1 return true endif endif return false endFunction bool Function Process2() ;copy of Process1() that does the opposite if baA2 && bbA1 == 1 ;i dont even want to think about 3 or 4 actors. if bbA2 == 1 return true endif endif return false endFunction Also usage of global variables is out of question since i might end up with upwards of 100 booleans On the side note how does GetVMQuestVariable / GetVMScriptVariable compare to global variables and what is permormance cost on usage of those in general. Edited April 1, 2021 by xyz3lt Link to comment Share on other sites More sharing options...
xyz3lt Posted April 1, 2021 Author Share Posted April 1, 2021 (edited) Now that i read through your post a bit more throughly doing scriptname Actor extends ActorExtender would propably work pretty well (altough i am not sure if i could access it's variables in conditional) Below rough sketch of what i am doing / want to do scriptname MainScript Conditional ExtendedActor A1 Conditional ;Simply adding conditional doesnt work ExtendedActor A2 Conditional Function Work() ;init actors A1.akRef = ScanForActor() InitializeEA(A1) A2.akRef = ScanForActor() InitializeEA(A2) ;run some logic int res = SomeLogic() ;start a scene based on res and internal variables of A1 & A2 (and potenially A1-A7) ;i dont know how to access A1.Something from CK conditional window endFunction Function InitializeEA(ExtendedActor A) ;sets all of Extended Actor variables actor Function ScanForActor() Function SomeLogic() Edited April 1, 2021 by xyz3lt Link to comment Share on other sites More sharing options...
dylbill Posted April 1, 2021 Share Posted April 1, 2021 Are your actors vanilla actors or actors you have custom made? If your actors are custom, you can just add a script to them that extends actor: Scriptname TM_ActorScript extends Actor Int Property BBA1 = 1 Auto HiddenThen in another script you can do this: Bool Function MyBoolFunction(Actor akActor) If (akActor as TM_ActorScript).BBA1 == 1 Return True Endif Return False EndFunction If they are vanilla actors, you will need to use reference alias's instead for compatibilities sake. Link to comment Share on other sites More sharing options...
dylbill Posted April 1, 2021 Share Posted April 1, 2021 Another option, if you're using skse you can us ConsoleUtil to dynamically attach scripts to object references and actors: https://www.nexusmods.com/skyrim/mods/66257 Actor Property MyActor Auto Event OnInit() ConsolUtil.SetSelectedReference(MyActor) ;set console reference to MyActor ConsolUtil.ExecuteCommand("AttachPapyrusScript TM_ActorScript") ;attach the TM_ActorScript to MyActor EndEvent Link to comment Share on other sites More sharing options...
xyz3lt Posted April 1, 2021 Author Share Posted April 1, 2021 Every actor reference i am operating on is scanned from player surroundings(Most of them will be vanilla), then put in ExtendedActor which after initializing stores variables extracted from factions and serves as an argument for few functions that operate on said variables(and sometimes on akRef). Dynamically attaching scripts to actors can be easilydone with ActiveMagicEffect or ActorAlias, thats not really the problem i have. All i really need is to get variables from dynamically attached scripts into conditional system in CK. And frankly, i have no idea how to do it, for now i'll just make a quest instance for all actors i need(2 for now but it will go up), put a simple script with variables in each of them and link them into mainScript as Properties. I already tested if it'll work, and it does, but it really feels like there is some better way of doing that. Link to comment Share on other sites More sharing options...
dylbill Posted April 1, 2021 Share Posted April 1, 2021 What conditions specifically? You can put conditions directly on your magic effect, or on the spell that holds the magic effect. Then use a script that extends ActiveMagicEffect with OnEffectStart. Use ability type spells. Example, put an ability with the condition IsInCombat == 1 and the effect will start when the actor enters combat. Link to comment Share on other sites More sharing options...
xyz3lt Posted April 1, 2021 Author Share Posted April 1, 2021 I want to use conditions for scene and player dialogs, currently i am using AOE that does addSpell() that adds Abilty with ActiveMagicEffect(it does have some basic conditions such as IsInCombat) to retrive all. On side note i'll probably ditch this model and use ScanCellNPCs from PapyrusUtils Let me elaborate, if i had a bool in a quest, where both quest and said bool are marked as conditional i could use it in conditional system with GetVMQuestVariable.If i had a bool in an activator, both marked as conditional, i could use GetVMScriptVariable on activator reference(a leaver in some cell for example). But if i were to "attach" ActiveMagicEffect onto some actor and then retrive it into the mainScript(with a callback or a while loop) then i would have "ActiveMagicEffect Property someEffect Auto" inside for example MainScript, i can use it's variables and functions just fine but i can't seem to get it to work with conditional system. If ActiveMagicEffect carries a bool i would have to make a new bool in MainScript just so i could retrive it with GetVMQuestVariable. Can you recommend me any mods that seem add dynamic npc scenes/dialog (or mods that rely heavily on scripted conditions, but thats a bit of an unreasonable request)? If i am lucky i might find what i am looking for by looking through their source/esp's. Link to comment Share on other sites More sharing options...
dylbill Posted April 1, 2021 Share Posted April 1, 2021 What I would recommend here is using a faction. Make a new faction, then in your magic effect script add, remove or set rank of the faction on the target. Then in the CK you can put IsInFaction or GetFactionRank for the conditions. You can use multiple factions if you need more bools or ranks. Link to comment Share on other sites More sharing options...
Recommended Posts