• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Solved Changing damage/healing values before they are applied to a creature

Status
Not open for further replies.

Xikini

I whore myself out for likes
Senator
Joined
Nov 17, 2010
Messages
6,814
Solutions
585
Reaction score
5,379
TFS 0.3.7

This has been driving me a bit crazy, and I'm trying to find a good means to figure this out.
I want to know the raw damage/healing value being sent to a creature.. and be able to alter those values before they are applied to a creature.

Here is anything dealing with creature-creature interactions.

Code:
function onTradeRequest(cid, target, item)
function onTradeAccept(cid, target, item)
function onStatsChange(cid, attacker, type, combat, value)
function onAreaCombat(cid, ground, position, aggressive)
function onPush(cid, target)
function onTarget(cid, target)
function onFollow(cid, target)
function onCombat(cid, target)
function onAttack(cid, target)
function onCast(cid, target)
function onKill(cid, target, damage, flags)
function onDeath(cid, corpse, deathList)
function onPrepareDeath(cid, deathList)

We can throw most of these out since they are useless for what we are trying to do.

Code:
function onStatsChange(cid, attacker, type, combat, value)
function onAreaCombat(cid, ground, position, aggressive)
function onTarget(cid, target)
function onCombat(cid, target)
function onAttack(cid, target)
function onCast(cid, target)
function onKill(cid, target, damage, flags)
function onDeath(cid, corpse, deathList)
function onPrepareDeath(cid, deathList)

We can further get rid of some of these.

onTarget - is when you are specifically targetting a creature
onAttack - is when you are attacking a creature using a weapon of some kind.
OnCast - again focus's on single target
onAreaCombat - doesn't effect single target.. very specific use-case.
onKill/Death/PrepareDeath - all of these are after the damage has been calculated and added.

Code:
function onStatsChange(cid, attacker, type, combat, value)
function onCombat(cid, target)
So we are left with above.

onStatsChange
- "value" is calculated after looking at resistances/immunities/armor/current creature health.(rounding down to creatures max health if the raw value will kill the creature)
- This could work, however "value" is already determined when it get's to this point.
- I haven't found a way to change the value of value and 'continue' with the damage.
- If you return false, it negates all damage. - useful.. but not for what we are doing.

I don't think onStatsChange fit's the bill.
(however if someone knows how to edit value and continue script with the edited value.. that would be awesome to know.. and might be a non-optimal work-around)

I want to see the raw values before they have been altered.

onCombat
Now.. I've never used onCombat before but it doesn't have any direct information.
From the sound of it, it appears to happen the moment that combat is initiated between two targets.

Can onCombat check/detect the values being sent from cid to target?
Or is it only detecting if combat has been initiated?

Is there a function I've overlooked?

I don't feel there is any way to find these damage values before they are calculated and sent to the recipient.

Any feedback would be great, whether it's somber news or an enlightening piece of information.

Cheers,

Xikini
 
i dont think there is a way to see the "raw" values before server applies them and calls onStatsChange (i may be wrong, they may be altered after statsChange, try it out i guess)
but in statsChange you can see current value, and calculate original damage if you really need it, or just change the current one
Code:
function onStatsChange(cid, atk, type, combat, value)
if type == TYPE_HEALTHLOSS (cant remember enum) then
return cid, atk, type, combat, value/2
else
return cid, atk, type, combat, value
end
if the modified value isnt good enough, you can always get the attacked creatures resistances etc (if its a monster) with some functions i believe, and go from there
e.g cid is a dragon, dragon has 50% fire res, if you get 100 value and combat = combat_firedamage (or w/e its called) then value/(1/res)
 
i dont think there is a way to see the "raw" values before server applies them and calls onStatsChange (i may be wrong, they may be altered after statsChange, try it out i guess)
but in statsChange you can see current value, and calculate original damage if you really need it, or just change the current one
Code:
function onStatsChange(cid, atk, type, combat, value)
if type == TYPE_HEALTHLOSS (cant remember enum) then
return cid, atk, type, combat, value/2
else
return cid, atk, type, combat, value
end
if the modified value isnt good enough, you can always get the attacked creatures resistances etc (if its a monster) with some functions i believe, and go from there
e.g cid is a dragon, dragon has 50% fire res, if you get 100 value and combat = combat_firedamage (or w/e its called) then value/(1/res)
Yeah I've tried to return different values before, but it never alters the damage.

Tried this script just now, and here's the results.
Code:
function onStatsChange(cid, attacker, type, combat, value)
     print("--------------\ncid: " .. cid .. "\nattacker: " .. attacker .. "\ntype: " .. type .. "\ncombat: " .. combat .. "\nvalue: " .. value .. "\n--------------")
     if isPlayer(cid) and type == STATSCHANGE_HEALTHLOSS then
         print("Healthloss confirmed.\ntype: " .. type .. "\nvalue: " .. value)
         return cid, attacker, type, combat, value/2
     end
     return true
end
986kGXA.png

Also tried changing value to a new local.
Code:
function onStatsChange(cid, attacker, type, combat, value)
     print("--------------\ncid: " .. cid .. "\nattacker: " .. attacker .. "\ntype: " .. type .. "\ncombat: " .. combat .. "\nvalue: " .. value .. "\n--------------")
     if isPlayer(cid) and type == STATSCHANGE_HEALTHLOSS then
         local new_value = value/2
         print("Healthloss confirmed.\ntype: " .. type .. "\nnew_value: " .. new_value)
         return cid, attacker, type, combat, new_value
     end
     return true
end
SQuj9Wu.png

