Jump to content

How to add invalid foods for birdcage ?


Recommended Posts

Hi,

I want to add food to the invalid_foods table of the birdcage, so the bird will refuse to eat it. I tried this :
 


AddPrefabPostInit("birdcage", function(inst)

table.insert(invalid_foods, "myfoodprefab")

end)

but i got this crash :


[00:01:04]: error calling PrefabPostInit: birdcage in mod SummerFloraFauna: 
[string "../mods/SummerFloraFauna/scripts/postinit.l..."]:49: bad argument #1 to 'insert' (table expected, got nil)
LUA ERROR stack traceback:
        =[C] in function 'insert'
        ../mods/SummerFloraFauna/scripts/postinit.lua(49,1)
        =(tail call) ?
        =[C] in function 'xpcall'
        scripts/mods.lua(154,1) in function 'mod'
        scripts/mainfunctions.lua(184,1)
        =[C] in function 'SpawnPrefab'
        scripts/mainfunctions.lua(220,1) in function 'SpawnPrefab'
        scripts/util.lua(24,1) in function 'DebugSpawn'
        scripts/consolecommands.lua(159,1) in function 'c_spawn'
        c_spawn("birdcage")(1,1) in main chunk
        =[C] in function 'pcall'
        scripts/mainfunctions.lua(1363,1)	

when i try to spawn a birdcage. So what i am doing wrong ?

Thanks for your help.

Link to comment
Share on other sites

Well, the 'birdcage' is a local variable which you cannot modify directly in AddPrefabPostInit.

There are several ways to modify a local variable, like overriding the birdcage.lua by placing a modified version in script/prefabs folder in you mod folder, or you can override the ShouldAcceptItem function in birdcage. But I think this is a more elegant way:

Quote

 

AddPrefabPostInit("birdcage", function(inst)

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(v.components.trader.test, i)
        if n == "invalid_foods" then
            table.insert(v, "myfoodprefab")
            return
        -- When "invalid_foods" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find invalid_foods, something is wrong!")
            return
        end
        i = i + 1
    end

end)

 

 

Edited by ptr
remove lines which are not useful
Link to comment
Share on other sites

Thanks i'll try it. Should i do something similar if i want to modify the DigestFood function to add more result to the thing i can obtain when feeding a bird ?
(It's the next step of what i want to do, ideally i would like that the bird will give a "monster egg" if you give it a monster food)

Link to comment
Share on other sites

quite similar

Quote

 

AddPrefabPostInit("birdcage", function(inst)

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(v.components.trader.onaccept, i)
        if n == "DigestFood" then
            local oldDigestFood=v
            v = function(inst, giver, item)
                -- TODO:add your own code
                
                -- you can remove this if you don't need the original code
                oldDigestFood(inst, giver, item)
            end
            return
        -- When "DigestFood" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find DigestFood, something is wrong!")
            return
        end
        i = i + 1
    end

end)

 

 

Link to comment
Share on other sites

I tried this :

AddPrefabPostInit("birdcage", function(inst)

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(v.components.trader.onaccept, i)
        if n == "DigestFood" then
            local oldDigestFood=v
            v = function(inst, food)
							  
					if food.components.edible.foodtype == FOODTYPE.MEAT and item.prefab:HasTag("monstermeat") then
						--If the food is meat:
							--Spawn an egg.
						inst.components.lootdropper:SpawnLootPrefab("cutgrass")
					elseif food.components.edible.foodtype == FOODTYPE.MEAT then
						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
					
    local bird = GetBird(inst)
    if bird and bird:IsValid() and bird.components.perishable then
        bird.components.perishable:SetPercent(1)
    end
  -- TODO:add your own code
                
                -- you can remove this if you don't need the original code
                oldDigestFood(inst, food)
            end
            return
        -- When "DigestFood" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find DigestFood, something is wrong!")
            return
        end
        i = i + 1
    end

end) 

But got this :


[00:00:21]: error calling PrefabPostInit: birdcage in mod SummerFloraFauna: 
[string "../mods/SummerFloraFauna/scripts/postinit.l..."]:40: attempt to index global 'v' (a nil value)
LUA ERROR stack traceback:
        ../mods/SummerFloraFauna/scripts/postinit.lua(40,1)
        =(tail call) ?
        =[C] in function 'xpcall'
        scripts/mods.lua(154,1) in function 'mod'
        scripts/mainfunctions.lua(184,1)
        =[C] in function 'SpawnPrefab'
        scripts/mainfunctions.lua(220,1) in function 'SpawnPrefab'
        scripts/mainfunctions.lua(226,1) in function 'SpawnSaveRecord'
        scripts/gamelogic.lua(430,1) in function 'PopulateWorld'
        scripts/gamelogic.lua(680,1) in function 'DoInitGame'
        scripts/gamelogic.lua(798,1) in function 'cb'
	...
        =[C] in function 'GetPersistentString'
        scripts/saveindex.lua(250,1) in function 'Load'
        scripts/gamelogic.lua(982,1) in function 'callback'
        scripts/playerprofile.lua(853,1) in function 'Set'
        scripts/playerprofile.lua(714,1)
        =[C] in function 'GetPersistentString'
        scripts/playerprofile.lua(712,1) in function 'Load'
        scripts/gamelogic.lua(981,1) in main chunk
        =[C] in function 'require'
        scripts/mainfunctions.lua(836,1)	

 

(cutgrass is here only for testing purpose, i plan to change it later)

Edited by Lumina
Link to comment
Share on other sites

And you shouldn't change the parameter list

v = function(inst, food)

which should be

v = function(inst, giver, item)

you can rename 'item' to 'food', but you can't simply remove the 'giver'.

Edited by ptr
Link to comment
Share on other sites

I tried various things to see if the error was related to this, it's one of the change i made trying to see if i can fix it myself.

Now i have another crash :


AddPrefabPostInit("birdcage", function(inst)

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i)
        if n == "DigestFood" then
            local oldDigestFood=v
            v = function(inst, giver, item)
							  
					if food.components.edible.foodtype == FOODTYPE.MEAT and item.prefab:HasTag("monstermeat") then
						--If the food is meat:
							--Spawn an egg.
						inst.components.lootdropper:SpawnLootPrefab("cutgrass")
					elseif food.components.edible.foodtype == FOODTYPE.MEAT then
						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
					
    local bird = GetBird(inst)
    if bird and bird:IsValid() and bird.components.perishable then
        bird.components.perishable:SetPercent(1)
    end
  -- TODO:add your own code
                
                -- you can remove this if you don't need the original code
                oldDigestFood(inst, giver, item)
            end
            return
        -- When "DigestFood" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find DigestFood, something is wrong!")
            return
        end
        i = i + 1
    end

end) 

