Beginner to C++, how do i specify an ability to only target entities with certain jobs?

Hey,
I am looking to create a version of the cleric that can only target particular jobs with heals and buffs. Take for instance if you only wanted your cleric to heal and buff Footmen/Women, Knights and Archers, leaving the other classes to your herbalist?

I did some digging and off the back of some information from one of my previous topics i dug up the add_health_buff.lua and aura_buff.lua. These led me to entities.lua in which i found the “entities.has_job_role” function. This led me to believe that if i gave my desired classes a new and unique role in there description.json such as, “Nazgren” then made my healers abilities require this perk then this would be enough. To this end i looked for how to implement this function and came up with these

custom_add_buff.lua

– Aura buff generic class
– Add this as the script to your buff if you want your buff
– to periodically apply another buff to entities around it
local AuraBuff = class()

function AuraBuff:on_buff_added(entity, buff)
local json = buff:get_json()
self._tuning = json.script_info
if not self._tuning or not self._tuning.aura_buff then
return
end
local pulse_duration = self._tuning.pulse or "15m"
self._entity = entity
self._pulse_listener = stonehearth.calendar:set_interval(“Aura Buff “…buff:get_uri()…” pulse”, pulse_duration,
function()
self:_on_pulse()
end)
if self._tuning.pulse_immediately then
self:_on_pulse()
end
end

function AuraBuff:_on_pulse()
local player_id = radiant.entities.get_player_id(self._entity)
local num_affected = 0
– get everyone around us
local aura_buff = self._tuning.aura_buff
local sensor_name = self._tuning.sensor_name or 'sight’
local sensor = self._entity:add_component(‘sensor_list’):get_sensor(sensor_name)
local enemies_within_range = false
local target_entities = {}
for id, target in sensor:each_contents() do
if id ~= self._entity:get_id() or self._tuning.affect_self then
local target_player_id = radiant.entities.get_player_id(target)
if stonehearth.player:are_player_ids_friendly(player_id, target_player_id) then
local can_target = true
– If we can only target specific type of entity, make sure the entity’s target_type matches
if self._tuning.target_type then
if radiant.entities.get_target_type(target) ~= self._tuning.target_type then
can_target = false
end
end
if not self:_is_within_range(target) then
can_target = false
end

        if can_target then
           table.insert(target_entities, target)
        end
     elseif self._tuning.emit_if_enemies_nearby and not enemies_within_range and stonehearth.player:are_player_ids_hostile(player_id, target_player_id) then
        if self:_is_within_range(target) then
           enemies_within_range = true
        end
     end
  end

end

if self._tuning.emit_if_enemies_nearby and not enemies_within_range then
return – buff needs enemies to be nearby in order to emit the aura buff
end

for _, target in ipairs(target_entities) do
radiant.entities.add_buff(target, aura_buff)
if radiant.entities.has_buff(target, aura_buff) then
num_affected = num_affected + 1
end
end

if num_affected > 0 and self._tuning and self._tuning.pulse_effect then
radiant.effects.run_effect(self._entity, self._tuning.pulse_effect)
end
end

function AuraBuff:_is_within_range(target)
if self._tuning.radius then
local distance = radiant.entities.distance_between_entities(self._entity, target)
if not distance or distance > self._tuning.radius then
return false
end
end
return true
end

function AuraBuff:on_buff_removed(entity, buff)
if self._pulse_listener then
self._pulse_listener:destroy()
self._pulse_listener = nil
end
end
function entities.has_job_role(entity, combat)
local job_component = entity:get_component(‘stonehearth:job’)
if not job_component then
buff:destroy()
end
end

return AuraBuff

I then saved this, replaced the default after making a back up and when i loaded into the game to see if the Clerics would only heal combat jobs i was met with this error:

error

release-771 (x64)[M]
std::logic_error: 'Error loading “stonehearth/data/buffs/scripts/aura_buff.lua”: stonehearth/data/buffs/scripts/aura_buff.lua:90: variable ‘entities’ is not declared’
stack traceback:
[C]: ?
[C]: in function 'require_script’
radiant/modules/mods.lua:11: in function 'load_script’
stonehearth/components/buffs/buff.lua:296: in function '_create_script_controller’
stonehearth/components/buffs/buff.lua:96: in function '_create_buff’
stonehearth/components/buffs/buff.lua:78: in function <stonehearth/components/buffs/buff.lua:73>

