Jump to content

[LE] Unequip>Equip script


NOOBIV

Recommended Posts

sorry my bad english, and sorry if this is the wrong forum :unsure:


hi, i want to make a script that makes: all actors wearing a specific item makes to unequip>equip that/a item when changing cells


just like, i give a scripted ring to Cicero that makes to unequip>equip a sword(or the ring) each time i change cells


the reason because i want to make this script is because i'm using a X mod (HDT items) that add tails,ears,etc, everything works fine, but when i change to another cells, the tails/ears looks really weird on npcs, and only unequip and re-equip fix that, so this is the only way to fix the mod i found, making a script, but i have 0 knowledge of scripting :sad:â , i was reading the Creation kit wiki, but basically i don´t understand what im reading :sweat:

if someone can help me how to make that script, i already have the empty script and the object with the empty script (the only phase that my brain could understand :wacko: ), or links with the necessary to make this script or just hold my hand and guide me to the way to make this script :rolleyes: , i will appreciate every help :D



Link to comment
Share on other sites

Are you by chance using a skeleton mod? I'm quite certain mods that change that could be a conflict with your mod that adds ears and stuff.

 

Perhaps someone else can help you further with your script! but I do suggest to remove that skeleton mod and try with a clean save.

Link to comment
Share on other sites

thanks for the tip! im using XMPSE (XP32 Maximum Skeleton Extended) so i cant just remove it, it will break the game :unsure: , anyways ears/tails doesn´t look really really weird (just becomes shorter than normal and HDT is unnoticeable) also i don´t think is a skeleton issue, i think is a HDT issue, because if i remove the XML attached in the .nif (ears/tails) it doesn´t look weird anymore, but lost HDT, if i attach the XML again and load the game, it looks weird again until i re-equip it each load screen :sad:

 

About the script, i think it should looks like this. Warning, cringe script inside

 

 

Event OnCellLoad()
endEvent
Function UnequipItem(Form akItem, bool abPreventEquip = false, bool abSilent = false) native
Game.GetPlayer().UnequipItem(The Ring)
endFunction
Function EquipItem(Form akItem, bool abPreventRemoval = false, bool abSilent = false) native
Game.GetPlayer().EquipItem(The Ring)
endFunction

how i can change Game.GetPlayer for Followers only? also what means AkActor?, any actor :confused: ?
also i should add "Armor property "The Ring" Auto"
"Actor property "Follower?" Auto" at the top?.

 

For what i understand, this script should do
1Event: when the player change to another cells the functions will start
2Function: will unequip the ring from the followers wearing it
3Function:will equip the ring on all Followers that have the ring in his inventory
Those are the correct scripts? or i should add more scripts to make it work :ohmy:â ?, also please help me to modify it correctly :smile: .
Link to comment
Share on other sites

This is a basic script, its not tested or anything. Im guessing you need this script active at all times so.. put it on alias quest

 

 

Actor Property PlayerRef Auto ; references the player "you"

Armor Property Item Auto ; references the item below. Property "Item" you can change item to whatever, as long as its matching the script below. same with actor
Event OnCellLoad()
PlayerRef.UnequipItem(Item)
Utility.Wait(0.1)

PlayerRef.EquipItem(Item)

 

Link to comment
Share on other sites

ooh thanks, it should be like this?



Actor Property PlayerRef Auto

Armor Property TheRing Auto


Event OnCellLoad()

endEvent


Function UnequipItem(Form akItem, bool abPreventEquip = false, bool abSilent = false) native

PlayerRef.UnequipItem(TheRing)

endFunction


Utility.Wait(0.1)


Function EquipItem(Form akItem, bool abPreventRemoval = false, bool abSilent = false) native

PlayerRef.EquipItem(TheRing)

endFunction



i want to make this script to affect followers only, so is there a way to change the "Actor Property"? like this


Actor Property FollowersRef Auto



FollowersRef.UnequipItem(Item)

Utility.Wait(0.1)

FollowersRef.EquipItem(Item)


Edited by NOOBIV
Link to comment
Share on other sites

Just a bit more scriptness. Maybe it is helpful for understanding. You need both scripts for the workaround you like to have.

 

NOOBIV_ItemPlayerAliasScript

 

