Jump to content

Any way to import original functions from a prefab (so as to not copy them manually)


Recommended Posts

Hi,

I am doing a change in birdcage.lua

Is it possible to import the functions from the original birdcage.lua, or even call the original ones in my AddPrefabPostInit

I do not wish to copy over literally 7 functions for my change.

 

local function DigestFood(inst, food)
    if food == nil then return false end
    if food.components.edible.foodtype == GLOBAL.FOODTYPE.MEAT then
        --If the food is meat:
            --Spawn an egg.
        inst.components.lootdropper:SpawnLootPrefab("bird_egg")
    else
        local seed_name = string.lower(food.prefab .. "_seeds")
        if Prefabs[seed_name] ~= nil then
            --If the food has a relavent seed type:
                --Spawn 1 or 2 of those seeds.
            local num_seeds = math.random(2)
            for k = 1, num_seeds do
                inst.components.lootdropper:SpawnLootPrefab(seed_name)
            end
                --Spawn regular seeds on a 50% chance.
            if math.random() < 0.5 then
                inst.components.lootdropper:SpawnLootPrefab("seeds")
            end
        else
            --Otherwise...
                --Spawn a poop 1/3 times.
            if math.random() < 0.33 then
                local loot = inst.components.lootdropper:SpawnLootPrefab("guano")
                loot.Transform:SetScale(.33, .33, .33)
            end
        end
    end

    --Refill bird stomach.
    local bird = GetBird(inst)
    if bird and bird:IsValid() and bird.components.perishable then
        bird.components.perishable:SetPercent(1)

        --TODO:Bird dies if too much mmeat is given
        if food.components.edible.foodtype == GLOBAL.FOODTYPE.MEAT and 
            food.components.edible:GetHealth(inst) < 0 then --monster meat is currently the only negative health meat item
            if bird.monsterbelly ~= nil and bird.monsterbelly ~= 0 then 
                bird.monsterbelly = bird.monsterbelly+1
            else
                bird.monsterbelly = 1
            end

            print(bird.monsterbelly )

            if bird.monsterbelly >= 4 then
                --OnBirdStarve(inst, bird)
                inst.AnimState:PlayAnimation("death")
                --PushStateAnim(inst, "idle", false)

                --Put loot on "shelf"
                local loot = SpawnPrefab("smallmeat")
                inst.components.inventory:GiveItem(loot)
                inst.components.shelf:PutItemOnShelf(loot)
            end
        end 
    end
end

 

Link to comment
Share on other sites

what functions exactly you want to change?
All non-local functions can be accessed in AddPrefabPostInit.
And most local functions can be accessed with the upvaluehacker IF you really need to access the local (in 90% of the cases there are better ways to achieve the same result) https://github.com/rezecib/Rezecib-s-Rebalance/blob/master/scripts/tools/upvaluehacker.lua

so you should NOT replace birdcage.lua, but do all changes within modmain.

Edited by Serpens
Link to comment
Share on other sites

8 minutes ago, Serpens said:

what functions exactly you want to change?
All non-local functions can be accessed in AddPrefabPostInit.
And most local functions can be accessed with the upvaluehacker IF you really need to access the local (in 90% of the cases there are better ways to achieve the same result) https://github.com/rezecib/Rezecib-s-Rebalance/blob/master/scripts/tools/upvaluehacker.lua

so you should NOT replace birdcage.lua, but do all changes within modmain.

the functions seem to be local

I just want to do a small change down a stack of 3-4 local functions

can check the upvalue, no other way?

19 minutes ago, Serpens said:

what functions exactly you want to change?
All non-local functions can be accessed in AddPrefabPostInit.
And most local functions can be accessed with the upvaluehacker IF you really need to access the local (in 90% of the cases there are better ways to achieve the same result) https://github.com/rezecib/Rezecib-s-Rebalance/blob/master/scripts/tools/upvaluehacker.lua

so you should NOT replace birdcage.lua, but do all changes within modmain.

For example, here is my full change (makes bird die after being fed 4 monster meat)

It ended up being huge, and I copied over most things

-----------------------------------------------------------------
-- Bird dies if fed too much monster meat
-----------------------------------------------------------------
--TODO: Shorten functions here, and overwrite only (maybe use upvalue hacker)

local function OnBirdStarve(inst, bird)
    if inst.AnimationTask then
        inst.AnimationTask:Cancel()
        inst.AnimationTask = nil
    end
    inst.CAGE_STATE = "_death"

    inst.AnimState:PlayAnimation("death")
    inst.AnimState:PushAnimation("idle"..inst.CAGE_STATE, false)
    --PushStateAnim(inst, "idle", false)

    --Put loot on "shelf"
    local loot = GLOBAL.SpawnPrefab("smallmeat")
    inst.components.inventory:GiveItem(loot)
    inst.components.shelf:PutItemOnShelf(loot)
