Lumina Posted September 10, 2017 Share Posted September 10, 2017 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 More sharing options...
ptr Posted September 10, 2017 Share Posted September 10, 2017 (edited) 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 September 10, 2017 by ptr remove lines which are not useful Link to comment Share on other sites More sharing options...
Lumina Posted September 10, 2017 Author Share Posted September 10, 2017 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 More sharing options...
ptr Posted September 10, 2017 Share Posted September 10, 2017 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 More sharing options...
Lumina Posted September 10, 2017 Author Share Posted September 10, 2017 (edited) 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 September 10, 2017 by Lumina Link to comment Share on other sites More sharing options...
alainmcd Posted September 10, 2017 Share Posted September 10, 2017 Shouldn't that be local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i) ? Link to comment Share on other sites More sharing options...
ptr Posted September 10, 2017 Share Posted September 10, 2017 Oh, sorry. I made a typo: (line 6) local n,v = GLOBAL.debug.getupvalue(v.components.trader.onaccept, i) it should be local n,v = GLOBAL.debug.getupvalue(inst.components.trader.onaccept, i) Link to comment Share on other sites More sharing options...
ptr Posted September 10, 2017 Share Posted September 10, 2017 (edited) 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 September 10, 2017 by ptr Link to comment Share on other sites More sharing options...
Lumina Posted September 10, 2017 Author Share Posted September 10, 2017 (edited) 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 September 10, 2017 by Lumina Link to comment Share on other sites More sharing options...
alainmcd Posted September 10, 2017 Share Posted September 10, 2017 Missing if not GLOBAL.TheWorld.ismastersim then return inst end at the start of your AddPrefabPostInit, perhaps? Link to comment Share on other sites More sharing options...
Lumina Posted September 10, 2017 Author Share Posted September 10, 2017 Yes, totally this. I'm sorry, i should had got the idea to add this myself, usually i'm cautious about this kind of check... Thanks. Link to comment Share on other sites More sharing options...
Lumina Posted September 10, 2017 Author Share Posted September 10, 2017 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 More sharing options...
ptr Posted September 10, 2017 Share Posted September 10, 2017 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 More sharing options...
Lumina Posted September 11, 2017 Author Share Posted September 11, 2017 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now