Scriptname NOOBIV_ItemPlayerAliasScript extends ReferenceAlias
{written by ReDragon 2017}    ; attach this script to the player alias, that is a part of a new created quest

  FormList fml        ; empty formlist


; -- EVENTs -- 2

EVENT OnCellLoad()
;;  Debug.Notification("new Cell has been loaded!")
;;  myF_Item()
ENDEVENT

; Event that is triggered when this actor changes from one location to another
EVENT OnLocationChange(Location akOldLoc, Location akNewLoc)
    gotoState("Busy")
    Debug.Trace("PlayerAlias: old = " +akOldLocation+ ", new = " akNewLocation)
    myF_Item()
    gotoState("")
ENDEVENT

;==================================
state Busy  ;you have to cover the same event in no state
;=========
EVENT OnLocationChange(Location akOldLoc, Location akNewLoc)
ENDEVENT
;=======
endState

; -- FUNCTIONs -- 3

;-----------------------------------------
FUNCTION myF_AddMe(NOOBIV_ItemEUScript ps)  ; add to formlist, external called by "NOOBIV_ItemEUScript"
;-----------------------------------------
; https://www.creationkit.com/index.php?title=AddForm_-_FormList
    fml.AddForm(ps as Form)
ENDFUNCTION


;--------------------------------------------
FUNCTION myF_RemoveMe(NOOBIV_ItemEUScript ps)  ; remove from formlist, external called by "NOOBIV_ItemEUScript"
;--------------------------------------------
; https://www.creationkit.com/index.php?title=RemoveAddedForm_-_FormList
    fml.RemoveAddedForm(ps as Form)
ENDFUNCTION


;------------------
FUNCTION myF_Item()
;------------------
    int i = fml.GetSize()
WHILE (i > 0)
    i = i - 1
    NOOBIV_ItemEUScript ps = fml.GetAt(i) as NOOBIV_ItemEUScript
    IF ( ps )
        ps.myF_Action()
    ENDIF
ENDWHILE
ENDFUNCTION

 

 

 

NOOBIV_ItemEUScript

 

Scriptname NOOBIV_ItemEUScript extends ObjectReference
{written by ReDragon 2017}    ; attach this script to the baseobject of your item, which should be equipped/unequipped if player is changing the cell

; https://forums.nexusmods.com/index.php?/topic/6114328-unequipequip-script/
; NOOBIV wrote: "I give a scripted ring to Cicero that makes to unequip/equip a sword(or the ring) each time I change cells"

  NOOBIV_ItemPlayerAliasScript PROPERTY ps auto        ; DO NOT FORGET !!! to fill the property with NOOBIV_ItemPlayerAliasScript

  Actor myOwner


; -- EVENTs --

; Event received when this object enters, exits, or changes containers
EVENT OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer)
IF (akNewContainer as Actor)
ELSE
    gotoState("Done")                ; ### STATE ###
    myOwner = None
    ps.myF_RemoveMe(self)
    RETURN    ; - STOP -    ring is thrown away or placed into barrel, sack or similiar container
ENDIF
;---------------------
IF (akNewContainer as Actor == Game.GetPlayer())
    gotoState("Done")                ; ### STATE ###
    myOwner = None
    ps.myF_RemoveMe(self)
    RETURN    ; - STOP -    ring was given to the player, do not equip by the player
ENDIF
;---------------------
    gotoState("Waiting")            ; ### STATE ###
    myOwner = akNewContainer as Actor                ; make new owner persistent for a while
    ps.myF_AddMe(self)
ENDEVENT


;==============================
state Done    ; do not track anything, there is no owner of this item
;=========
endState


;==============================
state Waiting
;============
; Event received when this object is equipped by an actor
EVENT OnEquipped(Actor akActor)
    int i = (self as ObjectReference).GetFormID()
    Debug.Notification("Item " +i)                        ; info only
ENDEVENT

; Event received when this object is unequipped by an actor
EVENT OnUnequipped(Actor akActor)
;    int i = (self as ObjectReference).GetFormID()
;    Debug.Notification("Item (un) " +i)                  ; info only
ENDEVENT
;=======
endState


; -- FUNCTION --

;; Forces this actor to equip the specified item, preventing removal if requested
;Function EquipItem(Form akItem, bool abPreventRemoval = false, bool abSilent = false) native

