Jump to content

EquipItem(someArmor) fails...?


payl0ad

Recommended Posts

Hey Nexus. I'm starting to lose my sanity over this. Help me hive mind, you're my only hope.

 

I have a script attached to a MGEF that gets applied by a potion. It should force-equip the player with some piece of invisible armor that blocks some item slots.The script also listens for equip events to unequip stuff that slips through the cracks (it seems the game isn't horribly consistent when evaluating used item slots). When the MGEF finishes it should unequip that armor.

 

The code I have so far:

Scriptname GhoulskinScriptEffect extends ActiveMagicEffect

; equip a non-removable armor that occupies item slots 31,32,46,48,49,50
Armor Property pGhoulskinArmor Auto
Actor Property pPlayer Auto
FormList Property pClothingKeywordsToBlock Auto
Message[] Property pGhoulskinMessages Auto

Event OnInit()
	Debug.MessageBox("OnInit")
	RegisterForRemoteEvent(pPlayer, "OnItemEquipped")
EndEvent

Event OnEffectStart(Actor akTarget, Actor akCaster) 
	Debug.MessageBox("OnEffectStart")
	HandleGhoulSkin(true)
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
	Debug.MessageBox("OnEffectFinish")
	HandleGhoulSkin(false)
	UnregisterForRemoteEvent(pPlayer, "OnItemEquipped")
EndEvent

Function HandleGhoulSkin(bool abStart)
	if abStart
		Debug.MessageBox("HandleGhoulSkin(true)")
		pPlayer.AddItem(pGhoulskinArmor, 1, true)
		pPlayer.EquipItem(pGhoulskinArmor, true, true) ; culprit
		pGhoulskinMessages[0].Show()
	else
		Debug.MessageBox("HandleGhoulSkin(false)")
		pPlayer.UnequipItem(pGhoulskinArmor, false, true)
		pPlayer.RemoveItem(pGhoulskinArmor, 1, true)
		pGhoulskinMessages[1].Show()
	endIf
EndFunction

Event OnItemEquipped(Form akBaseObject, ObjectReference akReference)
	if akBaseObject.HasKeywordInFormList(pClothingKeywordsToBlock)
		pPlayer.UnequipItem(akBaseobject, false, true)
		pGhoulskinMessages[2].Show()
	endIf
EndEvent

As you see, I've already added debug messages to step through the code, so I know all code paths are used. Basically, everything except the one line marked "culprit" works. The armor gets added to the player inventory when the effect starts, but the game doesn't want to equip it. I can then equip it in the Pipboy and it unequips all other stuff, so the armor seems to work as intended.

 

I also tried to do the very same thing using the ingame console. When I do

player.additem <ArmorID>
player.equipitem <ArmorID> 1

in game that actually works, it also keeps the player from unequipping the armor as you'd expect. I noticed the difference in syntax of both functions (player.equipitem vs. PlayerRef.EquipItem()) and also their difference in parameters: player.equipitem seems to want a weapon slot ID as third argument (mentioned in an error message). So that test might be bogus, I can't tell.

 

Just for shits and giggles, I tried changing the offending line to this:

pPlayer.EquipItem(pGhoulskinArmor, 1)

which sadly does exactly the same as all other variants I've tried. When I search the Nexus boards, everybody seems to do it the same way: EquipItem(someForm, bool, bool).

 

Everything compiles just fine obviously.

 

BTW, I started trying this by using Actor.UnequipItemSlot() but that doesn't work except for item slot 30, which is the Pipboy (for some reason UnequipItemSlot does not seem to use the regular human biped slots).

 

Anybody got an idea what the hell is going on here?

Edited by payl0ad
Link to comment
Share on other sites

Does your armour have a keyword on it that also appears in the blocked list? Other than that, just a blind guess, but does adding a small delay between AddItem and EquipItem do anything? Probably not.

 

The EquipItem function should be fine according to the wiki: http://www.creationkit.com/fallout4/index.php?title=EquipItem_-_Actor

 

Edit: Is there a specific reason why you have your event registration in OnInit?

Edited by Contrathetix
Link to comment
Share on other sites

I made sure the armor has no Keywords on the block list. It doesn't get unequipped by it, there's a warning message that would display if it did (which does not appear). I can try adding that delay, might just work. Read another thread from a Skyrim modder that had a similar problem, was solved by moving operations from OnInit to OnLoad... which did not work for me. :-D

 

Event registration is in OnInit by habit. The event fires fine though, should I rather do that in OnEffectStart?

Edited by payl0ad
Link to comment
Share on other sites

Hmm. Have you tried the OnItemEquipped without registration? The ActiveMagicEffect Script page says it also receives events from the actor is it currently attached to, so if it really works that way, then you could maybe drop your event registration (it looks so odd anyway), if the magic effect automatically catches OnItemEquipped events from the actor. I have not tested it, just an idea.

 

You can also add a check to see if something is actually equipped right after the equip command, I think. Or not.

 

 

ScriptName GhoulskinScriptEffect Extends ActiveMagicEffect

; equip a non-removable armor that occupies item slots 31,32,46,48,49,50

; assuming Self refers to the object the script runs on (Actor), then maybe
; casting it as Actor would remove the need for the use of a separate
; Actor variable and would allow using the script also on other actors

Armor Property pGhoulskinArmor Auto
FormList Property pClothingKeywordsToBlock Auto
Message[] Property pGhoulskinMessages Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
    Debug.MessageBox("OnEffectStart, Actor(" + Self + ")")
    (Self as Actor).AddItem(pGhoulskinArmor, 1, True)
    (Self as Actor).EquipItem(pGhoulskinArmor, True, True) ; culprit
    Debug.MessageBox("IsEquipped(" + pGhoulskinArmor + ") = " + (Self as Actor).IsEquipped(pGhoulskinArmor))
    pGhoulskinMessages[0].Show()
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
    Debug.MessageBox("OnEffectFinish, Actor(" + Self + ")")
    (Self as Actor).UnequipItem(pGhoulskinArmor, False, True)
    (Self as Actor).RemoveItem(pGhoulskinArmor, 1, True)
    pGhoulskinMessages[1].Show()
EndEvent

Event OnItemEquipped(Form akBaseObject, ObjectReference akReference)
    If (akBaseObject.HasKeywordInFormList(pClothingKeywordsToBlock))
        (Self as Actor).UnequipItem(akBaseobject, False, True)
        pGhoulskinMessages[2].Show()
    EndIf
EndEvent

 

 

 

The thing with OnInit... I suppose it works if it fires once for each time the effect triggers, but even then the OnEffectStart would be there. Whatever works for you. There are so many equally great ways to do something.

 

Edit: Ooooooops. Fixed the tags. :facepalm:

 

Edit 2: About the script in the spoiler... I do not have the Fallout 4 CK installed at the moment, but the "Self as Actor" will probably fail now that I think of it. If it does that, maybe something like this would work better (judging by the family tree of scripts), maybe with an added "as ObjectReference" even. I really have no idea. I forgot ActiveMagicEffect was in another branch of sorts. I remember having issues in Skyrim with two custom scripts both extending Form, where casting one of them as the other required going "through" the parent (Form) script.

(((Self as ScriptObject) as Form) as Actor)

I really hope just "Self as Actor" works, since the object the scrip is running on should probably be an actor, and Self should probably refer to the actor, and the actor should have the Actor script on it and all that. Oh well. One of those "need to test" things again. Sorry, I was typing the initial response in the middle of the night half asleep. :sad:

Edited by Contrathetix
Link to comment
Share on other sites

The Event thing is fine, really. Event registers and fires exactly when I want it to, does exactly what I want. Armor has only 3 Keywords: DogMeatNoVisualsOnRetrieve, AnimHelmetCoversMouth, ArmorBodyPartHead - the block list has only AWKCR keywords, so the armor won't trigger the effect.

 

I tried using Utility.Wait(0.5) between adding and equipping the armor. Doesn't change a thing. It's still the very same line, EquipItem(pGhoulskinArmor, true, true) does not run, like, at all.

 

It's not a type problem either I feel. I tried changing the Armor Property to a Form Property which doesn't change a thing (as expected).

 

What bugs me most though is that the OnEffectFinish part works as expected. I can unequip things just fine, only equipping them fails in this case. In the mod I'm working on (which this effect is a part of), I actually have several scripts that equip stuff. Works fine, no problem, as long as I'm equipping potions.

 

Let me describe how I'm testing this. My mod starts up when the player wakes up from Cryosleep in V111. I have a savegame right there. I tcl to the vault door to pick up the Pipboy, then give myself a Bowler Hat by console. I then equip a potion by console that adds some magic effects to the player (should work like a disease in HC mode), one of them is this script. The effect should force the player to equip the Ghoulskin armor, which unequips all headgear slots except 47 (Glasses), in a way that the player can't remove the Ghoulskin armor.

 

The Event is only there to catch stuff that can be equipped regardless of the slot being blocked, for example the Bowler Hat (slot 30/46). The Ghoulskin armor blocks slots 30/46 (which is the slot most hats use) and when it can't be unequipped (done by using the console command instead of the script) the player can still wear the Bowler Hat on top of it. The OnItemEquip event fixes this, it's actually part of the solution and not the problem.

 

//edit: I think I should retain the Player as a property because of the way OnEffectFinish works. From the Wiki, if you don't store refs as Properties, those might already be gone when OnEffectFinish fires.

 

//edit2: This variant also fails: pPlayer.EquipItem(pGhoulskinArmor, abPreventRemoval = true, abSilent = true)

Edited by payl0ad
Link to comment
Share on other sites

I have something similar but with npc and weapon. It works. Though I don`t have function "AddItem" , the "EquipItem" function adds the item in case the item is missing so it`s unnecessary to use both.

akTarget.EquipItem(MyWeapon, true, true)

Maybe faling of your function has something to do with equipping it exactly on player, or maybe you can try to force unequip all required slots before equipping your item.

I think there is a function to unequip all. Don`t know if it can help, but easy to try.

Edited by kitcat81
Link to comment
Share on other sites

Yes the event probably works great the way you have it. And yes, I know what it is for. What I was talking about is the note on the ActiveMagicEffect wiki page that states this:

 

ActiveMagicEffects will also receive events from the Actor they are attached to.

 

Which, by common sense, would mean that the script should already receive the event - OnItemEquipped - from the Actor the effect is running on. If that is true, then you do not need to register for anything. So if the script will receive the events anyway, you do not need to register for them explicitly. That is what I trying to (sort of) explain. I blame my below-average communication skills. Sorry. :blush:

 

What does the following in the spoiler do? It also has the AddItem line commented out as per suggestion by kitcat81.

 

 

 

ScriptName GhoulskinScriptEffect Extends ActiveMagicEffect

; equip a non-removable armor that occupies item slots 31,32,46,48,49,50

Actor ThisActor ; just a normal variable, should also work?

Armor Property pGhoulskinArmor Auto
FormList Property pClothingKeywordsToBlock Auto
Message[] Property pGhoulskinMessages Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
    ThisActor = akTarget
    Debug.MessageBox("OnEffectStart, Actor(" + ThisActor + ")")
    ; ThisActor.AddItem(pGhoulskinArmor, 1, True) <-- commented out as per suggestion by kitcat81 above
    ThisActor.EquipItem(pGhoulskinArmor, True, True) ; culprit
    Debug.MessageBox("IsEquipped(" + pGhoulskinArmor + ") = " + ThisActor.IsEquipped(pGhoulskinArmor))
    pGhoulskinMessages[0].Show()
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
    Debug.MessageBox("OnEffectFinish, Actor(" + ThisActor + ")")
    ; ThisActor.UnequipItem(pGhoulskinArmor, False, True) <-- unnecessary if removing an item also unequips it (hmmm....)
    ThisActor.RemoveItem(pGhoulskinArmor, ThisActor.GetItemCount(pGhoulskinArmor), True)
    pGhoulskinMessages[1].Show()
EndEvent

Event OnItemEquipped(Form akBaseObject, ObjectReference akReference)
    If (akBaseObject.HasKeywordInFormList(pClothingKeywordsToBlock))
        ThisActor.UnequipItem(akBaseobject, False, True)
        pGhoulskinMessages[2].Show()
    EndIf
EndEvent

 

 

 

Edit: Also apologies for not being of much help. Hopefully someone else can help you with your actual issue.

 

Edit 2: To respond to your function issues: the property type should not matter. Armor should work. And the parameters in the function call... if you pass all of them in the right order then you would not need to use the "parameter_name=parameter_value". If you know Python, you can think of it as keyword arguments. For example these should be equivalent (by common sense, I have never tested it now that I think of it, but if Papyrus works logically then they should):

SomeActor.EquipItem(SomeItem, True, True)
SomeActor.EquipItem(akItem=SomeItem, abPreventRemoval=True, abSilent=True)
Edited by Contrathetix
Link to comment
Share on other sites

@kitkat81: Indeed, this partially works. I can EquipItem() the item and it gets added to the inventory, but it still does not equip. If I do UnequipAll(), the player drops everything including the Pipboy. Sadly, the other way, UnequipItemSlot(int) does not do anything for me, neither in script nor in the ingame console.

 

@Contrathetix: You are right, I do still receive the event even when I don't register for it, probably because of the reasons outlined by you. I do bash and batch scripting at work so Papyrus isn't exactly hard to grasp for me. I know my code looks correct, I just don't have a single clue why it doesn't work. Most of what I tried was wild guessing at what doesn't work right except that dreaded one line. Thanks for your input in any case though! :-)

Edited by payl0ad
Link to comment
Share on other sites

@kitkat81: Indeed, this partially works. I can EquipItem() the item and it gets added to the inventory, but it still does not equip. If I do UnequipAll(), the player drops everything including the Pipboy. Sadly, the other way, UnequipItemSlot(int) does not do anything for me, neither in script nor in the ingame console.

 

@Contrathetix: You are right, I do still receive the event even when I don't register for it, probably because of the reasons outlined by you. I do bash and batch scripting at work so Papyrus isn't exactly hard to grasp for me. I know my code looks correct, I just don't have a single clue why it doesn't work. Most of what I tried was wild guessing at what doesn't work right except that dreaded one line. Thanks for your input in any case though! :-)

Interesting. Maybe there are some limitations to redress the Player before the vault exit. Normally UnequipItemSlot should work. Something like this works in my game.

Function UndressPlayer() 
 If  akTarget == Game.GetPlayer()
     PlayerArmor = new Form[0]
       int  i = 0
       int  Stop = 29
       While (i <= Stop)
            Game.GetPlayer().UnequipItemSlot(i)
            i += 1
       EndWhile
 EndIf
EndFunction
Link to comment
Share on other sites

  • Recently Browsing   0 members

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