# \[A23\] Improving the Lua: a modder's insight (devs, please read)

**URL:** <https://discourse.stonehearth.net/t/a23-improving-the-lua-a-modders-insight-devs-please-read/33515>\
**Category:** Scripting & Code\
**Created:** [January 27, 2018, 10:52pm UTC](https://discourse.stonehearth.net/t/a23-improving-the-lua-a-modders-insight-devs-please-read/33515 "2018-01-27T22:52:39Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Pawel\_Malecki](https://sea2.discourse-cdn.com/flex022/user_avatar/discourse.stonehearth.net/pawel_malecki/32/52928_2.png) [@Pawel\_Malecki](https://discourse.stonehearth.net/u/Pawel_Malecki)\
**Post date:** [January 27, 2018, 10:52pm UTC](https://discourse.stonehearth.net/t/a23-improving-the-lua-a-modders-insight-devs-please-read/33515/1 "2018-01-27T22:52:39Z")

</div>

As I was modding various things, autoharvest for renewables being one of them, I found areas where small additions to the code could benefit the possibilities a lot. I decided to list them here.

**task\_tracker\_component.lua** : in many cases, especially with more than one player, it would be beneficial to be able to inform components about task cancellations so they can double-check how their situation has changed; this solution has practically no impact on performance as it is just a single event:

```auto
function TaskTrackerComponent:cancel_current_task(should_reconsider_ai)
   log:debug('Entity %s: cancelling current task \"%s\"', self._entity, tostring(self._sv.task_activity_name))

   local can_reconsider = false
   if self._sv.task_player_id ~= nil then
      can_reconsider = true
   end

   if self._task_effect then
      log:debug('Entity %s: removing effect "%s"', self._entity, self._sv._task_effect_name)
      self._task_effect:stop()
      self._task_effect = nil
   end
   if self._position_trace then
      self._position_trace:destroy()
      self._position_trace = nil
   end

   -- ADDITION: it is necessary to store event data prior to cancellation
   local cancel_info = {entity = self._entity, player_id = self._sv.task_player_id, category = self._sv.task_category, activity_name = self._sv.task_activity_name}

   self._sv.task_player_id = nil
   self._sv.task_category = nil
   self._sv.task_activity_name = nil
   self._sv._task_effect_name = nil
   self._sv._cancelled_if_entity_moves = false

   if can_reconsider and should_reconsider_ai then
      stonehearth.ai:reconsider_entity(self._entity, 'task tracker cancelling task')
   end

   self.__saved_variables:mark_changed()

   -- ADDITION: trigger an event so components can notice a task being removed and react properly
   radiant.events.trigger(self._entity, 'stonehearth:task_tracker:task_cancelled', cancel_info)

   return self
end

```

**place\_item\_call\_handler.lua** : this is not an optimal solution, but there is no way to restock objects which have no player ID assigned (e.g. berry bushes) so they cannot be undeployed; assigning player ID during undeploying is a temporary solution as it won’t work properly in mulitplayer:

```auto
function PlaceItemCallHandler:undeploy_item(session, response, item)
   local efc = item:get_component('stonehearth:entity_forms')
   if efc then
      -- ADDITION: setting the player ID here allows to undeploy items with no player ID
      radiant.entities.set_player_id(item, session.player_id)

      local current_value = efc:get_should_restock()
      efc:set_should_restock(not current_value)
   end

   radiant.events.trigger_async(item, 'stonehearth:item_undeployed')
   return true
end

```

**renewable\_resource\_node\_component.lua** : here we have two places which can result in buggy behaviour:

1. if the node is not harvestable on load starting model variant and description are not updated:

```auto
function RenewableResourceNodeComponent:post_activate()

   if not self._sv.renew_timer and not self._sv.harvestable then
      self:_update_renew_timer()
   end
   --If we're harvestable on load, fire the harvestable event again,
   --in case we need to reinitialize tasks and other nonsavables on the event
   if self._sv.harvestable then
      radiant.events.trigger(self._entity, 'stonehearth:on_renewable_resource_renewed', {target = self._entity, available_resource = self._resource})
   -- ADDITION: in case we are not harvestable on load we should use depleted model and description
   else
      local render_info = self._entity:add_component('render_info')
      render_info:set_model_variant('depleted')

      if self._json.unripe_description then
         radiant.entities.set_description(self._entity, self._json.unripe_description)
      end
   end
end

```

1. unlike resource node, renewable resource node does not cancel tasks when harvest is requested:

```auto
function RenewableResourceNodeComponent:request_harvest(player_id)
   if not self:is_harvestable() then
      return false
   end

   local task_tracker_component = self._entity:add_component('stonehearth:task_tracker')
   if task_tracker_component:is_activity_requested(HARVEST_ACTION) then
      return false -- If someone has requested to harvest already
   end

   -- ADDITION: cancel tasks (pasted from resource_node_component.lua)
   task_tracker_component:cancel_current_task(false) -- cancel current task first and force the resource node harvest

   local json = self._json
   local category = json.category or 'harvest'
   local success = task_tracker_component:request_task(player_id, category, HARVEST_ACTION, json.harvest_overlay_effect)
   return success
end

```

**farming\_service.lua** : it would be nice if it was possible to specify starting crop availability per biome as well as per kingdom:

```auto
function FarmingService:_get_crop_list(session)
   local player_id = session.player_id
   local crop_list = self._data.player_crops[player_id]
   if not crop_list then
      -- xxx: look this up from the player info when that is avaiable
      local kingdom = stonehearth.population:get_population(player_id):get_kingdom()
      -- start out with the default crops for this player's kingdom.
      crop_list = {}
      local all_crops = self._all_crops
      local kingdom_crops = self._initial_crops[kingdom]
      -- ADDITION: biome-enabled crops are added to the list of available crops
      ----[[
      local enabled_crops = kingdom_crops
      local biome = stonehearth.world_generation:get_biome_alias()
      local biome_crops = self._initial_crops[biome]
      if biome_crops then
         for key, crop in pairs (biome_crops) do
            enabled_crops[key] = crop
         end
      end
      --]]
      -- gather data when all available crops are listed in enabled_crops
      if enabled_crops and all_crops then
         for key, crop in pairs(all_crops) do
            crop_list[key] = {
               crop_key = key,
               crop_type = crop.crop_type,
               crop_info = self:get_crop_details(crop.crop_type),
               crop_level_requirement = crop.level_requirement,
               ordinal = crop.ordinal,
               initial_crop = enabled_crops[key]
            }
         end
      end
      self._data.player_crops[player_id] = crop_list
   end
   return crop_list
end

```

I decided to write this because after looking at code changes affecting my mods I noticed the new alpha uses a resource call handler fix for renewable and one-time resource nodes used in BrunoSupremo’s mods so I thought someone may find my observations useful.