;; Unequips the specified item from this actor
;Function UnequipItem(Form akItem, bool abPreventEquip = false, bool abSilent = false) native

;--------------------
FUNCTION myF_Action()  ; external called by "NOOBIV_ItemPlayerAliasScript"
;--------------------
IF ( myOwner )
    myOwner.EquipItem(self as Form)
    Utility.Wait(0.1)
    myOwner.UnequipItem(self as Form)
ENDIF
ENDFUNCTION

 

 

 

posting edited 31-10-2017

Edited by ReDragon2013
Link to comment
Share on other sites

I'm a fair bit concerned about triggering this on "cell" changes. Walking around in the worldspace will cause this to happen A LOT! More specifically it sounds like you only want something that happens between load doors. Sadly I don't have a good method for detecting and reacting to that. The best solution there I have is monitor for location change and check each time if the reference went FROM an interior to an exterior or the other way around or changed world spaces. There might also be times where you go from an exterior to an interior and the "Location" as the game knows it is the same.

Now for your content posts above. The actual name of the property makes no difference. You could leave it PlayerRef. You can change it to Alibaba if you want. It doesn't matter what it's called. What matters, is when you attach the script to an object in CK, that you assign the correct thing to the property you want the script to act on. If you have it named PlayerRef and use the autofill button (you have to press the button on the properties window) then it will fill the property for you with the PlayerRef object. You can change it after that as well, but you will need to do so before the mod is loaded and baked into a save game. At the same time if you renamed it to FollowersRef and hit autofill it will do nothing, unless you have an actual object with the editor ID of FollowersRef. Then it will put that object in the property. Otherwise if it fails to autofill then you have to manually fill the property or the script will get a "None" value.

As you wrote the changes to the script it won't compile. You have calls to things in the context of the script outside functions or events (Utility.Wait) which are invalid. You also have the script events declared as functions which are invalid. You also have those same events doing redundant things. When unquipping, unquip? So you're telling the script, when you unequip the ring from the object the script is running on, unequip it from the reference of the property. This is redundant because it's already done, unless you put the script on a different object and then want it to trigger when you unequip from one object, also unequip from another.

There's another issue in that you have the script reacting to different objects. If you have the script running on the player detecting when you change areas and then trying to equip/unquip on another actor, you need to make sure that actor is nearby. Followers sometimes take a while to move through load doors. You need the script to actually run on the follower itself and detect when the follower changes areas.

Unfortunately for what you're trying to do there's no real elegant solution, only rough hacks. One would be to run a quest with an alias. Place a script on the alias to detect the movement changes and then unequip/re-equip the item you desire on itself (the alias). Then you put whatever reference you want in the alias. It could be the player, or a follower, whatever. However only 1 at a time. Though you can create multiple aliases and use the same script. Another solution that would support multiple objects at once would be to use a magic effect. This would go something like, make ring with enchantment. The enchantment has a script that gets the call/area change. Then it equip/unequips an object defined by a property from the object the magic effect is on (the actor).

My preferred method to try and pull this off would be the magic effect script. It would go something like this. Note: This script uses OnLocationChange to detect the movement between areas and has no checking of any kind. This is a bad idea in practice because it will trigger more than necessary. This is only intended for example usage not for actual game play usage.

Scriptname TestEffect extends ActiveMagicEffect

Actor myActor ; holder for the actor this script is affecting
Armor Property RecycleArmorObject auto ; the armor record to unequip and then re-equip

Event OnEffectStart(Actor akTarget, Actor akCaster)
    myActor = akTarget ; this is necessary so that other events can act upon the actor the effect is running on
EndEvent

Event OnLocationChange(Location akOldLoc, Location akNewLoc)
    myActor.UnequipItem(RecycleArmorObject)
    Utility.Wait(0.1) ; this may be unnecessary and should be tested with and without it to see which works as desired
    myActor.EquipItem(RecycleArmorObject)
EndEvent

I don't believe the OnCellLoad() would work for what you're trying to do. You would need to attach the script to an object other than the player or the follower that would be in the cell you're going into which would then get the event when it loads. I don't see an easy way to accomplish that in any meaningful manner. The other issue is as I stated before, the follower you want to act on may not be there yet when the event fires. I could be wrong, it would need more testing. If it does work then my script above could be modified to use such.

 

