Jump to content

[Help] - Preventing Custom Item from going into Backpacks/Chests/Etc


Recommended Posts

Hello to All!

EDIT: I have been working on this since yesterday, and now the issue has changed slightly. Please excuse my edits.

I have been working on making some custom items for a friend's character. All the functions he wanted have been completed and I am currently in the process of testing for crashing, balance, code cleanup/commenting and likewise.

I've hit a snag though when it comes to the use of containers such as the backpack, chest, etc. The items I've made are supposed to be character exclusive and undroppable. The character spawns with their exclusive item and that same item is used for various recipes. Once the "fuel" runs out, it reverts back to the original item.

My issue is, when this item is placed in a backpack/container and it's dropped in the world. When the fuel hits zero, the item disappears. It doesn't get added back into the container's inventory nor does it just "loot drop" into the world.

It has to do with the function "OnFinished". This is called when the fuel hits zero, it gets removed, then immediately gives the player the original item. A pseudo "replace" function essentially. I couldn't find any "replace with" function to use.

local function OnFinished(inst)
	local owner = inst.components.inventoryitem:GetGrandOwner()
	local flask = SpawnPrefab("wyrdflask")
	inst:Remove()
	if owner ~= nil then -- CHECK IF THE OWNER ITEM IS VALID IN THE EVENT THE FLASK SOMEHOW ENDS UP IN THE WORLD
		owner.components.inventory:GiveItem(flask)
	else
		inst.components.lootdropper:SpawnLootPrefab("wyrdflask") -- DROPS NORMAL FLASK AS BASIC LOOT IN THE CASE OF ABOVE
	end	
end

Even though the item "undroppable", it isn't immune to container shenanigans such as putting it in a backpack. So if someone puts the crafted item into a backpack or container and it reaches zero, it's gone if that container is dropped anywhere in the world. I did put in a check to see if the owner is nil in the event the item somehow gets dropped into the world, but unfortunately, it sees the container as an owner. I speculated that perhaps the "world" aka nil would cause the item to just "loot drop" into the world, but it just makes it disappear completely. It probably sees the grandowner as Limbo or something, and I unfortunately don't know how to exactly check if "owner = limbo".

It might be better to make it so it cannot go into a backpack/chest/etc in the first place, but I don't know how to go about that. If anyone could provide assistance, I would be extremely grateful.

Thank You!

P.S. If anyone could assist in making the items pickup exclusive by this character named "wyrd", that would also be grand. I've tried using this below at the very bottom of the item's function fn(sim), but when testing, any character I spawn as can pick it up.

	local oldOnPickup = inst.components.inventoryitem.OnPickup
	inst.components.inventoryitem.OnPickup = function(self, pickupguy)
		if pickupguy.prefab == "wyrd" then
			if not self.inst.itemowner then
				self.inst.itemowner = pickupguy
			end
			if pickupguy == self.inst.itemowner then
				oldOnPickup(self, pickupguy)
			elseif pickupguy.components.talker then
				pickupguy.components.talker:Say("That flask is cursed...")
			end
		elseif pickupguy.components.talker then
			pickupguy.components.talker:Say("Definately can't touch this...")
		end
	end

 

wyrdflask_health.lua

Edited by Nominative99
Changes Since Posted. Cleaned up Post and added Script.
Link to comment
Share on other sites

Good news, I've figured out the disappearing issue. I got so wrapped up that I overlooked using "components.container". Disappearing issue solved thankfully.

local function OnFinished(inst)
	local owner = inst.components.inventoryitem.owner
	local flask = SpawnPrefab("wyrdflask")
	inst:Remove()
	if owner ~= nil and owner.components.inventory then -- CHECK IF THE OWNER ITEM IS VALID AND NOT A CONTAINER
		owner.components.inventory:GiveItem(flask)
	elseif owner ~= nil and owner.components.container then -- OR IF THE OWNER IS VALID AND IS A CONTAINER
		owner.components.container:GiveItem(flask)
	else
		inst.components.lootdropper:SpawnLootPrefab("wyrdflask") -- DROPS NORMAL FLASK AS BASIC LOOT IN THE CASE OF ABOVE
	end	
end