With this crash :

 


[00:01:22]: error calling PrefabPostInit: birdcage in mod SummerFloraFauna: 
[string "../mods/SummerFloraFauna/scripts/postinit.l..."]:40: attempt to index field 'trader' (a nil value)
LUA ERROR stack traceback:
        ../mods/SummerFloraFauna/scripts/postinit.lua(40,1)
        =(tail call) ?
        =[C] in function 'xpcall'
        scripts/mods.lua(154,1) in function 'mod'
        scripts/mainfunctions.lua(184,1)	

But the birdcage has the trader component so i don't see why it's nil ?
Could it be because if the birdcage is empty the trader component is disabled, hence nil ? And only enabled when active ? Should i add somewhere a test and if yes, where ?

Edit :

        local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i)

this is line 40 in my code.

Edited by Lumina
Link to comment
Share on other sites

So i have no crash but it's not working either. This is the code, with prints :

AddPrefabPostInit("birdcage", function(inst)

					print("function step 1")
if not GLOBAL.TheWorld.ismastersim then
	return inst
end
					print("function step 2")

    local i = 1
    
    while true do
					print("function step 3")
        local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i)
        if n == "DigestFood" then
            local oldDigestFood=v
					print("function step 4")
            v = function(inst, giver, item)
							  
					print("function step 5")
					-- if food.components.edible.foodtype == FOODTYPE.MEAT and food.prefab == "myprefab" then
						--If the food is meat:
							--Spawn an egg.
						-- inst.components.lootdropper:SpawnLootPrefab("cutgrass")
					if food.components.edible.foodtype == FOODTYPE.MEAT then
						inst.components.lootdropper:SpawnLootPrefab("cutgrass")
					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
					
    local bird = GetBird(inst)
    if bird and bird:IsValid() and bird.components.perishable then
        bird.components.perishable:SetPercent(1)
    end
  -- TODO:add your own code
                
                -- you can remove this if you don't need the original code
                oldDigestFood(inst, giver, item)
            end
            return
        -- When "DigestFood" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find DigestFood, something is wrong!")
            return
        end
        i = i + 1
    end

end) 

And in log :


[00:00:28]: function step 1	
[00:00:29]: function step 2	
[00:00:29]: function step 3	
[00:00:29]: function step 3	
[00:00:29]: function step 4	

It seems that i can't reach step 5. When giving the bird a meat, i obtain egg, not cutgrass.

I think i don't have the skill to make this kind of script work, since i don't understand how the n, v are supposed to work (and why it's not working). Thanks again, for all your help and the time you spent helping me. I'm grateful :)

Link to comment
Share on other sites

Sorry for not testing the code. I have made several mistakes. The following are the correct versions:

for "invalid_foods" table

Quote

 

AddPrefabPostInit("birdcage", function(inst)

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(inst.components.trader.test, i)
        if n == "invalid_foods" then
            table.insert(v, "yourprefab")
            GLOBAL.debug.setupvalue(inst.components.trader.test, i, v)
            return
        -- When "invalid_foods" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find invalid_foods, something is wrong!")
            return
        end
        i = i + 1
    end

end)

 

for "DigestFood" function

Quote

 

AddPrefabPostInit("birdcage", function(inst)
    if not GLOBAL.TheWorld.ismastersim then
        return
    end

    local i = 1
    
    while true do
        local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i)
        if n == "DigestFood" then
            local oldDigestFood=v
            v = function(inst, food)
            -- What's happening here: It seems you just want to override the monster meats, so let the original function do the rest.
                if string.find(food.prefab,"monster") then
                    inst.components.lootdropper:SpawnLootPrefab("cutgrass")
                    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)
                    end
                else
                    oldDigestFood(inst, food)
                end
            end
            GLOBAL.debug.setupvalue(inst.components.trader.onaccept, i, v)
            return
        -- When "DigestFood" does not exist. Shouldn't get here unless the birdcage file has been modified.
        elseif not n then
            print("Can't find DigestFood, something is wrong!")
            return
        end
        i = i + 1
    end

end) 

 

 

Link to comment
Share on other sites

Thanks a lot, all is working fine now, it's amazing. I just added the :

 if not GLOBAL.TheWorld.ismastersim then
        return
    end 

to the first code.

And really, mistakes aren't a problem. You helped me, you made me a code that i was totally unable to do alone (neither to fix), and spent time for me, i'm really grateful.

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