Edit: changed the RecycleArmorObject to a property. Oops.

Edited by BigAndFlabby
Link to comment
Share on other sites

 

 

Just a bit more scriptness. Maybe it is helpful for understanding. You need both scripts for the workaround you like to have.

 

NOOBIV_ItemPlayerAliasScript

 

Scriptname NOOBIV_ItemPlayerAliasScript extends ReferenceAlias
{written by ReDragon 2017}    ; attach this script to the player alias, that is a part of a new created quest

  FormList fml        ; empty formlist


; -- EVENTs -- 2

EVENT OnCellLoad()
;;  Debug.Notification("new Cell has been loaded!")
    myF_Item()
ENDEVENT

; Event that is triggered when this actor changes from one location to another
EVENT OnLocationChange(Location akOldLoc, Location akNewLoc)
;;  Debug.Trace("PlayerAlias: old = " +akOldLocation+ ", new = " akNewLocation)
ENDEVENT


; -- FUNCTIONs -- 3

;-----------------------------------------
FUNCTION myF_AddMe(NOOBIV_ItemEUScript ps)  ; add to formlist, external called by "NOOBIV_ItemEUScript"
;-----------------------------------------
; https://www.creationkit.com/index.php?title=AddForm_-_FormList
    fml.AddForm(ps as Form)
ENDFUNCTION


;--------------------------------------------
FUNCTION myF_RemoveMe(NOOBIV_ItemEUScript ps)  ; remove from formlist, external called by "NOOBIV_ItemEUScript"
;--------------------------------------------
; https://www.creationkit.com/index.php?title=RemoveAddedForm_-_FormList
    fml.RemoveAddedForm(ps as Form)
ENDFUNCTION


;------------------
FUNCTION myF_Item()
;------------------
    int i = fml.GetSize()
WHILE (i > 0)
    i = i - 1
    NOOBIV_ItemEUScript ps = fml.GetAt(i) as NOOBIV_ItemEUScript
    IF ( ps )
        ps.myF_Action()
    ENDIF
ENDWHILE
ENDFUNCTION

 

 

 

NOOBIV_ItemEUScript

 

Scriptname NOOBIV_ItemEUScript extends ObjectReference
{written by ReDragon 2017}    ; attach this script to the baseobject of your item, which should be equipped/unequipped if player is changing the cell

; https://forums.nexusmods.com/index.php?/topic/6114328-unequipequip-script/
; NOOBIV wrote: "I give a scripted ring to Cicero that makes to unequip/equip a sword(or the ring) each time I change cells"

  NOOBIV_ItemPlayerAliasScript PROPERTY ps auto        ; DO NOT FORGET !!! to fill the property with NOOBIV_ItemPlayerAliasScript

  Actor myOwner


; -- EVENTs --

; Event received when this object enters, exits, or changes containers
EVENT OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer)
IF (akNewContainer as Actor)
ELSE
    gotoState("Done")                ; ### STATE ###
    myOwner = None
    ps.myF_RemoveMe(self)
    RETURN    ; - STOP -    ring is thrown away or placed into barrel, sack or similiar container
ENDIF
;---------------------
    gotoState("Waiting")            ; ### STATE ###
    myOwner = akNewContainer as Actor                ; make new owner persistent for a while
    ps.myF_AddMe(self)
ENDEVENT


;==============================
state Done    ; do not track anything, there is no owner of this item
;=========
endState


;==============================
state Waiting
;============
; Event received when this object is equipped by an actor
EVENT OnEquipped(Actor akActor)
    int i = (self as ObjectReference).GetFormID()
    Debug.Notification("Item " +i)                        ; info only
ENDEVENT

; Event received when this object is unequipped by an actor
EVENT OnUnequipped(Actor akActor)
;    int i = (self as ObjectReference).GetFormID()
;    Debug.Notification("Item (un) " +i)                  ; info only
ENDEVENT
;=======
endState


; -- FUNCTION --

;; Forces this actor to equip the specified item, preventing removal if requested
;Function EquipItem(Form akItem, bool abPreventRemoval = false, bool abSilent = false) native

