Jump to content

How to make something similar to drying rack?


Recommended Posts

Right now, I've made a structure that is essentially just a drying rack that looks different and is crafted with different materials. I want to make this structure have different dryable items and different products, and also give it collision (i.e. I don't want to be able to walk through it); I also want to edit the ingame name of the drying function (i.e. when i mouse over the structure with an applicable item, it should say "Extract" instead of "Dry"). Changing the prefabs in the drying rack.lua didn't really do anything. How do I go about doing this stuff?

Link to comment
Share on other sites

@AfrostLord, first of all, make sure you have a mod folder set up and place your prefab files in the scripts/prefabs folder there.

 

If you need to understand Lua better, try these.

 


 

To make something a solid structure, use the following in the main function (usually called "fn"):

MakeObstaclePhysics(inst, RADIUS)

 

where radius would be something between .1 (less than Wilson's hip size) and .8 (dromedary size :razz:)

 


 

I'm not sure drying itself is the easiest way to do this. You see, in order to dry something, you need to place something dryable on a dryer.

 

Instead, you should make your own component for extractable items and add it to them using AddPrefabPostInit. Copying most of dryable could work.

 


 

In order to have a unique way of using those items, you need a custom action in adition to the custom component. Example of a custom action (in modmain.lua):

local ACTIONS = GLOBAL.ACTIONS --you only need these two lines once in the modmain.lua, ideally at the top

local STRINGS = GLOBAL.STRINGS --they're so you need not place "GLOBAL." in front of those words every time

 

ACTIONS.USESTIM = GLOBAL.Action() --view the parameters possible in action.lua
ACTIONS.USESTIM.str = "Inject" --what word is displayed?
ACTIONS.USESTIM.id = "USESTIM" --same name as after "ACTIONS."
ACTIONS.USESTIM.fn = function(act)

--you can see the data possibly available in "act" in bufferedaction.lua

--use this to trigger things in the item component, the extraction device or the player
end

STRINGS.ACTIONS.USESTIM = "Inject"
--you need to declare the displayed word twice I think

 

Actions are a bit of an hit-and-miss because other properties of that prefab might interfere. If it has no components other than inventory (and probably a custom dryer to allow harvesting instead of simply dropping the product), then it should be fine.

 


 

Also, the keyword "extract" reminds me of this (I think it's abandoned). It's probably not exactly what you had in mind, but make sure not to use the same component or action names (for the sake of mod compatibility).

 


 

Ask when an issue arrive (you can @Mention me or other modders by marking any of that person's posts and copying the resulting snippet into your message).

Link to comment
Share on other sites

@Mobbstar,

 

local function Override(inst)
    print("postinit loaded")
    local function monster()
    local inst = common()

    inst:AddComponent("juice")
    inst.components.juice:SetProduct("brainjuice")
    inst.components.juice:SetDryTime(TUNING.DRY_FAST)


    return inst
end
end

 

AddPrefabPostInit("rabbit",Override)

 

So to add the component what I have to put this in modmain.lua, correct? It hasn't crashed the game so I assume it is.

 

I'm really confused about the action thing. Am I supposed to just copy it to modmain? Am I supposed to replace USESTIM with the prefab name, or is it irrelevant? Do I leave GLOBAL.action() as it is? (actions.lua says that DRY = Action(), among others). Right now, this is what I put in. Did I even use the right bufferedactions thing?

 

ACTIONS.USESTIM = GLOBAL.Action()
ACTIONS.USESTIM.str = "Extract"
ACTIONS.USESTIM.id = "USESTIM"
ACTIONS.USESTIM.fn = function(act)
function BufferedAction:Do()
    if self:IsValid() then
        
        local success, reason = self.action.fn(self)
        if success then
            if self.invobject and self.invobject:IsValid() then
                self.invobject:OnUsedAsItem(self.action)
            end
            self:Succeed()
            
        else
            self:Fail()
        end
        
        return success, reason
    end
end
end
 
What exactly do I put in the structure's prefab to make it perform the action?
Link to comment
Share on other sites

@Mobbstar,

 

local function Override(inst)

    print("postinit loaded")

    local function monster()

    local inst = common()

    inst:AddComponent("juice")

    inst.components.juice:SetProduct("brainjuice")

    inst.components.juice:SetDryTime(TUNING.DRY_FAST)

    return inst

end

end

 

AddPrefabPostInit("rabbit",Override)

 

So to add the component what I have to put this in modmain.lua, correct? It hasn't crashed the game so I assume it is.

 

I'm really confused about the action thing. Am I supposed to just copy it to modmain? Am I supposed to replace USESTIM with the prefab name, or is it irrelevant? Do I leave GLOBAL.action() as it is? (actions.lua says that DRY = Action(), among others). Right now, this is what I put in. Did I even use the right bufferedactions thing?

 

ACTIONS.USESTIM = GLOBAL.Action()
ACTIONS.USESTIM.str = "Extract"
ACTIONS.USESTIM.id = "USESTIM"
ACTIONS.USESTIM.fn = function(act)
function BufferedAction:Do()
    if self:IsValid() then
        
        local success, reason = self.action.fn(self)
        if success then
            if self.invobject and self.invobject:IsValid() then
                self.invobject:OnUsedAsItem(self.action)
            end
            self:Succeed()
            
        else
            self:Fail()
        end
        
        return success, reason
    end
end
end
 
What exactly do I put in the structure's prefab to make it perform the action?

 

I suppose I was talking too briefly :p

 

In the function "Override" for AddPrefabPostInit, you only need the three lines regarding the juice component, everything else has no effect. (In fact, the component wasn't added so far because you constructed an unused function "monster" around that part.)

 

The "usestim" stuff is what I used for an unfinished item in IR, you should use a different word (e.g. "extractjuice" since that would be very unique and thus be unlikely to cause incompatibility).

 

You can leave Action() as is, though you may need to change the action priority or alike later (meaning that you would have to put data in the parentheses).

 

The function makes no sense, sadly. You can see examples of action functions in action.lua, but keep in mind that components and stategraphs usually handle most things.

 

Also, whether an action can even be performed is chosen in components, using the "CollectThingActions" functions (CollectSceneActions, CollectInventoryActions, etc.). Make sure the "juice" component has such a function, which, as said, can mostly be copied from "dryable".

 

Good luck!

Link to comment
Share on other sites

I suppose I was talking too briefly :razz:

 

In the function "Override" for AddPrefabPostInit, you only need the three lines regarding the juice component, everything else has no effect. (In fact, the component wasn't added so far because you constructed an unused function "monster" around that part.)

 

The "usestim" stuff is what I used for an unfinished item in IR, you should use a different word (e.g. "extractjuice" since that would be very unique and thus be unlikely to cause incompatibility).

 

You can leave Action() as is, though you may need to change the action priority or alike later (meaning that you would have to put data in the parentheses).

 

The function makes no sense, sadly. You can see examples of action functions in action.lua, but keep in mind that components and stategraphs usually handle most things.

 

Also, whether an action can even be performed is chosen in components, using the "CollectThingActions" functions (CollectSceneActions, CollectInventoryActions, etc.). Make sure the "juice" component has such a function, which, as said, can mostly be copied from "dryable".

 

Good luck!

Thanks Mobbie! I think that helped him.

I award you with this badge: http://www.stevefarber.com/wp-content/uploads/badge-1.png

Link to comment
Share on other sites

@Mobbstar,

Thanks for the help, but one last thing. I got rabbits to count as juice and the structure to count as juicemachine (replaced every instance of dryable with juice and every instance of dryer with juicemachine) and copied the "DRY" action and renamed it "extractjuice" (and replaced "dry" with "extractjuice" in the juice prefab). I THINK it recognizes this stuff since hovering a rabbit over the structure shows "Extract". However, clicking does nothing (my character just walks to the structure). What am I doing wrong? Was I not supposed to copy the DRY action?

Link to comment
Share on other sites

@Mobbstar,

Thanks for the help, but one last thing. I got rabbits to count as juice and the structure to count as juicemachine (replaced every instance of dryable with juice and every instance of dryer with juicemachine) and copied the "DRY" action and renamed it "extractjuice" (and replaced "dry" with "extractjuice" in the juice prefab). I THINK it recognizes this stuff since hovering a rabbit over the structure shows "Extract". However, clicking does nothing (my character just walks to the structure). What am I doing wrong? Was I not supposed to copy the DRY action?

 

Hey, that's already pretty good! But I can't help you troubleshooting the last errors without seeing the code (or crash log, if it was crashing). Post all related code here, ideally using spoiler tags (using "special BB code" button).

Link to comment
Share on other sites

@Mobbstar,

Part of modmain.lua

ACTIONS.extractjuice = GLOBAL.Action()
ACTIONS.extractjuice.str = "Extract"
ACTIONS.extractjuice.id = "extractjuice"
ACTIONS.extractjuice.fn = function(act)
if act.target.components.juicemachine then
   local ingredient = act.doer.components.inventory:RemoveItem(act.invobject)
   
   if not act.target.components.juicemachine:StartDrying(ingredient) then
       act.doer.components.inventory:GiveItem(product,nil, Vector3(TheSim:GetScreenPos(act.target.Transform:GetWorldPosition()) ))
       return false
   end
        return true
    end
end

 

juice.lua (dryable)

local juice = Class(function(self, inst)
    self.inst = inst
    self.product = nil
    self.drytime = nil
end)
 
function juice:SetProduct(product)
    self.product = product
end
 
function juice:GetProduct()
    return self.product
end
 
function juice:GetDryingTime()
    return self.drytime
end
 
function juice:SetDryTime(time)
    self.drytime = time
end
 
function juice:CollectUseActions(doer, target, actions)
    if target.components.juicemachine and target.components.juicemachine:CanDry(self.inst) then
        table.insert(actions, ACTIONS.extractjuice)
    end
end
 
return juice
 
juicemachine.lua (dryer)
local function DoDry(inst)
    local juicemachine = inst.components.juicemachine
    if juicemachine then
   juicemachine.task = nil
   
   if juicemachine.ondonecooking then
   juicemachine.ondonecooking(inst, juicemachine.product)
   end
    end
end
 
local juicemachine = Class(function(self, inst)
    self.inst = inst
    self.targettime = nil
    self.ingredient = nil
    self.product = nil
    self.onstartcooking = nil
    self.oncontinuecooking = nil
    self.ondonecooking = nil
    self.oncontinuedone = nil
    self.onharvest = nil
end)
 
function juicemachine:SetStartDryingFn(fn)
    self.onstartcooking = fn
end
 
function juicemachine:SetContinueDryingFn(fn)
    self.oncontinuecooking = fn
end
 
function juicemachine:SetDoneDryingFn(fn)
    self.ondonecooking = fn
end
 
function juicemachine:SetContinueDoneFn(fn)
    self.oncontinuedone = fn
end
 
function juicemachine:SetOnHarvestFn(fn)
    self.onharvest = fn
end
 
function juicemachine:GetTimeToDry()
if self.targettime then
return self.targettime - GetTime()
end
return 0
end
 
function juicemachine:IsDrying()
    return self.targettime and self:GetTimeToDry() > 0
end
 
function juicemachine:IsDone()
    return self.product and self.targettime and self:GetTimeToDry() < 0
end
 
function juicemachine:CanDry(juice)
    return not self:IsDone() and not self:IsDrying()
           and juice.components.juice and juice.components.juice:GetProduct() and juice.components.juice:GetDryingTime()
end
 
function juicemachine:StartDrying(juice)
if self:CanDry(juice) then
   self.ingredient = juice.prefab
   if self.onstartcooking then
   self.onstartcooking(self.inst, juice.prefab)
   end
   local cooktime = juice.components.juice:GetDryingTime()
   self.product = juice.components.juice:GetProduct()
   self.targettime = GetTime() + cooktime
   self.task = self.inst:DoTaskInTime(cooktime, DoDry)
   juice:Remove()
return true
end
end
 
function juicemachine:OnSave()
    
    if self:IsDrying() then
local data = {}
data.cooking = true
data.ingredient = self.ingredient
data.product = self.product
data.time = self:GetTimeToDry()
return data
    elseif self:IsDone() then
local data = {}
data.product = self.product
data.done = true
return data
    end
end
 
function juicemachine:OnLoad(data)
    --self.produce = data.produce
    if data.cooking then
self.product = data.product
self.ingredient = data.ingredient
if self.oncontinuecooking then
self.oncontinuecooking(self.inst, self.ingredient)
self.targettime = GetTime() + data.time
self.task = self.inst:DoTaskInTime(data.time, DoDry)
end
    elseif data.done then
self.targettime = GetTime() - 1
self.product = data.product
if self.oncontinuedone then
self.oncontinuedone(self.inst, self.product)
end
    end
end
 
function juicemachine:GetDebugString()
    local str = nil
    
if self:IsDrying() then 
str = "COOKING" 
elseif self:IsDone() then
str = "FULL"
else
str = "EMPTY"
end
    if self.targettime then
        str = str.." ("..tostring(self.targettime - GetTime())..")"
    end
    
    if self.product then
str = str.. " ".. self.product
    end
    
return str
end
 
function juicemachine:CollectSceneActions(doer, actions)
    if self:IsDone() then
        table.insert(actions, ACTIONS.HARVEST)
    end
end
 
 
function juicemachine:Harvest( harvester )
if self:IsDone() then
if self.onharvest then
self.onharvest(self.inst)
end
if self.product then
if harvester and harvester.components.inventory then
local loot = SpawnPrefab(self.product)
if loot then
if loot and loot.components.perishable then
   loot.components.perishable:SetPercent(1) --always full perishable
end
harvester.components.inventory:GiveItem(loot, nil, Vector3(TheSim:GetScreenPos(self.inst.Transform:GetWorldPosition())))
end
end
self.product = nil
end
 
return true
end
end
 
 
function juicemachine:LongUpdate(dt)
if self:IsDrying() then
if self.task then
self.task:Cancel()
self.task = nil
end
 
local time_to_wait = self.targettime - GetTime() - dt
if time_to_wait <= 0 then
self.targettime = GetTime()
DoDry(self.inst)
else
self.targettime = GetTime() + time_to_wait
self.task = self.inst:DoTaskInTime(time_to_wait, DoDry)
end
 
 
end
end
 
 
return juicemachine
 
brainmachine.lua (the structure)
local assets =
{
Asset("ANIM", "anim/brainmachine.zip"),
 
}
 
local prefabs =
{
-- everything it can "produce" and might need symbol swaps from
"brainjuice",
"rabbit",
}
 
local function onhammered(inst, worker)
inst.components.lootdropper:DropLoot()
SpawnPrefab("collapse_small").Transform:SetPosition(inst.Transform:GetWorldPosition())
inst:Remove()
inst.SoundEmitter:PlaySound("dontstarve/common/destroy_metal")
end
        
local function onhit(inst, worker)
 
end
 
local function getstatus(inst)
    if inst.components.juicemachine and inst.components.juicemachine:IsDrying() then
        return "DRYING"
    elseif inst.components.juicemachine and inst.components.juicemachine:IsDone() then
        return "DONE"
    end
end
 
local function onstartdrying(inst, juice)
    inst.AnimState:PlayAnimation("full")
end
 
local function setdone(inst, product)
    inst.AnimState:PlayAnimation("done")
end
 
local function ondonedrying(inst, product)
    inst.AnimState:PlayAnimation("done")
    local ondonefn -- must be forward declared, as it refers to itself in the function body
    ondonefn = function(inst)
        inst:RemoveEventCallback("animover", ondonefn)
        setdone(inst, product)
    end
    inst:ListenForEvent("animover", ondonefn)
end
 
local function onharvested(inst)
    inst.AnimState:PlayAnimation("idle")
end
 
local function onbuilt(inst)
inst.AnimState:PlayAnimation("idle")
end
 
local function fn(Sim)
local inst = CreateEntity()
local trans = inst.entity:AddTransform()
local anim = inst.entity:AddAnimState()
 
inst.entity:AddMiniMapEntity()
inst.MiniMapEntity:SetIcon( "brainmachine_map.tex" )
 
    inst.entity:AddSoundEmitter()
    inst:AddTag("structure")
 
    anim:SetBank("brainmachine")
    anim:SetBuild("brainmachine")
    anim:PlayAnimation("idle")
 
    inst:AddComponent("lootdropper")
    inst:AddComponent("workable")
    inst.components.workable:SetWorkAction(ACTIONS.HAMMER) -- should be DRY
    inst.components.workable:SetWorkLeft(4)
inst.components.workable:SetOnFinishCallback(onhammered)
-- inst.components.workable:SetOnWorkCallback(onhit)
 
inst:AddComponent("juicemachine")
inst.components.juicemachine:SetStartDryingFn(onstartdrying)
inst.components.juicemachine:SetDoneDryingFn(ondonedrying)
inst.components.juicemachine:SetContinueDryingFn(onstartdrying)
inst.components.juicemachine:SetContinueDoneFn(setdone)
inst.components.juicemachine:SetOnHarvestFn(onharvested)
    
MakeObstaclePhysics(inst, 0.3)
 
    inst:AddComponent("inspectable")
    
    inst.components.inspectable.getstatus = getstatus
MakeSnowCovered(inst, .01)
inst:ListenForEvent( "onbuilt", onbuilt)
    return inst
end
 
 
 
return Prefab( "common/objects/brainmachine", fn, assets, prefabs ),
  MakePlacer("common/brainmachine_placer", "brainmachine", "brainmachine", "idle")  
 
Game doesn't crash. Here's the rest of the mod if the stuff in spoilers isn't enough: http://forums.kleientertainment.com/files/file/1240-wunt-the-extraterrestrial/

 

Link to comment
Share on other sites

Sorry, I can't figure it out. The action fn doesn't fire for no obvious reason.

 

lol nevermind, I just remembered. Actions require you to edit the stategraph if they aren't instant. Either make your action instant or modify wilsons stategraph to add a state for inserting extraction stuff.

Link to comment
Share on other sites

@Mobbstar

How do I do this? I want it to use the "doshortaction" state. I tried copying the state under a different name, putting it in a function in modmain.lua, and then putting in "AddStategraphState ("SGwilson", [function name])", same thing with AddStategraphPostinit, neither worked. Putting in the state without a function makes the game crash. Also, I've been putting in "local actionhandlers= ActionHandler(ACTIONS.extractjuice, "(name of state)")", but that didn't seem to do anything no matter where I put it (I also tried simply putting that in with doshortaction, didn't work).

 

http://dontstarveapi.com/utility/modutil/ seems pretty vague on the stategraph stuff.

Link to comment
Share on other sites

@Mobbstar

Currently, this is what I have in my modmain

local Action = GLOBAL.Action
local ActionHandler = GLOBAL.ActionHandler
local extractjuice = Action()
extractjuice.str = "Extract"
extractjuice.id = "extractjuice"
extractjuice.fn = function(act)
if act.target.components.juicemachine then
   local ingredient = act.doer.components.inventory:RemoveItem(act.invobject)
   
   if not act.target.components.juicemachine:StartDrying(ingredient) then
       act.doer.components.inventory:GiveItem(product,nil, Vector3(TheSim:GetScreenPos(act.target.Transform:GetWorldPosition()) ))
       return false
   end
        return true
    end
end 
AddAction(extractjuice)
AddStategraphActionHandler('wilson', ActionHandler(extractjuice, "doshortaction"))
 
It seems to be working in that I can actually put "juice" items in the brainmachine now, which plays "doshortaction" and makes the machine start and finish drying. However, when I try to harvest the product, my character says "I can't do that!" and doesn't harvest. I do have "inst.components.juice:SetProduct("brainjuice")" in the override function and the product item itself is probably not the problem since I can spawn it in with no issue. What am I doing wrong? (if this is insufficient information the full mod is somewhere in this thread)
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.

×
  • Create New...