Jump to content

Replanted Berry bush regrowth time does not increase after harvesting


aat
  • DLC VERSION - IMPORTANT!: Vanilla - NO DLC, Reign of Giants, Shipwrecked, Hamlet Pending

The time to regrow for a replanted Berry Bush is supposed to increases, to a maximum of 7 days, when the Berry Bush has been harvested multiple times since it was last fertilized. This is according to the wiki but also the lines of codes in berrybush.lua

However, there are two major bugs in the current implementation

1. Bug in getregentimefn in berrybush.lua
The function that calculates the regrowth time in berrybush.lua is

local function getregentimefn(inst)
	if inst.components.pickable then
		local num_cycles_passed = math.min(inst.components.pickable.max_cycles - inst.components.pickable.cycles_left, 0)
		return TUNING.BERRY_REGROW_TIME + TUNING.BERRY_REGROW_INCREASE*num_cycles_passed+ math.random()*TUNING.BERRY_REGROW_VARIANCE
	else
		return TUNING.BERRY_REGROW_TIME
	end
end

but num_cycles_passed is always zero, because max_cycles-cycles_left is always positive and the math.min will always pick up the zero
This bug can be fixed by replacing math.min with math.max. See also the correct DST version below:

local function getregentimefn_normal(inst)
    if not inst.components.pickable then
        return TUNING.BERRY_REGROW_TIME
    end
    --V2C: nil cycles_left means unlimited picks, so use max value for math
    local max_cycles = inst.components.pickable.max_cycles
    local cycles_left = inst.components.pickable.cycles_left or max_cycles
    local num_cycles_passed = math.max(0, max_cycles - cycles_left)
    return TUNING.BERRY_REGROW_TIME + TUNING.BERRY_REGROW_INCREASE * num_cycles_passed + TUNING.BERRY_REGROW_VARIANCE * math.random()
end

2. Bug in Pickable:Pick in pickable.lua 
The getregentimefn function is only called when a whitered berrybush is fertilized, not when it is picked. This means that even fixing the above bug in getregentimefn, the regrowth time won't actually increase as the bush is harvested. See the Pickable:Pick function below, which calculates the next regrowth time after a berrybush is picked:

function Pickable:Pick(picker)
    if self.canbepicked and self.caninteractwith then

		if self.transplanted then
			if self.cycles_left ~= nil then
				self.cycles_left = self.cycles_left - 1
			end
		end

		if self.protected_cycles ~= nil then
			self.protected_cycles = self.protected_cycles - 1
			if self.protected_cycles <= 0 then
                if not self:IsWithered() then
                    self:MakeWitherable()
                end
            end
		end
		
		local loot = nil
        if picker and picker.components.inventory and self.product then        	
            loot = SpawnPrefab(self.product)

            if loot then
	            if self.numtoharvest > 1 and loot.components.stackable then
	            	loot.components.stackable:SetStackSize(self.numtoharvest)	            	
	            end

				self.inst:ApplyInheritedMoisture(loot)

		        picker:PushEvent("picksomething", {object = self.inst, loot= loot})
                picker.components.inventory:GiveItem(loot, nil, Vector3(TheSim:GetScreenPos(self.inst.Transform:GetWorldPosition())))
            end
        end
        
        if self.onpickedfn then
            self.onpickedfn(self.inst, picker, loot)
        end
       
        self.canbepicked = false
        self.hasbeenpicked = true
        
        if not self.paused and not self.withered and self.baseregentime and (self.cycles_left == nil or self.cycles_left > 0) and self.inst:IsValid() then
        	self.regentime = self.baseregentime * self:GetGrowthMod()
			self.task = self.inst:DoTaskInTime(self.regentime, OnRegen, "regen")
			self.targettime = GetTime() + self.regentime
		end
        
        self.inst:PushEvent("picked", {picker = picker, loot = loot, plant = self.inst})
    end
end

This can be fixed by adding the option to use self.getregentimefn if it exist, just like the DST code does. Here how I fixed it in my Miscellaneous Tweaks mod:

-- Pickable:Pick bugfix for vanilla and DLCs
local function PickablePickBugFix(inst)
    function inst:Pick(picker)
        if self.canbepicked and self.caninteractwith then
            if self.transplanted and self.cycles_left ~= nil then
                self.cycles_left = math.max(0, self.cycles_left - 1)
            end

            if enabledAnyDLC then
                if self.protected_cycles ~= nil then
                    self.protected_cycles = self.protected_cycles - 1
                    if self.protected_cycles <= 0 then
                        if not self:IsWithered() then
                            self:MakeWitherable()
                        end
                    end
                end
            end

            local loot = nil
            if picker and picker.components.inventory and self.product then
                loot = GLOBAL.SpawnPrefab(self.product)

                if loot then
                    if self.numtoharvest > 1 and loot.components.stackable then
                        loot.components.stackable:SetStackSize(self.numtoharvest)
                    end

                    -- Moisture handling, ROG
                    if enabledROG then
                        local targetMoisture = 0

                        if self.inst.components.moisturelistener then
                            targetMoisture = self.inst.components.moisturelistener:GetMoisture()
                        elseif self.inst.components.moisture then
                            targetMoisture = self.inst.components.moisture:GetMoisture()
                        else
                            targetMoisture = GLOBAL.GetWorld().components.moisturemanager:GetWorldMoisture()
                        end

                        loot.targetMoisture = targetMoisture
                        loot:DoTaskInTime(2*GLOBAL.FRAMES, function()
                            if loot.components.moisturelistener then 
                                loot.components.moisturelistener.moisture = loot.targetMoisture
                                loot.targetMoisture = nil
                                loot.components.moisturelistener:DoUpdate()
                            end
                        end)
                    -- Moisture handling, SHIP and PORKLAND
                    elseif enabledSHIP or enabledPORK then
                        self.inst:ApplyInheritedMoisture(loot)
                    end

                    picker:PushEvent("picksomething", {object = self.inst, loot= loot})
                    picker.components.inventory:GiveItem(loot, nil, GLOBAL.Vector3(GLOBAL.TheSim:GetScreenPos(self.inst.Transform:GetWorldPosition())))
                end
            end

            if self.onpickedfn then
                self.onpickedfn(self.inst, picker, loot)
            end
            self.canbepicked = false
            if enabledAnyDLC then
                self.hasbeenpicked = true
            end

            local can_regen = not self.paused and (self.cycles_left == nil or self.cycles_left > 0)
            -- Vanilla: check on regentime only
            if vanilla then
                can_regen = can_regen and self.regentime
            -- DLCs: also check withered and baseregentime
            elseif enabledAnyDLC then 
                can_regen = can_regen and not self.withered and self.baseregentime
                -- PORK: also check inst:IsValid()
                if enabledPORK then
                    can_regen = can_regen and self.inst:IsValid()
                end
            end

            if can_regen then
                -- Vanilla: use regentime if getregentimefn not exists
                if vanilla then
                    self.regentime = self.getregentimefn and self.getregentimefn(self.inst) or self.regentime
                -- ROG: use baseregentime if getregentimefn not exists, unless IsSpring
                elseif enabledROG and GLOBAL.GetSeasonManager():IsSpring() then
                        local time = self.getregentimefn and self.getregentimefn(self.inst) or self.baseregentime
                        self.regentime = time * TUNING.SPRING_GROWTH_MODIFIER
                -- SHIP and PORK: use baseregentime if getregentimefn not exists and GetGrowthMod
                elseif enabledSHIP or enabledPORK then
                    local time = self.getregentimefn and self.getregentimefn(self.inst) or self.baseregentime
                    self.regentime = time * self:GetGrowthMod()
                end
                self.task = self.inst:DoTaskInTime(self.regentime, function(inst)
                    if inst.components.pickable then inst.components.pickable:Regen() end
                end, "regen")
                self.targettime = GLOBAL.GetTime() + self.regentime
            end

            local pickeddata = { picker = picker, loot = loot }
            if enabledAnyDLC then
                pickeddata.plant = self.inst
            end
            self.inst:PushEvent("picked", pickeddata)
        end
    end
end

The function handles correctly all the various DLC branches, as there are 4 different versions of Pickable:Pick depending on the DLC enabled. For the fix available as a mod, see Miscellaneous Tweaks on the Steam workshop


Steps to Reproduce

Just look at the original code in berrybush.lua and pickable.lua. The bug can be reproduced by removing the variance and printing the regrowth time with the following mod snippet:

TUNING.BERRY_REGROW_VARIANCE = 0

local function PickableInit(inst)
    local orig_getregentimefn = inst.components.pickable.getregentimefn
    inst.components.pickable.getregentimefn = function(inst)
        print("/ original getregentimefn " .. tostring(orig_getregentimefn(inst)))
        return orig_getregentimefn(inst)
    end
end
AddPrefabPostInit("berrybush", PickableInit)
AddPrefabPostInit("berrybush2", PickableInit)

 




User Feedback


There are no comments to display.



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...