;; Unequips the specified item from this actor
;Function UnequipItem(Form akItem, bool abPreventEquip = false, bool abSilent = false) native

;--------------------
FUNCTION myF_Action()  ; external called by "NOOBIV_ItemPlayerAliasScript"
;--------------------
IF ( myOwner )
    myOwner.EquipItem(self as Form)
    Utility.Wait(0.1)
    myOwner.UnequipItem(self as Form)
ENDIF
ENDFUNCTION

 

 

 

 

i appreciate your hard work, but i don´t know how to adapt those scripts to what i need, thanks anyways, all info and examples are useful for me :wub:

BigAndFlabby

I'm a fair bit concerned about triggering this on "cell" changes. Walking around in the worldspace will cause this to happen A LOT! More specifically it sounds like you only want something that happens between load doors. Sadly I don't have a good method for detecting and reacting to that. The best solution there I have is monitor for location change and check each time if the reference went FROM an interior to an exterior or the other way around or changed world spaces. There might also be times where you go from an exterior to an interior and the "Location" as the game knows it is the same.

Now for your content posts above. The actual name of the property makes no difference. You could leave it PlayerRef. You can change it to Alibaba if you want. It doesn't matter what it's called. What matters, is when you attach the script to an object in CK, that you assign the correct thing to the property you want the script to act on. If you have it named PlayerRef and use the autofill button (you have to press the button on the properties window) then it will fill the property for you with the PlayerRef object. You can change it after that as well, but you will need to do so before the mod is loaded and baked into a save game. At the same time if you renamed it to FollowersRef and hit autofill it will do nothing, unless you have an actual object with the editor ID of FollowersRef. Then it will put that object in the property. Otherwise if it fails to autofill then you have to manually fill the property or the script will get a "None" value.

As you wrote the changes to the script it won't compile. You have calls to things in the context of the script outside functions or events (Utility.Wait) which are invalid. You also have the script events declared as functions which are invalid. You also have those same events doing redundant things. When unquipping, unquip? So you're telling the script, when you unequip the ring from the object the script is running on, unequip it from the reference of the property. This is redundant because it's already done, unless you put the script on a different object and then want it to trigger when you unequip from one object, also unequip from another.

There's another issue in that you have the script reacting to different objects. If you have the script running on the player detecting when you change areas and then trying to equip/unquip on another actor, you need to make sure that actor is nearby. Followers sometimes take a while to move through load doors. You need the script to actually run on the follower itself and detect when the follower changes areas.

Unfortunately for what you're trying to do there's no real elegant solution, only rough hacks. One would be to run a quest with an alias. Place a script on the alias to detect the movement changes and then unequip/re-equip the item you desire on itself (the alias). Then you put whatever reference you want in the alias. It could be the player, or a follower, whatever. However only 1 at a time. Though you can create multiple aliases and use the same script. Another solution that would support multiple objects at once would be to use a magic effect. This would go something like, make ring with enchantment. The enchantment has a script that gets the call/area change. Then it equip/unequips an object defined by a property from the object the magic effect is on (the actor).

My preferred method to try and pull this off would be the magic effect script. It would go something like this. Note: This script uses OnLocationChange to detect the movement between areas and has no checking of any kind. This is a bad idea in practice because it will trigger more than necessary. This is only intended for example usage not for actual game play usage.

Scriptname TestEffect extends ActiveMagicEffect

Actor myActor ; holder for the actor this script is affecting
Armor RecycleArmorObject ; the armor record to unequip and then re-equip

Event OnEffectStart(Actor akTarget, Actor akCaster)
myActor = akTarget ; this is necessary so that other events can act upon the actor the effect is running on
EndEvent

Event OnLocationChange(Location akOldLoc, Location akNewLoc)
myActor.UnequipItem(RecycleArmorObject)
Utility.Wait(0.1) ; this may be unnecessary and should be tested with and without it to see which works as desired
myActor
.EquipItem(RecycleArmorObject)
EndEvent

I don't believe the OnCellLoad() would work for what you're trying to do. You would need to attach the script to an object other than the player or the follower that would be in the cell you're going into which would then get the event when it loads. I don't see an easy way to accomplish that in any meaningful manner. The other issue is as I stated before, the follower you want to act on may not be there yet when the event fires. I could be wrong, it would need more testing. If it does work then my script above could be modified to use such.

 

 