end

local function DigestFood(inst, food)
    if food == nil then return false end
    if food.components.edible.foodtype == GLOBAL.FOODTYPE.MEAT then
        --If the food is meat:
            --Spawn an egg.
        inst.components.lootdropper:SpawnLootPrefab("bird_egg")
    else
        local seed_name = string.lower(food.prefab .. "_seeds")
        if Prefabs[seed_name] ~= nil then
            --If the food has a relavent seed type:
                --Spawn 1 or 2 of those seeds.
            local num_seeds = math.random(2)
            for k = 1, num_seeds do
                inst.components.lootdropper:SpawnLootPrefab(seed_name)
            end
                --Spawn regular seeds on a 50% chance.
            if math.random() < 0.5 then
                inst.components.lootdropper:SpawnLootPrefab("seeds")
            end
        else
            --Otherwise...
                --Spawn a poop 1/3 times.
            if math.random() < 0.33 then
                local loot = inst.components.lootdropper:SpawnLootPrefab("guano")
                loot.Transform:SetScale(.33, .33, .33)
            end
        end
    end

    --Refill bird stomach.
    local bird = (inst.components.occupiable and inst.components.occupiable:GetOccupant()) or nil
    if bird and bird:IsValid() and bird.components.perishable then
        bird.components.perishable:SetPercent(1)

        --TODO:Bird dies if too much mmeat is given
        if food.components.edible.foodtype == GLOBAL.FOODTYPE.MEAT and 
            food.components.edible:GetHealth(inst) < 0 then --monster meat is currently the only negative health meat item
            if bird.monsterbelly ~= nil and bird.monsterbelly ~= 0 then 
                bird.monsterbelly = bird.monsterbelly+1
            else
                bird.monsterbelly = 1
            end

            print(bird.monsterbelly )

            if bird.monsterbelly >= 4 then
                OnBirdStarve(inst, bird)
            end
        end 
    end
end

local function OnGetItem(inst, giver, item)
    --If you're sleeping, wake up.
    if inst.components.sleeper and inst.components.sleeper:IsAsleep() then
        inst.components.sleeper:WakeUp()
    end

    if item~=nil and item.components.edible ~= nil and item.components.edible.foodtype ~= nil and
        (   item.components.edible.foodtype == GLOBAL.FOODTYPE.MEAT
            or item.prefab == "seeds"
            or Prefabs[string.lower(item.prefab .. "_seeds")] ~= nil
        ) then
        --If the item is edible...
        --Play some animations (peck, peck, peck, hop, idle)
        inst.AnimState:PlayAnimation("peck")
        inst.AnimState:PushAnimation("peck")
        inst.AnimState:PushAnimation("peck")
        inst.AnimState:PushAnimation("hop")
        inst.AnimState:PushAnimation("idle"..inst.CAGE_STATE, true)
        --Digest Food in 60 frames.
        inst:DoTaskInTime(60 * GLOBAL.FRAMES, DigestFood, item)
    end
end

AddPrefabPostInit("birdcage", DigestFood, OnGetItem, OnBirdStarve)
AddPrefabPostInit("birdcage", function (inst)
    if inst ~= nil and inst.components.trader ~= nil then
        inst.components.trader.onaccept = OnGetItem
    end
end)

 

Link to comment
Share on other sites

never saw such code:
AddPrefabPostInit("birdcage", DigestFood, OnGetItem, OnBirdStarve)
what does it? Is it already overwriting the original functions? Or just adding them only accessable by you? Or is this code wrong and not working (because it adds random functins that are not accessable by anyone)

Anyway, if I wanted to make the birds die after eating too much monstermeat I would simply go into OnGetItem (like you more or less did), but not overwrite the function, only add code.

AddPrefabPostInit("birdcage", function (inst)
    if inst ~= nil and inst.components.trader ~= nil then
        local old_onaccept = inst.components.trader.onaccept
        inst.components.trader.onaccept = function(inst, giver, item,...)
             old_onaccept(inst,giver,item,...)
             -- and now check if it was monster meat and do your stuff, maybe with a small DoTaskInTime delay to make sure the bird finished eating.
        end
    end
end)

only small problem is that you can not call the local OnBirdStarve this way. So you have 2 possibilites:
1) Write your own one that is only called when birds dies by monstermeat (this way if your mod breaks, only this death will crash)
2) Use upvaluehacker to get this function and call it.

It mostly depends if you want to change OnBirdStarve. your code above changes it, but I dont see why this is neccessary? You want to play a different death animation? Do you want it only for the monstermeat death? Then use 1).

Edited by Serpens
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...