So i deleted the “entities”, and left just the (combat), thinking the entities part must be the variable that i was meant to change, not the role_kind but got the exact same error back, even though “entities” no longer existed on line 90.

Where have i gone wrong?

Edit: tried changeing it to target_entities to better match the rest, no change.

Comments in lua require two -, –this is a comment

You don’t need (shouldn’t) copy the function entities.has_job_role(entity, combat)
You can simple call it using radiant.entities.has_job_role(entity, combat)

To target only combat classes, I guess you can use the role “combat”, I’m pretty sure all combat classes have that

Ok, the radiant.entitiy looks familiar so that makes sense, but working from that:

radiant.entities.has_job_role(entity, role_kind)
   local job_component = entity:get_component('stonehearth:job')
   if not job_component then
      return false
   buff:destroy()
   end
end

What is the variable for entities that i change to combat? The error lists it as being on the function entities.has_job_role(entity, role_kind) line but the only thing that would make sense to me to change from this would be whats in the brackets but as i said, there was no change. Forgive my ignorance, as i said, I’m new to this :frowning:

If you are adding this to the addbuff lua file it is wrong.
You should not write that as a new function. Just call it, using radiant.entities.has_job_role(entity, combat). That is all. Replace entity with the entity you want to get the role from, and combat with a string that is present in the classes you want to target.

Also, you have a lot of special characters, like , which is not equivalent to ", and will raise errors

Working off what you said, I put the line radiant.entities.has_job_role(mob, combat) into the .lua, replacing entities with mob as that is what the clerics abilities should target, left combat as is as that is the job role i want targeted and got back the error “variable ‘mob’ is not declared” which is basically the same error that i had before, only with the entity-mob change. Where am i going wrong now?

Did you declared mob? And for the combat parameter, it should be a string

I put it exactly as it is in the above post: radiant.entities.has_job_role(mob, combat)

radiant.entities.has_job_role(mob, “combat”)
Yes, but what you are adding to the mob variable?

“Combat”, is that not the variable? the original example function listed the brackets as (entity, role_kind). When i read this i took it as meaning replace role_kind with what role it is the function is looking for, in this case combat, which is unique to the Footman, Cleric, Knight and Archer. Since i am getting an error saying that i am not declaring the variable i can only assume that its not the case.

Yeah, if combat is a variable holding a string, that it is correct. Otherwise, just write the string directly there, as “combat”.

For the mob variable not being declared, it is exactly that. It is not declared. Where it is coming from? Did you created it or is getting from the function parameter?

From my extremely limited understanding of lua, the aura_buff, a lua that makes an effect on your hearthling apply itself to other entities around it, like the clerics muscle buff or aoe heal, determines the maximum range, the max # of entities to apply it to, if the entity it is trying to apply to is eligible, controls if there must be enemies in range for it to happen, duration of the buff etc. My understanding was that if i call a function that determines if the entity has a certain job role, in this case, combat, then it would allow the buff and if not then it wouldn’t. Is this not the case? Is putting combat after mob, not declaring that the variable is combat?

The function requires two variable, the first is an entity, that should be a hearthling. Just throw it in a variable and put it there in the function.
The second is a string, a text variable, which should contain a text equal to the role you want. You can add your text to a variable and put that variable in the function, or you can skip that step and put the text directly in the function.

I have no idea what is your whole code. But supposing it is a direct copy from the aura_buff.lua, you should just add this:

        if not radiant.entities.has_job_role(target, "combat") then
           can_target = false
        end

At the line 46

1 Like

Aha, I understand now. I wasn’t putting the combat in quotes which I didn’t see done elsewhere so I didn’t put it myself which is why I was getting the null variable. It also didn’t occur to me that it wasn’t that the function wasn’t returning false on the target having the combat role, its that the game didn’t know what to do with the false flag, so by putting the if not before it it looks for the false flag, causing the can_target false to go through. It all becomes clear now. I thought the function returning false would have been enough which in hindsight, with it being no longer 3:30 am makes much more sense

Bruno, you are a Gentleman and a Scholar. Off the back of this i can now go and start piecing together the numerous job abilities for my mod. Thanks for the help and all your patience, much appreciated.