Question: How would you make the Berry_Bush drop two different resources?

Hey guys. I’ve got another question for you.

This is the berry bush code. I want it to drop another resource or item. I’ve added the url path for the oak_log but now the Berry Bush will only drop Oak Logs.

{
“type”: “entity”,
“components”: {
“model_variants”: {
“default”: {
“models”: [
“file(berry_bush.qb)”
]
},
“depleted”: {
“models”: [
“file(berry_bush_empty.qb)”
]
}
},
“render_info” : {
“scale” : 0.15
},
“mob” : {
“model_origin” : { “x”: -0.075, “y”: 0, “z”: 0.075 },
“region_origin” : { “x”: 0.5, “y”: 0, “z”: 0.5 }
},
“region_collision_shape” : {
“region”: [
{
“min” : { “x” : -1, “y” : 0, “z” : -1 },
“max” : { “x” : 2, “y” : 2, “z” : 2 }
}
]
},
“destination” : {
“region” : [
{
“min” : { “x” : -1, “y” : 0, “z” : -1 },
“max” : { “x” : 2, “y” : 1, “z” : 2 }
}
]
},
“unit_info”: {
“name”: “Berry Bush”,
“description”: “Harvestable for a meager food supply.”
},
“stonehearth:renewable_resource_node”: {
“task_group_name” : “stonehearth:task_group:harvest”,
“resource” : “stonehearth:food:berries:berry_basket”,
“resource” : “stonehearth:resources:wood:oak_log”,
“renewal_time” : “1h”,
“harvest_command” : “harvest_berries”,
“unripe_description” : “Not yet ripe for harvest.”,
“harvest_overlay_effect” : “/stonehearth/data/effects/harvest_plant_overlay_effect”
}
}
}

Any ideas?

Well, right now you’re overwriting the property resource with the oak log. I bet you’ll have to modify stonehearth:renewable_resource_node to make it accept resource as an array, if it doesn’t, and force it to drop every element in the array rather than just the one resource. When finished, your code should look like this:

"stonehearth:renewable_resource_node": {
  "task_group_name" : "stonehearth:task_group:harvest",
  "resource" : [ 
    "stonehearth:food:berries:berry_basket", 
    "stonehearth:resources:wood:oak_log" 
  ],
  "renewal_time" : "1h",
  "harvest_command" : "harvest_berries",
  "unripe_description" : "Not yet ripe for harvest.",
  "harvest_overlay_effect" : "/stonehearth/data/effects/harvest_plant_overlay_effect"
}

I’m going to take a crack at it and report back to this thread if I have anything.

4 Likes

So I got it to work, though not the way I thought I would. A little hack I learned from the live streams:

entities/plants/berry_bush.json:

"stonehearth:renewable_resource_node": {
   "task_group_name" : "stonehearth:task_group:harvest",
   "resource" : { 
      "stonehearth:food:berries:berry_basket" : "",
      "stonehearth:resources:wood:oak_log" : ""
   },
   "renewal_time" : "22h",
   "harvest_command" : "harvest_berries",
   "unripe_description" : "Not yet ripe for harvest.",
   "harvest_overlay_effect" : "/stonehearth/data/effects/harvest_plant_overlay_effect"
}

And then, in components/renewable_resource_node/renewable_resource_node_component.luac, find the function spawn_resource, and replace it with:

function RenewableResourceNodeComponent:spawn_resource(owner,location)
    if self._resource then
        local item
        if type( self._resource )  == "table" then
          for key, value in pairs(self._resource) do
            item=radiant.entities.create_entity(key)
            local pt=radiant.terrain.find_placement_point(location,0,2)
            radiant.terrain.place_entity(item,pt)
            stonehearth.inventory:get_inventory(owner):add_item(item)
          end
        else
          item=radiant.entities.create_entity(self._resource)
          local pt=radiant.terrain.find_placement_point(location,0,2)
          radiant.terrain.place_entity(item,pt)
          stonehearth.inventory:get_inventory(owner):add_item(item)
        end

        local render_info=self._entity:add_component('render_info')
        render_info:set_model_variant('depleted')
        self:_start_renew_timer(self._renewal_time)
        if self._unripe_description then
            self._entity:get_component('unit_info'):set_description(self._unripe_description)
        end
        if self._renew_effect_name then
        end
        self._sv.harvestable=false
        self.__saved_variables:mark_changed()
        return item
    end
end

Short explanation:

  1. For some reason, Stonehearth doesn’t like reading array values (@RepeatPan, any clue why?)
  2. We substitute the array with a table, in which we will only use the keys (the values are left blank, "").
  3. In the Lua code, we first check whether the node only has one resource, or a bunch (i.e. we check the type of the self._resource variable for whether it’s a table or a string).
  4. If there are multiple components, drop them.
  5. If there is just one component, drop it.

I’ve tested this, and it works with both the modified berry bush and unmodified resources, thanks to us checking the type of the resource before dropping it. Now the hard part, packaging all this into an smod, I’ll leave to you :smile:

EDIT: Be careful, the function spawn_resource returns an item when it completes. If there’s only one resource being dropped, that’s fine. If there’s more than one, only the last item dropped gets returned. I don’t know how this can/will affect the game right now, but it’s something to keep in mind.

2 Likes

Lol. Thank you very much.

I’m going to have a fiddle with it :smiley:

Protip: if you aren’t using Lua Unminifier, grab it. It’ll be much easier to read the minified lua code with it. I copy-paste the unminified file from the formatter into the corresponding file inside the unpacked mods/stonehearth/ directory, then I can test it. Best of luck!

2 Likes

It can deal with arrays just well, but stonehearth:renewable_resource_node does not support such behaviour (as you surely have noticed). It’s currently hardcoded to drop one item. I don’t really understand what you mean with “doesn’t like reading array values”. If you use [ "stonehearth:food:berries:berry_basket", "stonehearth:resources:wood:oak_log"] it would likely work fine (remember that JSON differentiates between arrays and objects, which lua does not).

I think the object approach is valid, but I would change it to the format "resource_ref" : amount_dropped. This way, multiple resources could easily drop from one resource node.

As a solution that does not require a code change and therefore is much safer, but is smore work:
The spawned item could have a component that spawns these items and then removes the “carrier” (the item that the respawnable resource node spawned). That means, you spawn for example stonehearth:weird_plant_drop which has a component that, upon initializing, spawns some more entities and then removes itself.

1 Like

The following appears to work, provided self._resource is a table with entity names as keys:

for key, value in pairs(self._resource) do
  item=radiant.entities.create_entity(key)

The following throws something of a “Unrecognized overload” error, provided self._resource is an array of entity name strings:

for i, value in ipairs(self._resource) do
  item=radiant.entities.create_entity(value)

As does this:

for i, value in ipairs(self._resource) do
  item=radiant.entities.create_entity(self._resource[i])

Am I getting the syntax wrong somewhere?

Well, you’re missing the end for starters. Then I would print what you actually are trying to create (i.e. the value). Last but not least, ipairs is deprecated and will be removed in lua 5.2, it should not be used. pairs or a normal for with #self._resource are the way to go, preferably the first.

We use both arrays and tables in SH, but tables enforce more reliable behavior when dealing with mixins and overrides, so we tend to prefer using tables when possible, even if that means more work in the short-term.

Good work! :smiley:

6 Likes