Jump to content

Activate Parent on Containers


Recommended Posts

I'm perplexed again. With Skyrim v1.6.1170.0 and the Creation Kit 2.0 v1.6.1130.0 I'm trying to activate a container via an Activate Parent. I know we're not supposed to be able to do it. The wiki says under References, "Containers appear to be bugged and cannot be activated through any activate parent."

But the Creation Club fishing tanks in the Hearthfires homes use containers that players open via Activators in front of the tanks via Activate Parent in the container reference (under the floor). All I can see happening in the OnActivate event handler in the (decompiled) script attached to each CC fishing tank container (ccBGSSE001_FishTankContainerScript.psc) is self.Activate(Game.GetPlayer(), true).

After that, the next thing in OnActivate is UpdateFish() which looks to me like the OnItemAdded() event handler and AddFish() function have already finished and the container has been closed.

But when I try Activate(Game.GetPlayer(), true) in my own script's OnActivate() event handler attached to the same type of container (without Betheda's script attached), nothing happens. I need the container to open and for the player to be able to put stuff in or take stuff out of the container, so I can watch for that via the OnItemAdded event.

I know I can probably use a dummy NPC (Actor) as the container with ShowGiftMenu() or OpenInventory() (which I can't get to work on a container), but I'd rather use what the CC fish tanks are using, an invisible container in the void.

Has anyone figured this out? I also saw open player inventory from script  (uses Input.Tapkey()) and will probably go with that method if no one knows how the fish tanks are managing to get Activate Parent to work. I'm missing something but I can't figure it out, so it must be something simple right in my face that I'm not noticing. lol

This is the decompiled CC script Bethesda attaches to one of the orange containers bookcases use:

 


;/ Decompiled by Champollion V1.0.0
Source   : ccBGSSSE001_FishTankContainerScript.psc
Modified : 2022-08-26 19:52:07
Compiled : 2022-08-30 14:02:48
User     : builds
Computer : RKVBGSBUILD11
/;
scriptName ccBGSSSE001_FishTankContainerScript extends ObjectReference

	;-- Properties --------------------------------------
message property notAllowedFishMsg auto
{Message displayed when the player places a non-fish form (or the wrong size of fish) in the container.}
keyword property ccBGSSSE001_FishTankMarkerKW02 auto
{The keyword corresponding to the second fish tank fish marker.}
message property fishTankFirstTimeMsg auto
{Display message when a fish tank of this size is used for the first time. Only displays once.}
formlist property placeableFishList auto
{The list of inventory items that can be placed in this tank.}
keyword property ccBGSSSE001_FishTankMarkerKW03 auto
{The keyword corresponding to the third fish tank fish marker.}
message property ccBGSSSE001_fishTankHostileFishMsg auto
{Message displayed when the player places a hostile fish form (i.e. Slaughterfish) in the container.}
Int property maxFishAllowed
    Int function get()
	        return 3
    endfunction
endproperty
keyword property ccBGSSSE001_FishTankMarkerKW01 auto
{The keyword corresponding to the first fish tank fish marker.}
globalvariable property fishTankActivated auto
{Tracks whether or not the player has ever activated a fish tank of this size.}
message property ccBGSSSE001_fishTankRoomLeftMsg auto
{Notification that tells the player how much room is left in the fish tank.}
message property ccBGSSSE001_fishTankNoMoreRoomMsg auto
{Message displayed when the amount of fish in the tank would exceed the tank limit.}
formlist property placeableFishActivatorList auto
{The list of corresponding swimming fish activators for each inventory item.}
formlist property hostileFishList auto
{The list of inventory items of hostile fish.}
	;-- Variables ---------------------------------------
Int currentFishCount = 0
Activator placedFishForm01
Activator placedFishForm02
Activator placedFishForm03
ccBGSSSE001_FishTankCritterScript placedFishRef01
ccBGSSSE001_FishTankCritterScript placedFishRef02
ccBGSSSE001_FishTankCritterScript placedFishRef03
Bool queuedUpdate = false
Bool skipRemovalProcessing = false
	;-- Functions ---------------------------------------
	function UpdateFish()
	    self.GotoState("UpdatingFish")
    if self.Is3DLoaded()
        placedFishRef01 = self.UpdateSingleFish(placedFishForm01 as Form, placedFishRef01, self.GetLinkedRef(ccBGSSSE001_FishTankMarkerKW01))
        placedFishRef02 = self.UpdateSingleFish(placedFishForm02 as Form, placedFishRef02, self.GetLinkedRef(ccBGSSSE001_FishTankMarkerKW02))
        placedFishRef03 = self.UpdateSingleFish(placedFishForm03 as Form, placedFishRef03, self.GetLinkedRef(ccBGSSSE001_FishTankMarkerKW03))
    else
        queuedUpdate = true
    endif
    self.GotoState("")
endfunction
	; Skipped compiler generated GotoState
	function OnItemRemoved(Form akBaseItem, Int aiItemCount, ObjectReference akItemReference, ObjectReference akDestContainer)
	    if placeableFishList.HasForm(akBaseItem)
        if !skipRemovalProcessing
            self.RemoveFish(akBaseItem, aiItemCount)
            currentFishCount -= aiItemCount
        else
            skipRemovalProcessing = false
        endif
    endif
endfunction
	function OnItemAdded(Form akBaseItem, Int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)
	    if placeableFishList.HasForm(akBaseItem)
        if aiItemCount + currentFishCount <= self.maxFishAllowed
            self.AddFish(akBaseItem, aiItemCount)
            currentFishCount += aiItemCount
        else
            ccBGSSSE001_fishTankNoMoreRoomMsg.Show(0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000)
            skipRemovalProcessing = true
            self.RemoveItem(akBaseItem, aiItemCount, true, game.GetPlayer() as ObjectReference)
        endif
    else
        if hostileFishList.HasForm(akBaseItem)
            ccBGSSSE001_fishTankHostileFishMsg.Show(0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000)
        else
            notAllowedFishMsg.Show(0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000)
        endif
        self.RemoveItem(akBaseItem, aiItemCount, true, game.GetPlayer() as ObjectReference)
    endif
endfunction
	function MakeFishPanic()
	    if placedFishRef01
        placedFishRef01.TryToMoveToNextMarker(true)
    endif
    if placedFishRef02
        placedFishRef02.TryToMoveToNextMarker(true)
    endif
    if placedFishRef03
        placedFishRef03.TryToMoveToNextMarker(true)
    endif
endfunction
	function RemoveFish(Form akFish, Int fishCount)
	    Activator fishActivator = placeableFishActivatorList.GetAt(placeableFishList.Find(akFish)) as Activator
    if !fishActivator
        return 
    endif
    while fishCount > 0
        if placedFishForm01 == fishActivator
            placedFishForm01 = none
        elseif placedFishForm02 == fishActivator
            placedFishForm02 = none
        elseif placedFishForm03 == fishActivator
            placedFishForm03 = none
        endif
        fishCount -= 1
    endwhile
endfunction
	ccBGSSSE001_FishTankCritterScript function UpdateSingleFish(Form targetFish, ccBGSSSE001_FishTankCritterScript placedFishRef, ObjectReference targetMarker)
	    ccBGSSSE001_FishTankCritterScript returnFishRef
    if placedFishRef
        placedFishRef.StopPathing()
        placedFishRef.Disable(false)
        placedFishRef.Delete()
    endif
    if targetFish
        returnFishRef = targetMarker.PlaceAtMe(targetFish, 1, false, false) as ccBGSSSE001_FishTankCritterScript
        returnFishRef.StartPathing(targetMarker)
        while !returnFishRef.Is3DLoaded()
            utility.Wait(0.100000)
        endwhile
        returnFishRef.SetScale(0.750000)
        utility.Wait(utility.RandomFloat(0.000000, 0.300000))
    endif
    return returnFishRef
endfunction
	function AddFish(Form akFish, Int fishCount)
	    Activator fishActivator = placeableFishActivatorList.GetAt(placeableFishList.Find(akFish)) as Activator
    if !fishActivator
        return 
    endif
    while fishCount > 0
        if !placedFishForm01
            placedFishForm01 = fishActivator
        elseif !placedFishForm02
            placedFishForm02 = fishActivator
        elseif !placedFishForm03
            placedFishForm03 = fishActivator
        endif
        fishCount -= 1
    endwhile
endfunction
	; Skipped compiler generated GetState
	function OnActivate(ObjectReference akActionRef)
	    ccBGSSSE001_fishTankRoomLeftMsg.Show((self.maxFishAllowed - currentFishCount) as Float, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000)
    if fishTankActivated.GetValueInt() == 0
        fishTankFirstTimeMsg.Show(0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000)
        fishTankActivated.SetValue(1 as Float)
    endif
    self.Activate(game.GetPlayer() as ObjectReference, true)
    utility.Wait(0.250000)
    self.UpdateFish()
endfunction
	function OnLoad()
	    if queuedUpdate
        queuedUpdate = false
        self.UpdateFish()
    endif
endfunction
	;-- State -------------------------------------------
state UpdatingFish
	    function UpdateFish()
	        ; Empty function
    endfunction
endstate


 

Link to comment
Share on other sites

I've never had trouble opening a container from a script. I'm not sure what activate parent means though. From what I understand, you have an activator that when activated will open a linked container. I just tested this simple script and it worked fine for me: 

ObjectReference property TG06_MarkarthWizardsEnableMarker Auto ;in the empty interior cell aaaMarkers
Container property PlayerHouseChest Auto
ObjectReference property containerRef Auto

Event OnInit()
    containerRef = TG06_MarkarthWizardsEnableMarker.placeAtMe(PlayerHouseChest, 1, true)
EndEvent 

Event OnActivate(ObjectReference akActionRef)
    if akActionRef == Game.GetPlayer()
        containerRef.activate(Game.GetPlayer())
    Endif
EndEvent

 

  • Like 1
Link to comment
Share on other sites

I'm not sure what's going on either, @dylbill. Thanks for the example, that's exactly what I'd expect. Activate Parent on a reference just allows a different activator to activate something, which is how doors get activated from levers and such.

That's working. I have a regular Activator (trigger) in a specific location and I can activate it fine. It then does send the activation event to the script attached to the container. I.e. in the script on the container using the Activate Parent, this debug message gets logged:

	;this script is on the container with the Activate Parent
	event OnActivate(ObjectReference akActionRef)
	     Debug.Trace("OnActivate begins")   ;this is being logged, so the event is triggering
	     self.Activate(akActionRef, true)   ;nothing happens
	endevent
	

I ran into several other posts stating the same thing when I was looking for a solution (that Activate() is doing nothing) and no one seems to know what's going on. I'm missing something but I don't know what.

In the same mod, I've got a Creation Club fish tank not far away with an Activate Parent activating a container via an Activator Parent and it's working fine. I put a barrel on the floor to test, then put an Activator (trigger) beside it and set that trigger as the Activate Parent on the barrel and the barrel won't open when no script should even be necessary. Activate Parent should simply pass the OnActivate event from the trigger to the barrel and it does but I can't get the barrel to open when Activate Parent is used. I need the visual/manual inventory UI so the player can put stuff into the barrel (or whatever container) and take stuff out. I then check what's in there when OnClose is triggered, but the inventory UI never opens.

Link to comment
Share on other sites

Use getLinkedRef().activate( akActionRef, True) instead, and place the script on the activator that gets activated, not the container you want opened.
The activate parent is useless, not involved in this use case, so you need to script it, and use the script to activate the real container.
Perhaps getLinkedRef is not what you want... you could just as well use a property to link the activator and container together, which is many cases is easier.

 

  • Like 1
Link to comment
Share on other sites

I think the CC Fish gets away with it because it calls Game.GetPlayer() instead of using akActionRef.  Testing would be needed to determine if that is truly the case.  It is the only obviously visible difference.

  • Like 1
Link to comment
Share on other sites

2 hours ago, xkkmEl said:

Use getLinkedRef().activate( akActionRef, True) instead, and place the script on the activator that gets activated, not the container you want opened.
The activate parent is useless, not involved in this use case, so you need to script it, and use the script to activate the real container.
Perhaps getLinkedRef is not what you want... you could just as well use a property to link the activator and container together, which is many cases is easier.

 

Thanks for the suggestion, @xkkmEl. That did the trick and I don't know if I would have thought of it before clawing my eyes out. lol

I still wonder how the Creation Club fish tank containers manage to open when they use Activate Parent links to activators in front of each tank.

Link to comment
Share on other sites

1 hour ago, IsharaMeradin said:

I think the CC Fish gets away with it because it calls Game.GetPlayer() instead of using akActionRef.  Testing would be needed to determine if that is truly the case.  It is the only obviously visible difference.

I noticed that and tried it because I couldn't see any other difference. It shouldn't matter when akActionRef is PlayerRef / Game.GetPlayer(). But I did change it to self.Activate(Game.GetPlayer(), true) (and without true) and still no luck. Good suggestion though.

Link to comment
Share on other sites

1 hour ago, Sirgallyhave said:

I still wonder how the Creation Club fish tank containers manage to open when they use Activate Parent links to activators in front of each tank.

Perhaps you need to block activation to make it work?  The use of self.activate( akActivatorRef, true) suggests it is meant to be setup that way.  I'm just guessing, but it could be that it does work, twice!??

Link to comment
Share on other sites

16 hours ago, xkkmEl said:

Perhaps you need to block activation to make it work?  The use of self.activate( akActivatorRef, true) suggests it is meant to be setup that way.  I'm just guessing, but it could be that it does work, twice!??

That's what I ran into when I was googling around initially. Someone mentioned enabling Parent Activate Only which is a checkbox on the Activate Parent tab. I thought maybe turning that on would fix things by blocking activation on the chest itself, but it had no effect, unfortunately, and the Creation Club containers don't do it.

The way they deal with it in the CC fish tanks is by putting the containers in the void, so the player can't activate them directly. They put Activators (trigger boxes) in front of the fish tanks (which are just static objects) and make the trigger boxes the Activate Parent for each tank with the actual containers under the floor in the void, so no one can get at them to activate them directly.

It's so strange that it works when I can't see any difference between how the CC containers are doing things to how I'd set things up before.

In any case, your suggestion worked and that's what matters (to me) the most, so I can get back to work. 😄 Thanks again for taking the time to help out, I appreciate it and your suggestion works perfectly.

Link to comment
Share on other sites

Bethesda activation scripts often have this bit of code:

event onCellAttach()
	blockActivation()
endEvent

This is what I was referring to...  In my initial experiements with ore veins, I had a lot of trouble understanding how the activation worked (and not!).  Blocking activation is a large part of why it works (and doesn't!).

In your case, the reference to "selft.activate( akActionRef, true)" strongly suggests the script's OnActivate was expecting this to be in place.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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