Jupiters Posted August 10, 2015 Share Posted August 10, 2015 I made a new container and want to add a widget for it, but it didn't work. The scripts of the function fn() are the following: require "prefabutil" local assets ={Asset("ANIM", "anim/shop.zip"),Asset("IMAGE", "images/inventoryimages/shop.tex"),Asset("ATLAS", "images/inventoryimages/shop.xml"),} local prefabs = {"shop",} local function onopen(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/chest_open")end local function onclose(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/chest_close") end local function onhammered(inst, worker) if not inst:HasTag("fire") and inst.components.burnable then inst.components.burnable:Extinguish() end inst.components.lootdropper:DropLoot() if inst.components.container then inst.components.container:DropEverything() end SpawnPrefab("collapse_small").Transform:SetPosition(inst.Transform:GetWorldPosition()) inst.SoundEmitter:PlaySound("dontstarve/common/destroy_wood") inst:Remove()end local function onhit(inst, worker) if not inst:HasTag("burnt") then inst.AnimState:PlayAnimation("hit") inst.AnimState:PushAnimation("closed", false) if inst.components.container then inst.components.container:DropEverything() inst.components.container:Close() end endend local function onbuilt(inst) inst.AnimState:PlayAnimation("place") inst.AnimState:PushAnimation("idle")end local function onsave(inst, data)end local function onload(inst, data)end local function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddSoundEmitter() MakeObstaclePhysics(inst, 1) inst.AnimState:SetBank("shop") inst.AnimState:SetBuild("shop") inst.AnimState:PlayAnimation("idle", true) local minimap = inst.entity:AddMiniMapEntity() minimap:SetIcon( "shop.png" ) inst:AddTag("structure") inst:AddComponent("lootdropper") inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.HAMMER) inst.components.workable:SetWorkLeft(4) inst.components.workable:SetOnFinishCallback(onhammered) inst.components.workable:SetOnWorkCallback(onhit) inst:AddComponent("inspectable") inst:AddComponent("container") inst.components.container:WidgetSetup("treasurechest") inst.components.container.onopenfn = onopen inst.components.container.onclosefn = onclose local widgetbuttoninfo = { text = "DO", position = Vector3(0, -195, 0), fn = function(inst) --body end } inst.components.container.widgetbuttoninfo = widgetbuttoninfo inst:ListenForEvent("onbuilt", onbuilt) MakeSnowCovered(inst) inst.OnSave = onsave inst.OnLoad = onload return instend return Prefab("common/objects/shop", fn, assets, prefabs),MakePlacer("common/shop_placer", "shop", "shop", "idle")shop.lua Link to comment Share on other sites More sharing options...
DarkXero Posted August 11, 2015 Share Posted August 11, 2015 @Jupiters, that's for DS.This is DST. First, setup the function of the button, as an action, in modmain.lua:local function TradeFn(act) if act.doer and act.doer.components.inventory then local test = GLOBAL.SpawnPrefab("goldnugget") act.doer.components.inventory:GiveItem(test) return true endendAddAction("TRADE", "Trade", TradeFn)This is an example. This is the new shop.lua:require "prefabutil"local assets = { Asset("ANIM", "anim/shop.zip"), Asset("IMAGE", "images/inventoryimages/shop.tex"), Asset("ATLAS", "images/inventoryimages/shop.xml"),}local function onopen(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/chest_open")end local function onclose(inst) inst.SoundEmitter:PlaySound("dontstarve/wilson/chest_close") end local function onhammered(inst, worker) if not inst:HasTag("fire") and inst.components.burnable then inst.components.burnable:Extinguish() end inst.components.lootdropper:DropLoot() if inst.components.container then inst.components.container:DropEverything() end SpawnPrefab("collapse_small").Transform:SetPosition(inst.Transform:GetWorldPosition()) inst.SoundEmitter:PlaySound("dontstarve/common/destroy_wood") inst:Remove()endlocal function onhit(inst, worker) if not inst:HasTag("burnt") then inst.AnimState:PlayAnimation("hit") inst.AnimState:PushAnimation("closed", false) if inst.components.container then inst.components.container:DropEverything() inst.components.container:Close() end endendlocal function onbuilt(inst) inst.AnimState:PlayAnimation("place") inst.AnimState:PushAnimation("idle")endlocal function onsave(inst, data)endlocal function onload(inst, data)endlocal function EditContainer(inst) local self if TheWorld.ismastersim then self = inst.components.container else self = inst.replica.container end self:WidgetSetup("treasurechest") local function buttonfn(inst) if TheWorld.ismastersim then BufferedAction(inst.components.container.opener, inst, ACTIONS.TRADE):Do() else SendRPCToServer(RPC.DoWidgetButtonAction, ACTIONS.TRADE.code, inst, ACTIONS.TRADE.mod_name) end end self.widget.buttoninfo = { text = "Trade", position = Vector3(0, -195, 0), fn = buttonfn, }endlocal function fn() local inst = CreateEntity() inst.entity:AddTransform() inst.entity:AddAnimState() inst.entity:AddSoundEmitter() inst.entity:AddMiniMapEntity() inst.entity:AddNetwork() MakeObstaclePhysics(inst, 1) inst.AnimState:SetBank("shop") inst.AnimState:SetBuild("shop") inst.AnimState:PlayAnimation("idle", true) inst.MiniMapEntity:SetIcon("shop.png") inst:AddTag("structure") inst.entity:SetPristine() if not TheWorld.ismastersim then local _OnEntityReplicated = inst.OnEntityReplicated inst.OnEntityReplicated = function(inst) if _OnEntityReplicated then _OnEntityReplicated(inst) end EditContainer(inst) end return inst end inst:AddComponent("container") inst.components.container.onopenfn = onopen inst.components.container.onclosefn = onclose EditContainer(inst) inst:AddComponent("inspectable") inst:AddComponent("lootdropper") inst:AddComponent("workable") inst.components.workable:SetWorkAction(ACTIONS.HAMMER) inst.components.workable:SetWorkLeft(4) inst.components.workable:SetOnFinishCallback(onhammered) inst.components.workable:SetOnWorkCallback(onhit) inst:ListenForEvent("onbuilt", onbuilt) MakeSnowCovered(inst) inst.OnSave = onsave inst.OnLoad = onload return instendreturn Prefab("common/objects/shop", fn, assets), MakePlacer("common/shop_placer", "shop", "shop", "idle")Notice:1) inst.entity:AddNetwork(), essential for the prefab to exist for hosts and clients.2) if not TheWorld.ismastersim then, separating host code (master simulation) from client code. 3) EditContainer(inst)This function is seen twice.One, to setup the widget for the host, after the container component is added.Two, to setup the widget for the client, after the container replica is added client side. A replica is a component stub that the client interacts with. This difference makes the function have two different functions for the button, one that sends an RPC for the server to do an action, and one that does the action directly. Both cause the same thing in the server, the execution of the trade action we added in modmain. Link to comment Share on other sites More sharing options...
Jupiters Posted August 11, 2015 Author Share Posted August 11, 2015 @DarkXero : It works. How amazing! I can't thank you enough.May I ask you one more question?I want the "shop" mod to be a bank, too. That means I want it can store gold nuggets. Number of the gold nuggets is one value( x_gold ).How do I make the value x_gold still the same when I start the game next time? Link to comment Share on other sites More sharing options...
Jupiters Posted August 11, 2015 Author Share Posted August 11, 2015 @DarkXero : Oh, by the way, how do add other buttons? Use "self.widget.buttoninfo", "self.widget.buttoninfo2" and so on? Link to comment Share on other sites More sharing options...
DarkXero Posted August 11, 2015 Share Posted August 11, 2015 How do I make the value x_gold still the same when I start the game next time? That's the use oflocal function onsave(inst, data) data.x_gold = inst.x_goldend local function onload(inst, data) if data then inst.x_gold = data.x_gold or 0 endendAnd you initialize inst.x_gold = 0 in the prefab fn. Oh, by the way, how do add other buttons? Use "self.widget.buttoninfo", "self.widget.buttoninfo2" and so on? Unfortunately, no.The widget is hard coded to use only one button.This means that we have to override the widget and copy paste a lot of code that handles that one button, for all other buttons. I propose a simpler alternative, easier to understand, instead of messing with widgets. When your shop prefab spawns, it spawns two mini shop prefabs that depend on it.(Those mini shops can be scaled down versions of the shop.)The main shop won't be a container, it will just be examined.These mini shops can be interacted with, but can't be destroyed, they will only be destroyed if the main shop is destroyed. One mini shop will act like the trader, with the trader button.The other mini shop, like the bank, with the store button. Link to comment Share on other sites More sharing options...
Jupiters Posted August 12, 2015 Author Share Posted August 12, 2015 @DarkXero : What a pity....... But still, thank you anyway. That's so kind of you. Link to comment Share on other sites More sharing options...
Jupiters Posted August 12, 2015 Author Share Posted August 12, 2015 @DarkXero : If it doesn't bother you, I would like to ask you anoher question. How to trigger an event when the day comes, the night comes, or in a period of time that is set. Link to comment Share on other sites More sharing options...
Jupiters Posted August 12, 2015 Author Share Posted August 12, 2015 @DarkXero : OMG. I've asked you so many question. What about another one?Here is the code in modmain.lua for the button: local function TradeFn(act) if act.doer and act.doer.components.inventory then local give_bluegem = GLOBAL.SpawnPrefab("bluegem") local inst = GLOBAL.SpawnPrefab("statuemaxwell") local num_found = 0 for k,v in pairs(inst.components.container.slots) do if v and v.prefab == "bluegem" then num_found = num_found + v.components.stackable:StackSize() end end if num_found == 3 then if act.doer.components.inventory:ConsumeByName("goldnugget", 5) then act.doer.components.inventory:ConsumeByName("goldnugget", 5) act.doer.components.inventory:GiveItem(give_bluegem) end end return true endendAddAction("TRADE", "Trade", TradeFn) I want it possible that when I have 5 goldnuggets and there are 3 red gems in the container and if I click the button, it will give me a redgem and take away 5 goldnugget. Unfortunately, it did not work. But if I replace " if num_found == 3 then " with " if num_found == 0 then ", it did give a redgem. That means the value num_found is still the same. What's wrong with my code? Link to comment Share on other sites More sharing options...
DarkXero Posted August 12, 2015 Share Posted August 12, 2015 How to trigger an event when the day comes, the night comes, or in a period of time that is set local function TriggerEvent(inst, phase) if phase == "day" then -- Event a elseif phase == "dusk" then -- Event b elseif phase == "night" then -- Event c endend inst:WatchWorldState("phase", TriggerEvent)TriggerEvent(inst, TheWorld.state.phase) I want it possible that when I have 5 goldnuggets and there are 3 red gems in the container and if I click the button, it will give me a redgem and take away 5 goldnugget. Unfortunately, it did not work. But if I replace " if num_found == 3 then " with " if num_found == 0 then ", it did give a redgem. That means the value num_found is still the same. What's wrong with my code? Try saying that again. There is not a single mention of a red gem in your code.There is also no reference to the shop.I understand none of this. Maybe you meant this?local function TradeFn(act) if act.doer and act.target then local inv_doer = act.doer.components.inventory local con_target = act.target.components.container local is_near = act.doer:IsNear(act.target, 20) if inv_doer and con_target and is_near then local fivegold = con_target:Has("goldnugget", 5) if fivegold then con_target:ConsumeByName("goldnugget", 5) local redgem = GLOBAL.SpawnPrefab("redgem") inv_doer:GiveItem(redgem) end return true end endendAddAction("TRADE", "Trade", TradeFn) Link to comment Share on other sites More sharing options...
Jupiters Posted August 13, 2015 Author Share Posted August 13, 2015 (edited) @DarkXero : I get it.Thanks. You nearly solved all my problems. May I ask you again if I have new problems? Edited August 13, 2015 by Jupiters Link to comment Share on other sites More sharing options...
Jupiters Posted August 13, 2015 Author Share Posted August 13, 2015 (edited) @DarkXero : Here comes a problem. I add a widget and it can change values when I press. (It is like the widget in the mod : "Speed Me Up DST".)When I click the button of the container(I have made it with your help), it will give me different things according to the value.Everything seems normal.But the problem is the client can't change the value. Only the host can change the value.I want the value seperate for every single player.What can I do?I have uploaded the modmain.lua so that you can check it. modmain.lua Edited August 13, 2015 by Jupiters Link to comment Share on other sites More sharing options...
Jupiters Posted August 14, 2015 Author Share Posted August 14, 2015 @DarkXero : Would you tell me how to do it please? Link to comment Share on other sites More sharing options...
DarkXero Posted August 14, 2015 Share Posted August 14, 2015 @Jupiters, try this: modmain.lua Link to comment Share on other sites More sharing options...
Jupiters Posted August 16, 2015 Author Share Posted August 16, 2015 @DarkXero : Thx, it works now Link to comment Share on other sites More sharing options...
Jupiters Posted August 27, 2015 Author Share Posted August 27, 2015 (edited) Hello, @DarkXeroI have been working for this mod for a long time. But, I cannot find a way to add multiple buttons for the container. Is there any way to push a screen with a few other buttons, which shows when I click the button "Trade". And the buttons shown have different action after they are click. Will you show me how to do this. I will attach the mod file. Thanks.Magical Chest.zip Edited August 27, 2015 by Jupiters Link to comment Share on other sites More sharing options...
DarkXero Posted August 28, 2015 Share Posted August 28, 2015 @Jupiters, here, I enabled many container buttons:Magical Chest.zip Link to comment Share on other sites More sharing options...
Jupiters Posted August 28, 2015 Author Share Posted August 28, 2015 @DarkXero, now I can add many buttons. I can't thank you enough. Link to comment Share on other sites More sharing options...
Jupiters Posted August 28, 2015 Author Share Posted August 28, 2015 Hello, @DarkXeroThe mod is nearly done but with a problem.When I put many things that are not tradable in the chest and then click sell, it crashed. Here is the log: [00:01:50]: [string "../mods/Magical Chest/modmain.lua"]:127: attempt to index field 'tradable' (a nil value)LUA ERROR stack traceback: ../mods/kk/modmain.lua:127 in (field) fn (Lua) <120-142> scripts/bufferedaction.lua:23 in (method) Do (Lua) <19-33> scripts/networkclientrpc.lua:155 in () ? (Lua) <143-159> =[C]:-1 in (method) CallRPC © <-1--1> scripts/networkclientrpc.lua:480 in (global) HandleRPCQueue (Lua) <471-488> scripts/update.lua:47 in () ? (Lua) <39-123> The part of the code of modmain.lua is: local function SellFn( act )if act.doer and act.doer.components.inventory and act.target thenlocal inv_doer = act.doer.components.inventorylocal con_target = act.target.components.containerlocal is_near = act.doer:IsNear(act.target, 20)local num_found = 0 for k,v in pairs(act.target.components.container.slots) do if v and v.components.tradable.goldvalue > 0 then num_found = num_found + v.components.stackable:StackSize() * v.components.tradable.goldvalue end endif is_near and num_found >0 thenfor k = 1, num_found do inv_doer:GiveItem(GLOBAL.SpawnPrefab("goldnugget")) end--con_target:DestroyContents()for k,v in pairs(act.target.components.container.slots) doif v and v.components.tradable.goldvalue > 0 thencon_target:ConsumeByName(v.prefab, v.components.stackable:StackSize())endendreturn trueendendendAddAction("SELL", "Sell", SellFn) The line in red is line 127. I cannot figure out what was going wrong.I want it to behave like pigking. But what I need is put things that can trade for gold with pigking in the chest and click Sell. Link to comment Share on other sites More sharing options...
Jupiters Posted August 28, 2015 Author Share Posted August 28, 2015 I change the code above into this: local function SellFn( act )if act.doer and act.doer.components.inventory and act.target thenlocal inv_doer = act.doer.components.inventorylocal con_target = act.target.components.containerlocal is_near = act.doer:IsNear(act.target, 20)local num_found = 0 for k,v in pairs(act.target.components.container.slots) do if v and v.components.tradable then if v.components.tradable.goldvalue >0 then num_found = num_found + v.components.stackable:StackSize() * v.components.tradable.goldvalue end end endif is_near and num_found >0 thenfor k = 1, num_found do inv_doer:GiveItem(GLOBAL.SpawnPrefab("goldnugget")) end--con_target:DestroyContents()for k,v in pairs(act.target.components.container.slots) doif v and v.components.tradable thenif v.components.tradable.goldvalue > 0 thencon_target:ConsumeByName(v.prefab, v.components.stackable:StackSize())endendendreturn trueendendendAddAction("SELL", "Sell", SellFn) And it seems that it works now. Did I do this right? Link to comment Share on other sites More sharing options...
DarkXero Posted August 29, 2015 Share Posted August 29, 2015 @Jupiters, yes, all right.You check for the tradable component before trying to access a member value, goldvalue. Link to comment Share on other sites More sharing options...
Jupiters Posted August 29, 2015 Author Share Posted August 29, 2015 @DarkXero I could not mine rocks using this mod. My character hits the rock with the pick, makes a ***** sound, and the character says "I can't do that" every swing. Rock never goes down. I only installed this mod. I don't know what's going wrong. Need your help plz.Magical Chest.zip Link to comment Share on other sites More sharing options...
Jupiters Posted August 29, 2015 Author Share Posted August 29, 2015 (edited) Sorry for disturbing you, I think I've figured out where the problen lies. In modmain.lua, there is the code: local function MineFn( act )if act.doer and act.doer.components.inventory and act.target thenlocal inv_doer = act.doer.components.inventorylocal is_near = act.doer:IsNear(act.target, 20)if inv_doer:Has("goldnugget",1) and is_near thenif GLOBAL.TheWorld.state.isday theninv_doer:ConsumeByName("goldnugget", 1)for i = 1, 5 do inv_doer:GiveItem(GLOBAL.SpawnPrefab("marble")) endelseinv_doer:ConsumeByName("goldnugget", 1)for i = 1, 5 do inv_doer:GiveItem(GLOBAL.SpawnPrefab("nitre")) endendreturn trueendendendAddAction("MINE", "Mine", MineFn) I think it overrides the function of mine action, so I cannot mine. Now I change "mine" into "mines" and it seems okay now. Am I right? Edited August 29, 2015 by Jupiters Link to comment Share on other sites More sharing options...
DarkXero Posted August 29, 2015 Share Posted August 29, 2015 I think it overrides the function of mine action, so I cannot mine. Now I change "mine" into "mines" and it seems okay now. Am I right? Correct. AddAction(id, str, fn) takes three arguments. id must be unique, it identifies the action.str can be "Mine" or "MINE" or whatever, doesn't matter that it's the same. But the id, again, must be unique.Name it "MAGICAL_MINE" or "MC_MINE" so there is no conflict. Link to comment Share on other sites More sharing options...
Jupiters Posted August 30, 2015 Author Share Posted August 30, 2015 Correct. AddAction(id, str, fn) takes three arguments. id must be unique, it identifies the action.str can be "Mine" or "MINE" or whatever, doesn't matter that it's the same. But the id, again, must be unique.Name it "MAGICAL_MINE" or "MC_MINE" so there is no conflict. Thanks, I get it. Link to comment Share on other sites More sharing options...
Jupiters Posted August 31, 2015 Author Share Posted August 31, 2015 Hello @DarkXero Your another post gave an inspiration. ( http://forums.kleientertainment.com/topic/57411-help-clickable-buttons/ )Since the content of this mod is too complicated(trade for many things) and client don't know how the mod functions, I want add button for the container that will display the information after clicking and hide it after another clicking. I know how to add a button for a container now but I don't how to display the information. I think this is one way to show clients how the mod functions. How about another way, when the mouse move upon the button ( Let's assume the button's funtion is buy 10 flint for 1 gold nugget. ), a line of words ( the content is " 10 flint for 1 gold nugget ") will show at the top of the mouse. Does this way work? I am not sure that these two way which is better because I don't know how to do them. Could you please help me out? Thank you! 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