It's also not by-passing the return.. as I've tested that quickly as well.
Code:
function onStatsChange(cid, attacker, type, combat, value)
     print("--------------\ncid: " .. cid .. "\nattacker: " .. attacker .. "\ntype: " .. type .. "\ncombat: " .. combat .. "\nvalue: " .. value .. "\n--------------")
     if isPlayer(cid) and type == STATSCHANGE_HEALTHLOSS then
         local new_value = value/2
         print("Healthloss confirmed.\ntype: " .. type .. "\nnew_value: " .. new_value)
         return cid, attacker, type, combat, new_value
     end
     print(111111111)
     return true
end
It never prints the 1's.

I'm unsure how to return different values then what's already inside the function.
 
as far as i know, doing it like that works fine in 1.2, but i recall 0.x having some issues with returning stuff, like return true onEquip doesnt work, have to callFunction
maybe try return callFunction(cid,atk,type,combat,value)
if that doesnt work im afraid i dont know how to change it :/
other than not applying the dmg and doing it urself with combatHealth/addHealth that is
 
as far as i know, doing it like that works fine in 1.2, but i recall 0.x having some issues with returning stuff, like return true onEquip doesnt work, have to callFunction
maybe try return callFunction(cid,atk,type,combat,value)
if that doesnt work im afraid i dont know how to change it :/
other than not applying the dmg and doing it urself with combatHealth/addHealth that is
The problem with adding the damage myself is that it creates a feedback loop.
Code:
statschange(cid, blah)
    some damage thing here
    return false
end
Doing the above will simply re-iterate on itself until you get a callstack overflow.. since the damage your applying has to go back through the statschange.

I also tried that as well. :p
Code:
--------------
cid: 268438622
attacker: 1073745000
type: 1
combat: 1
value: 5
--------------
Healthloss confirmed.
type: 1
new_value: 2.5

[7:44:00.949] [Error - CreatureScript Interface]
[7:44:00.950] data/creaturescripts/scripts/test_reduction.lua:onStatsChange
[7:44:00.950] Description:
[7:44:00.950] data/creaturescripts/scripts/test_reduction.lua:6: attempt to call global 'callFunction' (a nil value)
[7:44:00.951] stack traceback:
[7:44:00.951]  data/creaturescripts/scripts/test_reduction.lua:6: in function <data/creaturescripts/scripts/test_reduction.lua:1>
 
Last edited:
if you try the docombathealth just once, is the type/combat the same values? 1.2 has origin arg which can be used to fix this i believe, but not in 0.x :/
you could add negative health i guess, but it would be weird :(

edit: oh yeah, callFunction is in 0.4, not in earlier version
 
What you try to achieve is only possible by denying the statschange and using doTargetCombatHealth, let's say that creature event is on read-mode and just lets you cancel it...unless source-edit is done.
 
What you try to achieve is only possible by denying the statschange and using doTargetCombatHealth, let's say that creature event is on read-mode and just lets you cancel it...unless source-edit is done.
Right yeah.. it seems that way.
I might have to place this into jobs or something.. I definitely am unable to modify sources cuz I'm a noob. :(

Placing my edit down below instead of previous post.
@Zothion
I've also tried doing something like this.. (players only)
Code:
function onStatsChange(cid, attacker, type, combat, value)
     if type == STATSCHANGE_HEALTHLOSS then
         if getPlayerStorageValue(cid, storage) < 1 then
             setPlayerStorageValue(cid, storage, 1)
             if getCreatureHealth(cid) <= value then
                 return true
             end
             local value = value * 0.95
             doTargetCombatHealth(attacker, cid, combat, -value, -value, statsChangeGetEffect(combat))
             return false
         else
             setPlayerStorageValue(cid, storage, 0)
             return true
         end
     end
     return true
end
But doing it this way.. If two creatures attack at the same time before it can change the storage value back.. then it simply cancels itself or returns the true damage instead of the modified damage.

eg:
Code:
attack1 -> calls stat_change_1
attack2 -> calls stat_change_2
stats_change1 -> changes storage to 1 + calls stats_change3
stats_change2 -> changes storage to 0, full damage applied, end.
stats_change3 -> changes storage to 1 + calls stats_change4
stats_change4 -> changes storage to 0, modified damage applied, end.
 
a quick solution would be having a global tables with all the cids, and when you attack you do
Code:
if t[attacker][cid] then
t[attacker][cid] = nil
return true
else
table[attacker][cid] = true
doTargetCombatHealth(...)
end
then multiple attacks on different creatures etc wont interfere, even if you have super fast attack, since it calls the onstatchange, then calls dotargetcombat>statschange before it calls it for the next dmg
 
a quick solution would be having a global tables with all the cids, and when you attack you do
Code:
if t[attacker][cid] then
t[attacker][cid] = nil
return true
else
table[attacker][cid] = true
doTargetCombatHealth(...)
end
I think this is currently out of my scripting ability.
Do you think you could try to explain it to me via PM?
 
Closing as solved. Can a mod please lock the thread?

The solution is obv. a source edit as @cbrm advises.

A semi-solution to the stats_change issue provided by @Zothion is below.

Of course this doesn't get the raw values before they are number crunched by the system, but gives some headway into possible alternatives.

Code:
local orig = true

function onStatsChange(cid, attacker, type, combat, value)
     if type == STATSCHANGE_HEALTHLOSS then
         if orig then
             local value = value * 0.95
             orig = nil  
             doTargetCombatHealth(attacker, cid, combat, -value, -value, CONST_ME_NONE)
             return false
         else
             orig = true
             return true
         end
     end
     return true
end
 
Status
Not open for further replies.
Back
Top