Jump to content

Recommended Posts

Unfortunately anything eaten is always removed from your inventory at the end of the eat function, so even if the item has finite uses it both won't have its uses depleted in that function nor will that stop it from being deleted after.

You'll probably need to work around this by making your own eating action and function for the item, entirely separate from the game's eat action, which can get complicated and messy but shouldn't be impossible. The gist of it would be making a custom action with a custom component attached to your food item, forgoing the edible component while also using the finiteuses component. The action can call a function in that custom component that does the same things the normal Eat function does but removing the part that deletes the food and replacing it with code that reduces the uses left on the food item. There will still be problems with this that could come up you may need to account for, as your item isn't technically food.

Hopefully that gives you somewhere to go with it. If you're new to modding dst it might be a bit daunting to do/understand all that so I'm happy to continue helping if its needed. There are also multiple posts on the forums that can help explain how to do a custom action or a custom component.

  • Like 1
6 hours ago, Merkyrrie said:

Unfortunately anything eaten is always removed from your inventory at the end of the eat function, so even if the item has finite uses it both won't have its uses depleted in that function nor will that stop it from being deleted after.

You'll probably need to work around this by making your own eating action and function for the item, entirely separate from the game's eat action, which can get complicated and messy but shouldn't be impossible. The gist of it would be making a custom action with a custom component attached to your food item, forgoing the edible component while also using the finiteuses component. The action can call a function in that custom component that does the same things the normal Eat function does but removing the part that deletes the food and replacing it with code that reduces the uses left on the food item. There will still be problems with this that could come up you may need to account for, as your item isn't technically food.

Hopefully that gives you somewhere to go with it. If you're new to modding dst it might be a bit daunting to do/understand all that so I'm happy to continue helping if its needed. There are also multiple posts on the forums that can help explain how to do a custom action or a custom component.

yea, now I understand how i can do that but i can't find an examples of custom action/component, i'll search more

actually my another idea was that i can use edible component and delete something that was causing item to delete and just somehow add depleting of % (i saw somewhere that a guy used a lighter (from willow) and just deleted fuel component by one line)

ty, i'm new and wasn't waiting for a reply really

6 hours ago, Tejras3 said:

I don't understand what i need to put in my custom component and my head hurts already so I'll do it later ig

Basically just the Eat function from the eater component really, to emulate what already happens when you eat something. Like this maybe:

Spoiler
local CustomEater = Class(function(self, inst)
    self.inst = inst
    
end)


