XP from Ability Use?

I know that Clerics can earn XP from healing, I was wondering if I could make a class earn experience when using a certain ability and how would I go about doing that.

Just give me a rough idea where to look I suppose and I might be able to figure it out as long as it’s not overly complicated.

In general, you can grant exp points via the add_exp function of the job component.

If your ability is a new AI action that gets injected, you just have to retrieve the job component in it and grant the exp when the action is complete, or even better, fire an event so that any relevant class gets notified.

See cleric.lua :

function ClericClass:_create_listeners()
   CombatJob._create_listeners(self)
   self._on_heal_entity_listener = radiant.events.listen(self._sv._entity, 'stonehearth:healer:healed_entity', self, self._on_healed_entity)
   self._on_heal_entity_in_combat_listener = radiant.events.listen(self._sv._entity, 'stonehearth:healer:healed_entity_in_combat', self, self._on_healed_entity_in_combat)
   self._on_calories_changed_listener = radiant.events.listen(self._sv._entity, 'stonehearth:expendable_resource_changed:calories', self, self._on_calories_changed)
end

function ClericClass:_on_healed_entity_in_combat(args)
   self:_add_exp('heal_entity_in_combat')
end

-- Get xp reward using key. Xp rewards table specified in cleric description file
function ClericClass:_add_exp(key)
   local exp = self._xp_rewards[key]
   if exp then
      self._job_component:add_exp(exp)
   end
end

In the heal actions we trigger the 'stonehearth:healer:healed_entity_in_combat' event, and we listen to it here , granting the exp any time that it happens (remember to clean your listeners properly in the demote/destroy functions too - in this particular example, we overwrite the _remove_listeners() from combat_job.lua to add our new listeners to the list. That function actually comes from base_job.lua so you should be able to overwrite that one too if your job isn’t a combat job).

I’ve copied basically all that from the cleric, but I’m stuck at not knowing what to do next.
In the execute_heal_action.lua there is this:

function HealRangedInSight:_heal(healer, target, weapon_data)
   if not target:is_valid() then
      return
   end

   local heal_info = self._heal_info
   local total_healing = stonehearth.combat:calculate_healing(healer, target, heal_info)
   local heal_context = HealContext(healer, target, total_healing)

   if stonehearth.combat:heal(heal_context) then
      radiant.events.trigger_async(healer, 'stonehearth:healer:healed_entity_in_combat', { entity = target })
   end
end

that’s where you trigger the event you mentioned. in my execute_summon_action.lua I’m guessing I need to add a trigger. This will be hard for me since .lua is like ancient Egyptian to me haha I don’t even know where to start when looking. This is what mine looks like in what I’m guessing would be the same spot:

function ExecuteSummon:_summon(summoner, target, weapon_data)
    if not target:is_valid() then
        return
    end
    local summon = self:_create_summon(summoner, target, self._summon_uri)
    
    local summon_info = self._summon_info
    
    
    local destroy_trace
    destroy_trace = radiant.events.listen(summon, 'radiant:entity:pre_destroy', function()
        if summon:is_valid() then
            --radiant.effects.run_effect(summon, 'stonehearth:effects:firepit_effect:green')
        end
        
        if destroy_trace then
            destroy_trace:destroy()
            destroy_trace = nil
        end
    end)
end

My .lua guy’s heart just isn’t into modding this game anymore, so I’m sort of at a loss.

If you want to grant the exp right after summoning, I guess you can trigger the event inside _create_summon.

It’s the same, just add something like this:

radiant.events.trigger_async(summoner, 'your_mod:invented_event_name')

Here’s a short explanation about events.

I’m probably too sleepy to continue right now, but adding it where I thought it’d go isn’t doing anything once I’m actually in game summoning. No errors, but no xp either lol

You’ll have to add a listener in the job’s lua file if there isn’t one already.

this?

self._on_summon_listener = radiant.events.listen(self._sv._entity, 'box_o_vox:necromancer:has_summoned', self, self._on_summon)

it’s there, but again I could be missing something or a whole lot of things haha

Yes, are you adding the exp in _on_summon there?

function NecromancerClass:_on_summon(args)
self:_add_exp(‘summon’)

and this is in the job description under xp_rewards

"summon": 20

:thinking:

It might be working then. You won’t get any notification unless the hearthling gains enough exp to level up.

Try changing that 20 to 2000 just for testing.

I thought I’d see a change in their level bar when opening character sheet. I’ll try with super number :smiley:

Oh, you’re right, they should be visible in the exp bar. But 20 is a low number. I think for the first level up it’s around 250.

If you don’t see a change, try adding this

function NecromancerClass:_on_summon(args)
self:_add_exp('summon')
print('ADDED EXP')

This should print a message in the stonehearth.log after adding the exp. If it doesn’t appear, it’s because the function isn’t being called.

You can also check the current exp amount with debugtools.

1 Like

Shouldn’t be job_component:add_exp(10)? Looking here it accepts numbers only

Yes, but this is _add_exp().
It’s a private function copied from cleric.lua that picks up the corresponding amount of exp depending on the key – so different events can point to different keys):

function ClericClass:_add_exp(key)
   local exp = self._xp_rewards[key]
   if exp then
      self._job_component:add_exp(exp)
   end
end
1 Like

I tried looking at @BrunoSupremo 's Fisher mod and got an idea from there, but it still doesn’t work. I’d post the file for you to look at, but it might be crazy to look at lol Owl wrote it himself very early on with the mod, somewhere like almost 2 years ago. I also don’t want to seem like I’m having others do the work for me, but I honestly don’t understand .lua enough to play around in there. I’m certain I’m just derping on something small as I’ve almost copy/paste everything from cleric.lua that looks relative into my necromancer.lua so it has to be somewhere in my execute_summon_action.lua that I’m not using the trigger correctly or in the right field. If anyone does feel like taking a peek. I’ll post both files below. Thanks in advance for any additional help you can provide. :heart: :wink:

execute_summon_action.lua (6.7 KB)
necromancer.lua (3.3 KB)
(uploaded as a .txt file since .json is not supported here)
necromancer_description.txt (7.8 KB)

You have this typo:

function NecromancerClass:_on_summon(args)
   self:_add_exp('summon')
   log:error('no exp dude')
end

-- Get xp reward using key. Xp rewards table specified in necromancer description file
function NecromancerClass:_on_summon(key)
   local exp = self._xp_rewards[key]
   if exp then
      self._job_component:add_exp(exp)
   end
end

The second function should be called _add_exp

That didn’t solve the problem. Also, in the cleric.lua it’s like that, so?

-- Get xp reward using key. Xp rewards table specified in cleric description file
function ClericClass:_add_exp(key)
   local exp = self._xp_rewards[key]
   if exp then
      self._job_component:add_exp(exp)
   end
end

Just to make sure, you changed it like this:

And still it doesn’t increase the exp in the bar in the UI after summoning?

The typo I mentioned is that both functions are called _on_summon, which is wrong.

1 Like

Can’t add anything beyond you have my sympathies andreal, lua drives me bonkers too.

1 Like

Thanks, I got lucky to have a viewer show up while I was streaming who has an understanding of .lua

We were able to get the Necromancer to earn XP from performing the summon action. Problem now is we don’t know why it’s triggering twice? so it was giving the XP 2 times.

For now I simply made the amount of xp earned half as much as I want since it’s going to double lol

1 Like