you opened my eyes about the script, this info is really useful for me, you made to jump my understanding from 3% to 50%, also you answered a lot of questions that i forget to ask, thanks! :D
So this line is unnecessary
Function UnequipItem(Form akItem, bool abPreventEquip = false, bool abSilent = false) native
and sorry, i had other understanding about "OnCellLoad" i will use "OnLocationChanged" so.
this is what i understand and did

1.Added a Actor Property (Ahri)
2.Added a Armor Property (TheRing)
3.And pressed "Auto-Fill All", now the Script Looks like this
Scriptname ReEquipRing extends ActiveMagicEffect
Actor Property Ahri (My Follower) Auto
Armor Property TheRing (JewelryRingGold the real object name with this script attached) Auto
Event OnEffectstart(Actor akTarget, Actor akCaster)
Ahri = akTarget
EndEvent
Event OnLocationChange(Location akOldLoc, Location akNewLoc)
Ahri.UnequipItem(TheRing)
Utility.Wait(0.1)
Ahri.EquipItem(TheRing)
EndEvent

and Saved without a error message.so this script should do
1.When the Actor (Ahri) change to another cell (Event OnLocationChange)
2.The Ring (TheRing"JewelryRingGold") will be unequipped from Actor (Ahri)
3.The RIng (TheRing"JewelryRingGold") will be Equipped to Actor (Ahri)
But before test it in game i have some questions
what means akTarget, akOldLoc, i mean, what means "ak"? what i understand it means "AnyTarget, AnyOldLocation"
Also i should 1. attach the Script to the Item that should be Unequipped-Equipped?, or 2. Attach the Script to an Item that makes another item to be Unequipped-Equipped?
what i mean, i should make a Scripted GoldRing to Unequip-Equip the same GoldRing with the Script. or i should make a Scripted SilverNecklace to Unequip-Equip the GoldRing
Please have patience, im not a english speaker, so i think this will add some walls in the way :unsure:
Link to comment
Share on other sites

To start with your questions:

 

The ak prefix doesn't mean anything special. Variable names can be named just about anything you want.

 

Event OnEffectstart(Actor akTarget, Actor akCaster)

This means that when the event is triggered then inside the event scope it will have a variable named akTarget which is of type actor and another variable named akCaster which is also of type actor. The names akCaster and akTarget are completely arbitrary. They could just as easily be "me" and "you" though that would be really confusing to the programmer I would think. Typically programmers will name their variables with descriptive names so they don't forget what they are. In this case the ak prefix doesn't really mean anything particular. In the future you may run into other scripts where people may name the variables with b or i prefixes, like bTargetDead which would typically be a boolean type or iCounter for an integer. In truth the variables can be named just about anything you want as long as it isn't a reserved name or one that is already used. But since most people either copy and paste from the wiki or the base script definition they usually leave them as Bethesda wrote them. Bethesda decided that when the event is called it will be passed 2 parameters. The first being the target actor and the second being the casting actor. Depending on what the magic effect does they may be the same reference. Like casting a self healing, the target and caster is the same actor reference.

The script as I wrote it would go on a magic effect. You would create a magic effect, attach the script to that. Then create an object enchantment which uses that magic effect. Then on an armor or weapon attach the enchantment. You can look at the StaffFirebolt "Staff of Firebolts" weapon to see how the hierarchy goes. That weapon has an enchantment named StaffEnchFirebolt "Firebolt" which has a magic effect FireDamageFFAimed "Firebolt" which has a script on it. A similar thing can be done for armor. You can look at any armor with the beginning name Ench to see how the object effect is attached and then linked to a magic effect.

 

Just to reiterate, this script will go on a magic effect that needs to be on the follower since it sets the actor to equip/unquip from as the target of the magic effect. So you would make a ring with an enchantment that the follower will then equip. If you're trying to make a ring that you wear then this script will not work without some fairly major and likely complex changes.

 

There's no need for Ahri to be a property set in CK since you're assigning the value in the OnEffectStart event. Using a local script variable would be better. Changing the line to just this will do exactly the same thing and does not allocate the extra memory required for a property

 

Actor Ahri
Link to comment
Share on other sites

  • Recently Browsing   0 members

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