function CustomEater:CustomEat(food, feeder)
  feeder = feeder or self.inst -- This is likely going unused but the oneat pushevent wants it
  -- Everything in this function assumes this component is attached to the Player
  
  eater = self.inst.components.eater -- For easily changing all self function calls to go to the eater component
  
  if eater:PrefersToEat(food) then
        local stack_mult = self.eatwholestack and food.components.stackable ~= nil and food.components.stackable:StackSize() or 1 -- Not needed if the food isn't stackable
        local base_mult = self.inst.components.foodmemory ~= nil and self.inst.components.foodmemory:GetFoodMultiplier(food.prefab) or 1 -- Not needed if Warly won't be eating the food
    	-- Both stack_mult and base_mult can likely be removed, but you'll need to remove their variables below too

		local health_delta = 0
		local hunger_delta = 0
		local sanity_delta = 0

        if self.inst.components.health ~= nil and
            (food.components.edible.healthvalue >= 0 or self:DoFoodEffects(food)) then
            health_delta = food.components.edible:GetHealth(self.inst) * base_mult * eater.healthabsorption
        end

        if self.inst.components.hunger ~= nil then
            hunger_delta = food.components.edible:GetHunger(self.inst) * base_mult * eater.hungerabsorption
        end

        if self.inst.components.sanity ~= nil and
            (food.components.edible.sanityvalue >= 0 or self:DoFoodEffects(food)) then
            sanity_delta = food.components.edible:GetSanity(self.inst) * base_mult * eater.sanityabsorption
        end

		if eater.custom_stats_mod_fn ~= nil then
			health_delta, hunger_delta, sanity_delta = eater.custom_stats_mod_fn(self.inst, health_delta, hunger_delta, sanity_delta, food, feeder)
		end

        if health_delta ~= 0 then
            self.inst.components.health:DoDelta(health_delta * stack_mult, nil, food.prefab)
        end
        if hunger_delta ~= 0 then
            self.inst.components.hunger:DoDelta(hunger_delta * stack_mult)
        end
        if sanity_delta ~= 0 then
            self.inst.components.sanity:DoDelta(sanity_delta * stack_mult)
        end

    	-- This is unneeded unless you want the food to be feedable to something like a bird in a cage, but the bird will need this component then so..
       -- if feeder ~= self.inst and self.inst.components.inventoryitem ~= nil then
       --     local owner = self.inst.components.inventoryitem:GetGrandOwner()
       --     if owner ~= nil and (owner == feeder or (owner.components.container ~= nil and owner.components.container:IsOpenedBy(feeder))) then
       --         feeder:PushEvent("feedincontainer")
       --     end
       -- end

        self.inst:PushEvent("oneat", { food = food, feeder = feeder }) 
        if eater.oneatfn ~= nil then
            eater.oneatfn(self.inst, food)
        end

        if food.components.edible ~= nil then
            food.components.edible:OnEaten(self.inst)
        end

    	-- Change the Remove part of this function to Use for finiteuses. the Use function will handle removing the item instead
        if food:IsValid() and food.components.finiteuses then
			food.components.finiteuses:Use(1)
			-- Assuming this food isn't stackable, if it is you'll need to add a check for that and it might be messy with finiteuses
        end

        self.lasteattime = GetTime()

    	-- This can be removed if Warly won't ever be eating this food
        if self.inst.components.foodmemory ~= nil and not food:HasTag("potion") then
            self.inst.components.foodmemory:RememberFood(food.prefab)
        end

        return true
    end
end

 