I just need assistance on making the item "bag proof" or at least drop into the world if it's in a container. Unfortunately the code (located in first post) I am using to make it a character exclusive pickup is not working. I've tried testing it on characters that are not the character "wyrd", but they are all able to pickup the item and at the same type spit out the taker:Say() comments.

Thank You

Edited by Nominative99
Link to comment
Share on other sites

I've been trying to figure it out and this is what I have that works (so far).

    inst:AddComponent("inventoryitem")
	inst.components.inventoryitem:SetOnPutInInventoryFn(OnPutInInventory)
local function OnPutInInventory(inst)
  print("flask put inventory fn ran")
  local owner = inst.components.inventoryitem:GetGrandOwner()
  --------------
  if owner then
  print("flask picked by", owner.name, owner.prefab) --just for testing
  end
  -------------
  if owner.components.inventory and owner.prefab ~= "wyrd" then 
		inst:DoTaskInTime(0.1, function()
				owner.components.inventory:DropItem(inst)
				owner.components.talker:Say("That flask is cursed...")
        end)
  end
  if owner.components.container then --for chests --test when in backpack with diff owner
  		inst:DoTaskInTime(0.1, function()
				owner.components.container:DropItem(inst)
        end)
   end  
end

In the quick tests I did when it is picked up by someone and if it isn't the character prefab given then it is dropped back down. Also when put in a chest it will get dropped (I think that's what you wanted).

Now it does go in the backpack of the character that can carry it but I haven't tested what happens with a different player taking the backpack.

I found this post helpful, before I was getting some weird issues where the item would drop but also another copy remain in the inventory.

I think it needs more testing still but just posting what I had and can look more into it later if needed. It isn't perfect but maybe it can be of some use.

Also I'll just attach the copy I worked on, I didn't have the art files so just added random DST ones.

wyrdflask_health.lua

Edited by maliblues
Link to comment
Share on other sites

Definitely appreciate it and is practically perfect. With the backpack, any other character can pick it up, the the second it is interacted with the mouse, it pops out which works perfectly really. You most likely noticed the "undroppable" tag, which overrides the drop function, so it still goes into the player's inventory (It's a requirement for the character). I've posted the code below.

"API Friendly Approach" - by Jjmarco

AddComponentPostInit("inventory", function(self)
	-- Adding a new Function "fn"
	
	-- Store the default Item Drop Function
	local DropItem_base = self.DropItem
    function self:DropItem(item, ...)
		-- If the item has the tag "undroppable", do nothing.
		if item:HasTag("undroppable") then
			return false 
			else
			return DropItem_base(self, item, ...) -- otherwise, use default execution
		end
	end
 end)

Is there a way to add an additional check in the PostInit so that the "return false" not only checks for the "undroppable" tag, but also if the player character is "wyrd"? I've been searching around trying a few ends, but I might be applying it incorrectly.

 

Thank You

modmain.lua

Edited by Nominative99
Link to comment
Share on other sites

Wait, I think I got it. Found it after some searching and looking at examples in the workshop.

AddComponentPostInit("inventory", function(self)
	-- Adding a new Function "fn"
	
	-- Store the default Item Drop Function
	local DropItem_base = self.DropItem
    function self:DropItem(item, ...)
		-- If the item has the tag "undroppable", do nothing.
		if item:HasTag("undroppable") and GLOBAL.ThePlayer:HasTag("bartender") then
			return false 
			else
			return DropItem_base(self, item, ...) -- otherwise, use default execution
		end
	end
 end)

Lastly, I did find one bug in regards to the containers. If the player tries to "Store" it into a container, it crashes with "attempt to index local 'owner' (a nil value)"

I made a tweak to check if the owner was "nil", then just return. Prevents it from crashing really. Item goes into the backpack and that's perfectly fine.

local function OnPutInInventory(inst)
	local owner = inst.components.inventoryitem:GetGrandOwner()
	if owner == nil then
	return
	elseif owner.components.inventory and owner.prefab ~= "wyrd" then 
		inst:DoTaskInTime(0.1, function()
				owner.components.inventory:DropItem(inst)
				owner.components.talker:Say("That flask is cursed...")
		end)
	end

	if owner.components.container then --for chests --test when in backpack with diff owner
		inst:DoTaskInTime(0.1, function()
			owner.components.container:DropItem(inst)
		end)
	end  
end

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...