Charsis Posted April 17, 2019 Share Posted April 17, 2019 I know you need AddPrefabPostInit("prefabname", functionImadename) at end of file to make edit for prefab, but not sure about rest. Have tried copy loot table and edit it, but not sure how to go from that to adding new loot table to the prefab. And what if want edit existing function of the prefab as well? Could I have examples pls? Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/ Share on other sites More sharing options...
Ultroman Posted April 17, 2019 Share Posted April 17, 2019 What do you want to achieve with your mod? Change the loot table of a certain prefab? Add a loot table to a custom prefab? Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1179835 Share on other sites More sharing options...
Charsis Posted April 17, 2019 Author Share Posted April 17, 2019 Yes, change loot table of prefab like hippopotamoose for example. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1179843 Share on other sites More sharing options...
Ultroman Posted April 17, 2019 Share Posted April 17, 2019 This thread should help. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1179854 Share on other sites More sharing options...
Charsis Posted April 17, 2019 Author Share Posted April 17, 2019 (edited) Looks very overcomplicated and restrictive for what I am doing, can I just not declare local loot table, then have it apply post init with a function? I actually trying claw palm tree and it look like its loot structured completely differently and thought this would change loot but not working I put this in new file under scripts/prefabs of my mod and import file in modmain. Edited April 17, 2019 by Charsis Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1179882 Share on other sites More sharing options...
Ultroman Posted April 17, 2019 Share Posted April 17, 2019 (edited) EDIT: OOPS! I accidentally went to talking about deciduous trees instead. They work exactly the same, though, so the code is still solid, and all my points about the problems of working with these tree scripts are still valid for e.g. claw trees. I've left the whole deciduous tree info and code here, and just made a new similar script for the claw trees at the bottom. Nope. GetBuild() is a local function in deciduoustree.lua and 'prefabs' and 'builds' are local variables in it. You cannot access or change them in any way. These trees do not want to be messed with. Absolutely everything about them is local. I don't think I've seen a less moddable prefab in my entire "career" in modding. And they change their loot table every time they grow leaves, and they push no events whatsoever that you can listen to. The only thing you can do, is mess with their components, one of which is their lootdropper. I would do something as idiotic as running a periodic task every 10 seconds on them, and manually set a new loot table on them. If you look at their code, they use the lootdropper like so: inst.components.lootdropper:SetLoot(GetBuild(inst).short_loot) As you've discovered, GetBuild(inst) gets one of the builds found in the builds, and they then access short_loot on it. This line of code would translate to this for the 'normal' build: inst.components.lootdropper:SetLoot( {"log", "log"} ) All this does, is tell it to drop exactly two logs when it is killed. It's just a list of prefab names to drop. Here's the problem with this...all deciduous trees ARE THE SAME PREFAB *facepalm*. Luckily, there is ONE thing you can access which identifies which kind it is: inst.build inst.build will either give you: nil, which defaults to "normal" "normal" "barren" "red" "orange" "yellow" "poison" So, what we have to do is actually pretty simple, and we can steal a whole lot of the original code for this. I always like a challenge, and these trees being so darn stubborn peaked my interest. If I'm not mistaken, this should work. Put it all in your modmain.lua. You can edit all the loot directly in the table at the top. -- We steal their idea of listing things by build, but this is our own list, -- which has nothing to do with theirs, since we cannot access it. -- Change these loot tables to whatever you like. local builds = { normal = { --Green normal_loot = {"log", "log"}, short_loot = {"log"}, tall_loot = {"log", "log", "log", "acorn"}, }, barren = { normal_loot = {"log", "log"}, short_loot = {"log"}, tall_loot = {"log", "log", "log"}, }, red = { normal_loot = {"log", "log"}, short_loot = {"log"}, tall_loot = {"log", "log", "log", "acorn"}, }, orange = { normal_loot = {"log", "log"}, short_loot = {"log"}, tall_loot = {"log", "log", "log", "acorn"}, }, yellow = { normal_loot = {"log", "log"}, short_loot = {"log"}, tall_loot = {"log", "log", "log", "acorn"}, }, poison = { normal_loot = {"livinglog", "acorn", "acorn"}, short_loot = {"livinglog", "acorn"}, tall_loot = {"livinglog", "acorn", "acorn", "acorn"}, }, } -- We also steal their way of accessing things by build. local function GetBuild(inst) local build = builds[inst.build] if build == nil then return builds["normal"] end return build end -- Some drops are done directly in the code, and you cannot touch those. -- It is things like extra living logs, extra acorns and nightmare fuel. -- Sadly, we can only change the base loot. AddPrefabPostInit("deciduoustree", function(inst) inst:DoPeriodicTask(10, function(inst) if inst:HasTag("stump") then -- If the tree is a stump, then the lootdropper's DropLoot() function -- is not called, so you cannot change the loot from stumps. -- It is determined directly in code, so we skip those. return end if inst:HasTag("burnt") then -- What to drop if it is burnt? -- It already automatically drops charcoal, and you can't change that. -- It's in code separate from the rest of the drop table code. -- But it does call DropLoot(), so it will still drop the loot you've set. -- If you just want it to drop the normal loot when burnt, delete this -- whole if-statement. return end -- Now for the normal loot. This is where we use our custom loot tables. -- Just like the original code, we use the growable component to determine -- which loot to assign. We also use inst.build, just like the original code. if inst.components.growable then if inst.components.growable.stage == 1 then inst.components.lootdropper:SetLoot(GetBuild(inst).short_loot) elseif inst.components.growable.stage == 2 then inst.components.lootdropper:SetLoot(GetBuild(inst).normal_loot) else inst.components.lootdropper:SetLoot(GetBuild(inst).tall_loot) end end end end The way I figured all this out, was just looking through the original code. If they hadn't exposed inst-build, this would be mostly impossible. We would have been left with only one option; to give all deciduous trees the exact same loot, only changing it by how much they've grown. Obviously, this would have been bad, since the poison trees have such special loot, and some types don't drop acorns. It took me about an hour to compile enough knowledge about the workings of the trees, to write all the information in the comments, and know how to properly handle stumps and burnt trees. Programming is very complicated and a lot of work. Very nearly always EDIT: Here's the claw tree code instead xD Put it all in your modmain.lua. -- We steal their idea of listing things by build, but this is our own list, -- which has nothing to do with theirs, since we cannot access it. -- Change these loot tables to whatever you like. local builds = { normal = { file="claw_tree_build", prefab_name="clawpalmtree", normal_loot = {"cork", "cork"}, short_loot = {"cork"}, tall_loot = {"cork", "cork", "cork"}, }, } -- We also steal their way of accessing things by build. local function GetBuild(inst) local build = builds[inst.build] if build == nil then return builds["normal"] end return build end -- Some drops are done directly in the code, and you cannot touch those. -- It is things like extra cork. Sadly, we can only change the base loot. AddPrefabPostInit("clawpalmtree", function(inst) inst:DoPeriodicTask(10, function(inst) if inst:HasTag("stump") then -- If the tree is a stump, then the lootdropper's DropLoot() function -- is not called, so you cannot change the loot (cork) from stumps. -- It is determined directly in code, so we skip those. return end if inst:HasTag("burnt") then -- What to drop if it is burnt? -- It already automatically drops charcoal, and you can't change that. -- It's in code separate from the rest of the drop table code. -- But it does call DropLoot(), so it will still drop the loot you set. -- If you just want it to drop the normal loot when burnt, delete this -- whole if-statement. return end -- Now for the normal loot. This is where we use our custom loot tables. -- Just like the original code, we use the growable component to determine -- which loot to assign. We also use inst.build, just like the original code. if inst.components.growable then if inst.components.growable.stage == 1 then inst.components.lootdropper:SetLoot(GetBuild(inst).short_loot) elseif inst.components.growable.stage == 2 then inst.components.lootdropper:SetLoot(GetBuild(inst).normal_loot) else inst.components.lootdropper:SetLoot(GetBuild(inst).tall_loot) end end end end Edited April 17, 2019 by Ultroman Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1179948 Share on other sites More sharing options...
Charsis Posted April 17, 2019 Author Share Posted April 17, 2019 Check all tree in vicinity if not world every 10 second? I think I will do the bad way to mod their loot then instead if can't detect when tree is chopped, dug or burnt. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180008 Share on other sites More sharing options...
Ultroman Posted April 17, 2019 Share Posted April 17, 2019 (edited) No no. This code just puts a script on each of the trees (there aren't THAT many) which runs every 10 seconds. You can change it to 60 seconds if you want. The code itself is very quick and benign. It's FAR better than overwriting game files. It CAN detect whether the tree is a stump or burnt, and you can add loot to it if it is burnt. Only the loot for the stump is locked. It's up to you, of course, but overwriting game files is really bad practice. It the penultimate bad practice. If you're planning on ever releasing it, you really shouldn't. If it's just for yourself, go for it Edited April 17, 2019 by Ultroman Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180010 Share on other sites More sharing options...
Charsis Posted April 17, 2019 Author Share Posted April 17, 2019 If I change lots of loots of things doing things this way is bad for CPU definitely. If no way to detect tree chop or stage then no point doing this way imo. No point wasting time for bad result. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180020 Share on other sites More sharing options...
Developer bizziboi Posted April 17, 2019 Developer Share Posted April 17, 2019 You don't have to do it on a timer. Growable component can call a function when a new stage is reached (Growable:SetOnGrowthFn(fn)), you could respond to that. Alternatively, you would mod LootDropper:GenerateLoot with a if self.customlootfn then return self.customlootftn() end and have the prefabs you want to respond differently in different situations hook up this function? Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180025 Share on other sites More sharing options...
Ultroman Posted April 17, 2019 Share Posted April 17, 2019 Bizziboi in from the sideline with a big play! You obviously read the code with a better overview than me. But he still won't be able to affect the extra loot from burnt trees, or change the loot from digging up stumps, right? Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180046 Share on other sites More sharing options...
Charsis Posted April 17, 2019 Author Share Posted April 17, 2019 2 hours ago, bizziboi said: You don't have to do it on a timer. Growable component can call a function when a new stage is reached (Growable:SetOnGrowthFn(fn)), you could respond to that. Alternatively, you would mod LootDropper:GenerateLoot with a if self.customlootfn then return self.customlootftn() end and have the prefabs you want to respond differently in different situations hook up this function? What do you mean with Growable component? How can I use this? And also same with LootDropper method, really confused about structure and syntax. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180059 Share on other sites More sharing options...
Developer bizziboi Posted April 17, 2019 Developer Share Posted April 17, 2019 @Charsis Sorry, too pressed for time to dive deep, but if @Ultroman gets what I mean maybe he's willing to help you along. @Ultromanthe burnt trees is harder because of the local functions, but you could override the entire surrounding function with a similar function that just adds in the callback functionality, or, if you really want to - you could for example override burnable:SetOnBurntFn to stub in your own function, you can also access and replace local function through digging into stuff with debug.getupvalue/setupvalue, but it gets hairy - the local functions are not mod-friendly. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180061 Share on other sites More sharing options...
Ultroman Posted April 18, 2019 Share Posted April 18, 2019 (edited) You could make use of Rezecib's upvalue API to access the local function more easily, but I have no experience with that. As bizziboi says, it gets hairy, so using an API made by a very respectable modder could be a way to do that, if it's that important to you. I don't have time to sit down and learn about it right now, though. If you use SetOnGrowth then the trees won't have their loot changed after loading a game, until they grow again, since (if I'm reading it correctly) ongrowth is not called during load, unless it is its time to grow. Other than that, the solution is fine, and you could just manually call our function on all the trees in the postinit. I like the idea of overriding GenerateLoot much better, however. That way the function is only called when needed. All of these solutions would still keep our current limitations of forcing some coal to be dropped regardless when you chop down a burnt tree (in addition to whatever loot you set), and that we cannot affect the stump loot. You could probably do something like bizziboi said with SeOnBurnt, but CBA to look into that now. You could do the GenerateLoot extension like this: -- We steal their idea of listing things by build, but this is our own list, -- which has nothing to do with theirs, since we cannot access it. -- I added burnt_loot as well for streamlinedness :) -- Change these loot tables to whatever you like. local builds = { normal = { file="claw_tree_build", prefab_name="clawpalmtree", normal_loot = {"cork", "cork"}, short_loot = {"cork"}, tall_loot = {"cork", "cork", "cork"}, burnt_loot = {"cork", "cork", "cork"}, }, } -- We also steal their way of accessing things by build. local function GetBuild(inst) local build = builds[inst.build] if build == nil then return builds["normal"] end return build end local getLoot = function(lootdropper_component, tree_inst) if tree_inst:HasTag("burnt") then -- What to drop if it is burnt? -- It already automatically drops charcoal, and you can't change that. -- It's in code separate from the rest of the drop table code. -- But it does call DropLoot(), so it will still drop the loot you set. -- If you just want it to drop the normal loot when burnt, delete this -- whole if-statement. return lootdropper_component:SetLoot(GetBuild(tree_inst).burnt_loot) end -- Now for the normal loot. This is where we use our custom loot tables. -- Just like the original code, we use the growable component to determine -- which loot to assign. We also use tree_inst.build, just like the original code. if tree_inst.components.growable then if tree_inst.components.growable.stage == 1 then return lootdropper_component:SetLoot(GetBuild(tree_inst).short_loot) elseif tree_inst.components.growable.stage == 2 then return lootdropper_component:SetLoot(GetBuild(tree_inst).normal_loot) else return lootdropper_component:SetLoot(GetBuild(tree_inst).tall_loot) end end return {} end -- Some drops are done directly in the code, and you cannot touch those. -- It is things like extra cork. Sadly, we can only change the base loot. AddPrefabPostInit("clawpalmtree", function(inst) if inst.components.lootdropper then inst.components.lootdropper.customlootfn = getLoot local oldGenerateLoot = inst.components.lootdropper.GenerateLoot function inst.components.lootdropper:GenerateLoot() if self.customlootfn then return self.customlootfn(self, self.inst) end return oldGenerateLoot() end end end If you want to be able to follow what's going on or improve upon it or in general start modding, you should take some time to learn the LUA syntax and structure. My newcomer post is a great place to start, and I highly recommend that you take the LUA Crash Course and look through the "getting started with modding guide" thread. I can't sink much more time into this, as I'm busy with my master thesis, and this is more like procrastination for me, haha Edited April 18, 2019 by Ultroman Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180082 Share on other sites More sharing options...
Developer bizziboi Posted April 18, 2019 Developer Share Posted April 18, 2019 It occurred to me you could add a similar callback to LootDropper:AddLoot and LootDropper:SpawnLootPrefab to get rid of the charcoal. Bit ugly but.....it could work. Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1180154 Share on other sites More sharing options...
MidrealmDM Posted April 30, 2019 Share Posted April 30, 2019 (edited) The following should work... =-=-=- TREE DROPS (This only adds extra loot when chopped.... not if burned ) function TreeLootPostInit(inst) local oldonfinish = inst.components.workable.onfinish inst.components.workable.onfinish = function(inst, chopper) if chopper then if inst.components.growable then if inst.components.growable.stage > 2 then inst.components.lootdropper:AddChanceLoot("log", 0.03) -- Adds 3% chance of extra log on growth stage greater than 2 elseif inst.components.growable.stage > 1 then inst.components.lootdropper:AddChanceLoot("log", 0.02) -- else adds 2% extra log chance on growth stage greater than 1 end else inst.components.lootdropper:AddChanceLoot("log", 0.01) -- else adds 1% chance of extra log end end oldonfinish(inst, chopper) end return inst end local modtrees = { -- list the prefab files of the trees you want to mod "evergreen_sparse", "marsh_tree" } for k,v in pairs(modtrees) do AddPrefabPostInit(v, TreeLootPostInit) end =-=-=-=-= MONSTER DROPS -- ADD DROP ITEM to CREATURES local function YourLogLoot(prefab) prefab.components.lootdropper:AddChanceLoot("log",0.5) -- 50% chance for one log prefab.components.lootdropper:AddChanceLoot("log",0.25) -- 25% chance for one log -- The chances above are independent, so its possible to get none, one, or two -- 37.5% none, 50% only one, 12.5% two -- You can set a line item to 1.0 for 100% chance end local function AddLogPostInit(prefab) YourLogLoot(prefab) end local modcreature = { -- list the prefab files of the creatures you want to mod "rocky", "merm" } for k,v in pairs(modcreature) do AddPrefabPostInit(v, AddLogPostInit) end Edited April 30, 2019 by MidrealmDM Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1187525 Share on other sites More sharing options...
MidrealmDM Posted April 30, 2019 Share Posted April 30, 2019 As far as removing loot and replacing it.. Something like this might work, I think - replacing one item with another. =-=-=-=-= local function NoCharcoalPostinit(inst) for i, v in ipairs(chanceloot) do if v.prefab == "charcoal" and math.random() < 0.15 then -- 15% chance to replace charcoal with log v.prefab = "log" break end end end AddPrefabPostInit("jungletree", NoCharcoalPostinit) -- or whatever tree prefab you want =-=-=- Sorry, its late, so this may not be accurate Link to comment https://forums.kleientertainment.com/forums/topic/105029-how-to-structure-function-or-loot-table-edits/#findComment-1187531 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