EuedeAdodooedoe Posted March 22, 2017 Share Posted March 22, 2017 Many prefabs in the game have their own files where most of their relevant code is written in. Some prefabs, however, such as an amulet, are all declared or whatever in one file, so in my case, the lazy forager shares a file with code with all other amulets. This means that it's all technically one prefab with different types of instances, or something along the lines, if I'm understanding this correctly. So, while for Flower and Evil Flower, this type of code structure in a file will work and change things accordingly, it crashes the game when I'm trying to work with the lazy forager: local function orangeChanged() local inst = commonfn("orangeamulet") if not TheWorld.ismastersim then return inst end -- inst.components.inspectable.nameoverride = "unimplemented" -- inst:AddComponent("useableitem") -- inst.components.useableitem:SetOnUseFn(unimplementeditem) inst.components.equippable:SetOnEquip(onequip_orange) inst.components.equippable:SetOnUnequip(onunequip_orange) inst:AddComponent("finiteuses") inst.components.finiteuses:SetOnFinished(inst.Remove) inst.components.finiteuses:SetMaxUses(TUNING.ORANGEAMULET_USES) inst.components.finiteuses:SetUses(TUNING.ORANGEAMULET_USES) inst:AddComponent("fueled") inst.components.fueled.fueltype = FUELTYPE.NIGHTMARE MakeHauntableLaunch(inst) return inst end local function orangeInitChanged(prefab) prefab.components.commonfn.orange = orangeChanged end AddPrefab("amulet", orangeInitChanged) And this is the error it gives me in the logs: [string "../mods/Changed values/scripts/fuelableChanged.l..."]:31: attempt to call global 'AddPrefab' (a nil value) So, could I have some ideas on what is going on and how exactly I could make it not crash? Please, explain how you've structured it too and why what is declared is needed, because coding in terms of modding seems to be even harder to comprehend than just reading code written for a game itself. Oh, and in terms of what I am trying to do, it's to make the lazy forager refuelable... if Klei isn't gonna do this, someone's gotta! Link to comment Share on other sites More sharing options...
PanAzej Posted March 23, 2017 Share Posted March 23, 2017 12 hours ago, EuedeAdodooedoe said: This means that it's all technically one prefab with different types of instances, or something along the lines, if I'm understanding this correctly. Nope. It's still a separate prefab. In amulet.lua file there's a separate function for every amulet and a "commonfn" function, which is used by every prefab. Prefab("amulet", red, assets), See, here's where the Prefab is created: "amulet" is the name of the prefab, "red" is the function we're going to use, and "assets" is, well, the assets table that this prefab's going to use. Here's the "red" function: local function red() local inst = commonfn("redamulet", "resurrector") if not TheWorld.ismastersim then return inst end -- red amulet now falls off on death, so you HAVE to haunt it -- This is more straightforward for prototype purposes, but has side effect of allowing amulet steals -- inst.components.inventoryitem.keepondeath = true inst.components.equippable:SetOnEquip(onequip_red) inst.components.equippable:SetOnUnequip(onunequip_red) inst:AddComponent("finiteuses") inst.components.finiteuses:SetOnFinished(inst.Remove) inst.components.finiteuses:SetMaxUses(TUNING.REDAMULET_USES) inst.components.finiteuses:SetUses(TUNING.REDAMULET_USES) inst:AddComponent("hauntable") inst.components.hauntable:SetHauntValue(TUNING.HAUNT_INSTANT_REZ) return inst end You can see that at first we call "commonfn" function, which contains base things that are used by every amulet. It's made a local variable and we add stuff to it. Why is it done like that? I guess it's so that it's a bit more efficient, and a bit more... fancy. 13 hours ago, EuedeAdodooedoe said: And this is the error it gives me in the logs: [string "../mods/Changed values/scripts/fuelableChanged.l..."]:31: attempt to call global 'AddPrefab' (a nil value) Because there's no "AddPrefab" function. I don't wanna be rude, but please look at other mods and how they do it before failing and asking to forums. Some things are so commonly used that it's really simple to find. If you want to change an existing prefab, then use AddPrefabPostInit function in your modmain: function PostInitFunction(inst) if GLOBAL.TheWorld.ismastersim then -- this function should only run on the server and not on client -- some code end end AddPrefabPostInit("prefabname", PostInitFunction) You can find more functions usable by mods in Steam/SteamApps/common/Don't Starve Together/data/scripts/modutil.lua. Link to comment Share on other sites More sharing options...
EuedeAdodooedoe Posted March 23, 2017 Author Share Posted March 23, 2017 (edited) "Because there's no "AddPrefab" function" ... What? There's no "AddPrefab" function where? I don't know what you're talking about. I am not sure how well looking through other mods will help me, but I'll try to keep that in mind next time. I still haven't understood anything here though, like why do I need "AddPrefabPostInit" instead of "AddPrefab" or whatever? The latter worked for changing functions in flower files, so idk what the big difference in logic here is. And just to be clear, are you implying I need to call out the "commonfn" function in my code before I can use anything used by it or the file it's in or whatever? I don't get why so often, obscure explenations are made by people when it comes to coding. It's not just here, but other forums that I've asked for some coding help as well. "Because there is no "AddPrefab" function" <= how am I supposed to interpret it? Where is "there"? Why does this matter? Because to my understanding, the only clear and constructive way to help someone in terms of coding is telling what they've done wrong, what needs to be done, how to do it (the code itself, an example) and WHY it needs to be done like that. Edited March 23, 2017 by EuedeAdodooedoe Link to comment Share on other sites More sharing options...
PanAzej Posted March 23, 2017 Share Posted March 23, 2017 (edited) 3 hours ago, EuedeAdodooedoe said: "Because there's no "AddPrefab" function" ... What? There's no "AddPrefab" function where? I don't know what you're talking about. (...) I don't get why so often, obscure explenations are made by people when it comes to coding. It's not just here, but other forums that I've asked for some coding help as well. "Because there is no "AddPrefab" function" <= how am I supposed to interpret it? Where is "there"? Why does this matter? Because to my understanding, the only clear and constructive way to help someone in terms of coding is telling what they've done wrong, what needs to be done, how to do it (the code itself, an example) and WHY it needs to be done like that. Uhh, okay. Well, the thing is, how am I supposed to know how advanced you're at coding/modding? Maybe you had some experience with things similar to it, maybe you've just opened one of Klei's *.luas for the first time. "There's no AddPrefab function" Yes, and I've pointed you where you should look for more functions like AddPrefabPostInit: 9 hours ago, PanAzej said: You can find more functions usable by mods in Steam/SteamApps/common/Don't Starve Together/data/scripts/modutil.lua. In that file there's all useful functions you can call from your modmain.lua file in your mod directory. I gave you the code - the only thing you need is to paste it into your modmain and customize it - put things you want to be changed in there. There's no "AddPrefab" function there, that's why the game crashes - because there's no function like that, the game doesn't know what to do and shows you the error screen. 3 hours ago, EuedeAdodooedoe said: (...)why do I need "AddPrefabPostInit" instead of "AddPrefab" or whatever? The latter worked for changing functions in flower files, so idk what the big difference in logic here is. Huh, okay, apparently I was wrong - there IS an AddPrefab function in dlcsupport.lua... But it's a local function. 3 hours ago, EuedeAdodooedoe said: And just to be clear, are you implying I need to call out the "commonfn" function in my code before I can use anything used by it or the file it's in or whatever? Nope, I just explained to you how the game "thinks" and builds the prefab. Amulet's prefabs are made out of a few functions, placed in a single file. You can see at the bottom what are actual prefabs, returned by the file: return Prefab("amulet", red, assets), Prefab("blueamulet", blue, assets), Prefab("purpleamulet", purple, assets), Prefab("orangeamulet", orange, assets, {"sand_puff"}), Prefab("greenamulet", green, assets), Prefab("yellowamulet", yellow, assets, { "yellowamuletlight" }), Prefab("yellowamuletlight", yellowlightfn) You can put whatever changes in the function I gave you, no need to worry about what's in that file. Also, you seem to think that you can edit local stuff, like local variables or local functions. You can't do that. They're "local", so they can be used only in that file. You can access some of them via component variables, well, if they're stored in there, that is. If you want to make the Lazy Forager possible to be fueled, then I recommend looking into other amulets (yellow one can be refueled, for example). I bet you'd want to use Orange Gems to refuel it, right? That'd be the hard way of doing it. You can see existing fuel types in Don't Starve Together/data/scripts/constants.lua: FUELTYPE = { BURNABLE = "BURNABLE", USAGE = "USAGE", MAGIC = "MAGIC", CAVE = "CAVE", NIGHTMARE = "NIGHTMARE", ONEMANBAND = "ONEMANBAND", PIGTORCH = "PIGTORCH", CHEMICAL = "CHEMICAL", WORMLIGHT = "WORMLIGHT", } You've chosen probably the hardest one to change, though. You need to remove the finiteuses component and change how the amulet takes fuel while it's being equipped. I'm sorry, but if you need finished code, maybe somebody else will come and help you. I also bet that somebody did the change you want to do already. Didn't Rezecib's Rebalance change that? Maybe some other mod? Edited March 23, 2017 by PanAzej Link to comment Share on other sites More sharing options...
EuedeAdodooedoe Posted April 2, 2017 Author Share Posted April 2, 2017 (edited) @PanAzej hmm, looking at Rezecib's rebalance mod's code, it seems like he got the refuelable thing going through the use of... applying the code every frame to every lazy forager existent in the game, AFTER the initialisation. So, that's what PostInit means? Post initialisation? If so, that explains why the code cannot be applied like I've done it, due to the whole local variable thing, unless I make an edited carbon copy of the amulet.lua file. Hmm... perhaps I'll try both methods. And the fuel type I want to add is nightmare fuel, not orange gems... dunno why you would want to refuel it via orange gems, that would simply be a waste. On 23/03/2017 at 2:27 PM, PanAzej said: You've chosen probably the hardest one to change, though. You need to remove the finiteuses component and change how the amulet takes fuel while it's being equipped. I really don't understand why this would be so much trouble, I mean, it's just changing an existing value to a higher one for an item's durability, it's simple math! Is "finiteuses" tag something that prevents an item from it being possible to add a way to refuel it? If so, why, it seems like a very dumb way of making things harder if you were a dev at Klei and thought "hmm, actually, this item could do with a way to refuel it". I mean, look at the amount of crap Rezecib needed to go through JUST to make it possible to add 25 durab when using up nightmare fuel for the lazy deserter: Spoiler local orangeamulet_rate = 1/25 local UpvalueHacker = require("tools/upvaluehacker") AddPrefabPostInit("world", function(TheWorld) UpvalueHacker.SetUpvalue(GLOBAL.Prefabs.panflute.fn, HearPanFlute, "HearPanFlute") local ACTIONS = GLOBAL.ACTIONS local COMPONENT_ACTIONS = UpvalueHacker.GetUpvalue(TheWorld.IsActionValid, "COMPONENT_ACTIONS") COMPONENT_ACTIONS.POINT.blinkstaff = function(inst, doer, pos, actions, right) if right and TheWorld.Map:IsAboveGroundAtPoint(pos:Get()) and not inst:HasTag("fueldepleted") then table.insert(actions, ACTIONS.BLINK) end end if not GLOBAL.TheNet:GetIsServer() then return end local TheSim = GLOBAL.TheSim local SpawnPrefab = GLOBAL.SpawnPrefab local function pickup(inst, owner) if inst.components.fueled:IsEmpty() then return end if owner == nil or owner.components.inventory == nil then return end local x, y, z = owner.Transform:GetWorldPosition() local ents = TheSim:FindEntities(x, y, z, TUNING.ORANGEAMULET_RANGE, { "_inventoryitem" }, { "INLIMBO", "NOCLICK", "catchable", "fire" }) for i, v in ipairs(ents) do if v.components.inventoryitem ~= nil and v.components.inventoryitem.canbepickedup and v.components.inventoryitem.cangoincontainer and not v.components.inventoryitem:IsHeld() and owner.components.inventory:CanAcceptCount(v, 1) > 0 then local fx = SpawnPrefab("small_puff") fx.Transform:SetPosition(v.Transform:GetWorldPosition()) fx.Transform:SetScale(.5, .5, .5) inst.components.fueled:DoDelta(-TUNING.LARGE_FUEL*orangeamulet_rate) if v.components.stackable ~= nil then v = v.components.stackable:Get() end if v.components.trap ~= nil and v.components.trap:IsSprung() then v.components.trap:Harvest(owner) else owner.components.inventory:GiveItem(v) end return end end end UpvalueHacker.SetUpvalue(GLOBAL.Prefabs.orangeamulet.fn, pickup, "onequip_orange", "pickup") end) local FUELTYPE = GLOBAL.FUELTYPE FUELTYPE.BAT = "BAT" FUELTYPE.ORANGEGEM = "ORANGEGEM" if not GLOBAL.TheNet:GetIsServer() then return end local function convert_finiteuses_to_fueled(inst, fueltype, rate, inflation) inflation = inflation or 1 inst:AddComponent("fueled") inst.components.fueled.fueltype = fueltype inst.components.fueled:InitializeFuelLevel(inst.components.finiteuses.total*inflation*TUNING.LARGE_FUEL*rate) inst.components.fueled.accepting = true local impossible_uses = inst.components.finiteuses.total + 1 inst.components.finiteuses:SetUses(impossible_uses) inst:DoTaskInTime(0, function(inst) local uses = inst.components.finiteuses:GetUses() if uses ~= impossible_uses then inst.components.fueled:InitializeFuelLevel(uses*inflation*TUNING.LARGE_FUEL*rate) end inst:RemoveComponent("finiteuses") inst.components.fueled:DoDelta(0) end) end Rezecib himself commented: "I can't believe I have to resort to this for this kind of change, but... 'tis the mod life, I guess". It almost feels like modding is a huge waste of time; you do more work than the developers do themselves for the same amount of changes, your work is highly undermined (unless perhaps it's visual client type mods), because they are mods and for games development, this kind of crap might not even be useful, since in the industry you'll be changing code directly. No wonder so many modders have simply quit! Klei needs to sort some crap out for modding, I don't want to do useless thought magic just to get one simple thing working. And what's more, this code runs through frames, imagine how big of a hell it would be with players having a bunch of those amulets lying in one place with the mod enabled! It'll be like beefalo due to the whole domestication mechanics... which mostly are there for no reason because so many people don't use that **** due to it being too much to give than what you actually gain. Edited April 2, 2017 by EuedeAdodooedoe Link to comment Share on other sites More sharing options...
EuedeAdodooedoe Posted April 5, 2017 Author Share Posted April 5, 2017 (edited) @PanAzej I now get why it's so difficult to do this... Even if I do the bad method (making copies of existing lua files and editing them for the mod), fueled.lua and finiteuses.lua are two ways that fuel is consumed in the game. The former happens over time, depending on conditions (e.g. it is equipped) and the latter loses uses and no item in the game that has durability in uses is fuelable... Except bone armour! I checked its code and it revealed to me the way to do this extremely easy, provided you make a carbon copy of amulet.lua file in your mod and edit it. What I did was: Change this code under "pickup" function that takes away 1 point of durability per item pickup from: inst.components.finiteuses:Use(1) To: inst.components.fueled:DoDelta(-1) Then changed this code in "orange", which initiates some things for the orange amulet, from: inst:AddComponent("finiteuses") inst.components.finiteuses:SetOnFinished(inst.Remove) inst.components.finiteuses:SetMaxUses(TUNING.ORANGEAMULET_USES) inst.components.finiteuses:SetUses(TUNING.ORANGEAMULET_USES) To: inst:AddComponent("fueled") inst.components.fueled.fueltype = FUELTYPE.NIGHTMARE inst.components.fueled:InitializeFuelLevel(TUNING.ORANGEAMULET_USES) inst.components.fueled.accepting = true What I can't figure out though is where the amount of fuel it gives back is declared exactly. Having 675 uses (in my mod) gave it back about 23%, which equates to about 150 uses. Similar or the same amount was for when the uses were reset back to 225, so a higher percentage was repaired when changing the amount of uses it had. Are you able to understand? I mean, this is all the code I changed in amulet.lua. Let me know if you need the fully changed file, although this is pretty much it, everything else was left as is in the original game's file. Kudos for your help so far, btw Edited April 6, 2017 by EuedeAdodooedoe Added in "inst:AddComponent("fueled")" for the edited script, since I forgot to place that in here... 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