Jump to content

[LE] Getting conditional variables, and classes


xyz3lt

Recommended Posts

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

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 atronachFrostActorExtenderScript

Our 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 by ReDragon2013
Link to comment
Share on other sites

 

 

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 by xyz3lt
Link to comment
Share on other sites

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 by xyz3lt
Link to comment
Share on other sites

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 Hidden

Then 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

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

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

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

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

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

  • Recently Browsing   0 members

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