If you planned on putting this component on the food instead (so you don't have to add it to players) you'd need to change the self.inst to feeder and make the feeder variable properly register who the doer actually is

  • Like 1
13 hours ago, Merkyrrie said:

Basically just the Eat function from the eater component really, to emulate what already happens when you eat something. Like this maybe:

  Reveal hidden contents
local CustomEater = Class(function(self, inst)
    self.inst = inst
    
end)


function CustomEater:CustomEat(food, feeder)
  feeder = feeder or self.inst -- This is likely going unused but the oneat pushevent wants it
  -- Everything in this function assumes this component is attached to the Player
  
  eater = self.inst.components.eater -- For easily changing all self function calls to go to the eater component
  
  if eater:PrefersToEat(food) then
        local stack_mult = self.eatwholestack and food.components.stackable ~= nil and food.components.stackable:StackSize() or 1 -- Not needed if the food isn't stackable
        local base_mult = self.inst.components.foodmemory ~= nil and self.inst.components.foodmemory:GetFoodMultiplier(food.prefab) or 1 -- Not needed if Warly won't be eating the food
    	-- Both stack_mult and base_mult can likely be removed, but you'll need to remove their variables below too

		local health_delta = 0
		local hunger_delta = 0
		local sanity_delta = 0

        if self.inst.components.health ~= nil and
            (food.components.edible.healthvalue >= 0 or self:DoFoodEffects(food)) then
            health_delta = food.components.edible:GetHealth(self.inst) * base_mult * eater.healthabsorption
        end

        if self.inst.components.hunger ~= nil then
            hunger_delta = food.components.edible:GetHunger(self.inst) * base_mult * eater.hungerabsorption
        end

        if self.inst.components.sanity ~= nil and
            (food.components.edible.sanityvalue >= 0 or self:DoFoodEffects(food)) then
            sanity_delta = food.components.edible:GetSanity(self.inst) * base_mult * eater.sanityabsorption
        end

		if eater.custom_stats_mod_fn ~= nil then
			health_delta, hunger_delta, sanity_delta = eater.custom_stats_mod_fn(self.inst, health_delta, hunger_delta, sanity_delta, food, feeder)
		end

        if health_delta ~= 0 then
            self.inst.components.health:DoDelta(health_delta * stack_mult, nil, food.prefab)
        end
        if hunger_delta ~= 0 then
            self.inst.components.hunger:DoDelta(hunger_delta * stack_mult)
        end
        if sanity_delta ~= 0 then
            self.inst.components.sanity:DoDelta(sanity_delta * stack_mult)
        end

    	-- This is unneeded unless you want the food to be feedable to something like a bird in a cage, but the bird will need this component then so..
       -- if feeder ~= self.inst and self.inst.components.inventoryitem ~= nil then
       --     local owner = self.inst.components.inventoryitem:GetGrandOwner()
       --     if owner ~= nil and (owner == feeder or (owner.components.container ~= nil and owner.components.container:IsOpenedBy(feeder))) then
       --         feeder:PushEvent("feedincontainer")
       --     end
       -- end

        self.inst:PushEvent("oneat", { food = food, feeder = feeder }) 
        if eater.oneatfn ~= nil then
            eater.oneatfn(self.inst, food)
        end

        if food.components.edible ~= nil then
            food.components.edible:OnEaten(self.inst)
        end

    	-- Change the Remove part of this function to Use for finiteuses. the Use function will handle removing the item instead
        if food:IsValid() and food.components.finiteuses then
			food.components.finiteuses:Use(1)
			-- Assuming this food isn't stackable, if it is you'll need to add a check for that and it might be messy with finiteuses
        end

        self.lasteattime = GetTime()

    	-- This can be removed if Warly won't ever be eating this food
        if self.inst.components.foodmemory ~= nil and not food:HasTag("potion") then
            self.inst.components.foodmemory:RememberFood(food.prefab)
        end

        return true
    end
end

 

If you planned on putting this component on the food instead (so you don't have to add it to players) you'd need to change the self.inst to feeder and make the feeder variable properly register who the doer actually is

Wow thank you! So now i need to create a custom action to trigger that custom eat right?

Oki, I was trying to do custom action ALL DAY and finally somehow did it (i'm stupid so i forgor to add something and just realized this in the end), but now it says that variable eater isn't declared in the custom component (line 11,13  for example) and food too, really just dk what to do now xd

Edited by Tejras3
3 hours ago, Tejras3 said:

Oki, I was trying to do custom action ALL DAY and finally somehow did it (i'm stupid so i forgor to add something and just realized this in the end), but now it says that variable eater isn't declared in the custom component (line 11,13  for example) and food too, really just dk what to do now xd

My bad, it needs a local in front of it (I don't know how I missed that)

local eater = self.inst.components.eater
  • Like 1
1 hour ago, Merkyrrie said:

My bad, it needs a local in front of it (I don't know how I missed that)

local eater = self.inst.components.eater

"attempt to index local 'food' (a nil value)" in if eater:PrefersToEat(food) then...

18 minutes ago, Tejras3 said:

"attempt to index local 'food' (a nil value)" in if eater:PrefersToEat(food) then...

Sounds like its not getting the paramaters for the function, what does the call to the function look like in the custom action?

  • Like 1
6 minutes ago, Merkyrrie said:

Sounds like its not getting the paramaters for the function, what does the call to the function look like in the custom action?

image.thumb.png.fd3d902e0b826e86b815915477e3a0a5.png

It'll be no surprise if i done it wrong and actually i can ask now what i need to put instead of obj. to check for that component because it just gives an obj = nil type error or does it just mean that there is no such component in my item?

The parameters in the function call (where you put food and feeder) need to be variables currently accessible in wherever the function is being called. In this case, you want to replace food with "act.invobject" and feeder with "act.doer", as act.invobject in AddAction is the item being used and act.doer is the one doing it.

  • Like 1
21 minutes ago, Merkyrrie said:

The parameters in the function call (where you put food and feeder) need to be variables currently accessible in wherever the function is being called. In this case, you want to replace food with "act.invobject" and feeder with "act.doer", as act.invobject in AddAction is the item being used and act.doer is the one doing it.

Oh oki understand that too now, had no clue about wtf i needed to put there so just copypasted the function... aaaaaaaand IT FINALLY WORKS THANK YOU 

I wouldn't been able to do this without your help cuz i wasn't even thinking about eater component, at first i thought that what i needed was EAT action in actions.lua. thankyouu i can finally sleep

  • Like 1

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
×
  • Create New...