Page 1 of 1
Check talents for failure
Posted: Thu Oct 15, 2015 3:05 am
by Charidan
I want to see if a talent has failed to properly cast. Specifically, T_RUSH. When you cast Player:useTalent(T_RUSH), it lets you pick an enemy, and then it tries to find a straight path to that target. In my case, I force the target. If the path is blocked (by say a pit) the talent will do nothing other than print a console message ("You are too close to build up momentum!" or, in the pit case, nothing), will not go on cooldown, and Player:useTalent(T_RUSH) will return true.
If I'm specifically concerned with Rush I can just check if my (x,y) changed, but I want to figure out if the talent failed without knowing if it's Rush (in case there exists any other talent ever that can fail similarly). I can't just check if it went on cooldown, because some talents like T_SHOOT don't have cooldowns, and I really want to allow Shoot to be used multiple times a turn.
How can I check that it actually cast?
Re: Check talents for failure
Posted: Thu Oct 15, 2015 11:13 am
by Radon26
edit NVM
Re: Check talents for failure
Posted: Thu Oct 15, 2015 11:38 am
by Micbran
I can't just check if it went on cooldown...
Pls
Anyways, could you possibly check for resource use? Wouldn't work for some cases, but that's all I can think of. Unless you want to superload all those talents and replace them with versions that tell you when they fail.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 12:34 pm
by Radon26
if cooldown can't work "because shot", the case with resources will be the same...
you correct me and then do the same.
and no, "time" resource is not an argument, because of virulent disease, willful combat, deadly strikes, thorn grab, a lot of sustains, and some chronomancy spells.
but there are no abilities that are BOTH, instant cast, and without cooldown.
if there is no single check that can do the trick, do both.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 1:49 pm
by Micbran
Shot uses a resource. It uses either arrows or shots from your pouch.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 2:49 pm
by Radon26
then how about a melee attack?
Re: Check talents for failure
Posted: Thu Oct 15, 2015 3:39 pm
by Micbran
Melee attacks fail if they don't have a target and aren't instant.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 4:14 pm
by Radon26
they are not instant, meaning "time passed" check can detect success or fail.
what about "relentless pursuit"?
it uses no resource, and is instant, but has a cooldown.
does it have any "fail if X=true/false"?
i still think "time passed or talent on cooldown" would be both a good check.
if both say "no", then the talent has failed.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 7:50 pm
by Charidan
Allow me to clarify some of the terminology and how my code works, in case that helps.
So currently I check, for each enemy in sight, which of my talents are legal to cast. This makes sure that cooling down talents, talents without legal targets, and talents with unmet prerequisites are not even considered. Talents excluded by this point (talents out of range, talents needing you to have a debuff when you don't have one, talents on cooldown, etc.) do not "fail", they simply are not cast.
I then cast the talent with Player:useTalent(talent_id, ... ,force_target). In most cases, this means the chosen talent will be cast on my specified target without prompting the user for confirmation. For reasons unknown, useTalent can return true or false, but always returns true when a talent "mostly casts" or as I call it, "fails". I suspect this is because, for most talents, the talent has fully cast from the game's perspective, just to no effect. On the other hand, there is an "ok" variable (as in, "did the talent casting go ok?") which seems like a good return value, and is exactly what I want to know.
When a talent is successfully cast, it will use some amount of the "time" resource called "energy". Internally, ToME doesn't actually have turns, it just let's people act when their energy hits a certain threshold.
----
Currently, the code assumes that any ability with no energy cost has a cooldown, and therefore should only be cast once per turn. This stops abilities like Cauterize Spirit (Doombringer talent, removes debuffs, but the game lets you cast it on Runic Infusion, Runic Infusion is unremovable, so the talent removes zero debuffs, doesn't go on cooldown, and has effectively "failed") from infinite looping.
Checking for "resource" expenditure is a little awkward, because you basically have to do it manually for each resource, and assuming a new class is added with a new resource, I'm not checking it. If there was a generic way to check if the player has used any resource, or a list of all resources that new addons could be expected to update, that could work though. It actually seems plausible that such a list exists somewhere, I'll look for it.
----
So while considering all your comments, I came up with An Idea, which is a little like what Radon suggested but different. The first thing I check isn't if the talent is cooling down, but if the talent *has a cooldown at all*. If it does, checking if it's cooling down will tell me if it failed or not. If it doesn't, it's not helpful to know it isn't cooling down. Next, I check if it costs energy. I store the player's energy in a local variable before I cast, so I can then check if any energy was spent. If it has no cooldown and doesn't cost energy, I assume it should not be cast more than some maximum number of times. I chose 5.
This isn't the best solution, but it should do the job. I might fiddle that constant if 5 turns out not to be a great number, but there aren't a lot of 20% of a turn or less abilities out there that aren't 0% of a turn. Thanks for all of your input guys!
If you're curious, here's the code I implemented:
Code: Select all
local function markTalentUsed(t, energy_precast)
if t.cooldown then
if game.player:isTalentCoolingDown(t) then
game.player.AI_talentused[t.id] = MAX_TALENT_PER_TURN + 1
end
elseif t.no_energy then
if not game.player.AI_talentused[t.id] then
game.player.AI_talentused[t.id] = 1
else
game.player.AI_talentused[t.id] = game.player.AI_talentused[t.id] + 1
end
elseif energy_precast == game.player.energy.value then
game.player.AI_talentused[t.id] = MAX_TALENT_PER_TURN + 1
end
end
local function filterUsedTalents(t)
local out = {}
local i = 0
for k, v in pairs(t) do
if game.player.AI_talentused[v] ~= nil and game.player.AI_talentused[v] > MAX_TALENT_PER_TURN then
out[i] = v
i = i + 1
end
end
return out
end
-- to cast a talent:
local energy_precast = game.player.energy.value
game.player:setTarget(target.actor)
game.player:useTalent(tid,nil,nil,nil,target.actor)
markTalentUsed(game.player:getTalentFromId(tid), energy_precast)
Re: Check talents for failure
Posted: Thu Oct 15, 2015 8:05 pm
by Radon26
ooze walk, on higher lvls becomes faster to cast, and fungus refunds "energy" when when a regen effect is applied.
other than that i cannot think of any talent on top of my head.
line is "elseif" are you sure there should be no space? there is no spaces in the unlock file and it works, but... just making sure.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 8:23 pm
by Charidan
How fast can Ooze Walk get? If it doesn't dip below 20%, or starts enough ahead of it, this won't even infringe on it. Otherwise I'll make a call.
Fungus is an interesting one, but the way the code is now I only assume there is a failure if energy is unchanged, so gaining energy will also be evidence the power was cast and won't mark the talent as failed. There is an odd case where if you cast a talent with no cooldown and perfectly regain the exact amount of energy spent you fool my algorithm into thinking it failed. I'm gonna go out on a limb and say that situation is sufficiently rare I don't want to care about it right now XD.
In lua, "elseif" is a different keyword from "else" and "if" and functions differently. A lot of languages don't do that. I think it has to do with compiler optimizations, and because lua is a scripting language it can't look ahead and figure it out on it's own the way a compiled language like C would.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 8:34 pm
by Radon26
tome tips says:
"This is quick, requiring only 100%, 72%, 50%, 38%, 31% of a turn to perform,"
it's not 20%, but i am not sure how it would work with global and mind speed.
ancestral life of the fungus category says:
"Each time a regeneration effect is used on you, you gain 85%, 97%, 107%, 115%, 122% of a turn."
soooo uhm... effectively, you would gain 22% instead of losing 100%? not sure is the check or regain is first, or if it's even matter.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 8:36 pm
by Charidan
Riiiiight. Mind speed. Also probably chronomancy.
So if you're playing a class that gets those kinds of crazy speed/action bonuses, the AI will probably be a little suboptimal in its play. I'll probably make the max_talent_per_turn a configurable value once I get configurations working.
EDIT: That's actually not a problem! The count of five uses only applies if the power has No Cooldown and No Energy Cost. Ooze walk costs very little, but it costs anything at all, so it won't accrue a counter.
The only danger is if you regenerate exactly the amount of energy a power used, because then energy before will equal energy after and the AI will assume the power failed to cast. Given that the energy gained is some unlikely cost numbers after it hits level 2 or 3, (what costs more than 100% of a turn?) that should almost never happen.
Re: Check talents for failure
Posted: Thu Oct 15, 2015 10:33 pm
by grayswandir
I'm a bit late, but I thought I'd chime in anyway.
Looking through the code real quick, I think you can wrap postUseTalent located in engine.interface.ActorTalents. As far as I can tell, it's the last check that's made for a talent succeeding. So do something like:
Code: Select all
local postUseTalent = _M.postUseTalent
function _M:postUseTalent(talent, ret, silent)
local result = postUseTalent(self, talent, ret, silent)
if result then self.talent_success = true end
return result
end
And just make sure to properly clear self.talent_success.
Re: Check talents for failure
Posted: Fri Oct 16, 2015 6:40 pm
by Charidan
That is much cleaner, and doesn't have the weird edge cases mine did. Implemented! Thanks again Grayswandir!