• 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!

onBlock/blockHit function?

Lubinho Fit

Member
Joined
May 10, 2017
Messages
37
Reaction score
8
I don't really now scripting but i wanted to know if it is possible to get something like this
If a player has a shield and successfully blocked an attack do X

And if it is please teach me how to do it or just make an example, im trying to learn .lua and understand c++
 
I think it can be done with Lua
register onHealthChange() creaturecript on a player.
in this function get player shield.
if he has one, get shield defence
then do your algorithm on the damage passed by function.
if damage goes 0 or below (or 0 and above, in default TFS negaitve value healed i think xD)
anyway if get that far with statements this is the kind of "block" you waned to achieve.
There you can write as many triggers you want.
 
I think it can be done with Lua
register onHealthChange() creaturecript on a player.
in this function get player shield.
if he has one, get shield defence
then do your algorithm on the damage passed by function.
if damage goes 0 or below (or 0 and above, in default TFS negaitve value healed i think xD)
anyway if get that far with statements this is the kind of "block" you waned to achieve.
There you can write as many triggers you want.

I'm not sure this will work, as you can see yourself, it's onHealthChange(), shield block will not change player's health. I am checking it now in source just to be 100% sure.

Confirmed. To execute onHealthChange monster must deal damage to you :)

As a hint: check combat.cpp Combat::CombatHealthFunc. It seems to be dealing with blocking. and Game::combatBlockHit in which you should find out when it's shield that blocked the hit.

Then you will need to introduce a new event type, called for example onShieldBlock and go from there.
 
Last edited:
Guys i tried to understand the source code hint that @Ziker posted, and i found this

C++:
bool Game::combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, bool field)
{
    if (damage.primary.type == COMBAT_NONE && damage.secondary.type == COMBAT_NONE) {
        return true;
    }

    if (target->getPlayer() && target->isInGhostMode()) {
        return true;
    }

    if (damage.primary.value > 0) {
        return false;
    }

Why @Ziker do u think @whitevo solutions can't work?
I can't test it right now because im not home
 
I'm not sure this will work, as you can see yourself, it's onHealthChange(), shield block will not change player's health. I am checking it now in source just to be 100% sure.

Confirmed. To execute onHealthChange monster must deal damage to you :)
if monster deals 0 damage in first place, can be considered a block or just a bugged monster? xD
Idk none of my monsters deal 0 damage. (ye they can end up doing no damage, but the combat starts with some kind of damage)
But then again my source doesn't do armor nor defence calculations instead I do it with Lua functions.

This is the main damage event on all players and monsters, all the function names might not represent them well, because that function is like year old, but trough here goes all my damage stuff. Including block hits and their triggers.
Lua:
function damageSystem_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() then
        if creature:isFakeDead() then return 0 end
        if getSV(creature, SV.player_ignoreDamage) == 1 then return 0 end
        if getSV(creature, SV.playerIsDead) == 1 then return 0 end
        setSV(creature, SV.lastDmg, os.time())
    end
  
    if creature:getCondition(INVISIBLE, 1) then return 0 end
    if attacker and attacker:isPlayer() then setSV(attacker, SV.lastHit, os.time()) end
    primaryDamage = tauntCreatures(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = bufferMonsters(creature, attacker, primaryDamage, primaryType, origin)
  
    primaryDamage = baseDamage(creature, attacker, primaryDamage, secondaryDamage, primaryType, origin)
    primaryDamage = damageModifers1(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = playerResistance(creature, attacker, primaryDamage, primaryType)
  
    primaryDamage = damageModifers2(creature, attacker, primaryDamage, primaryType)
    primaryDamage = playerArmor(creature, attacker, primaryDamage, primaryType)
    primaryDamage = damageModifers3(creature, attacker, primaryDamage, primaryType)
  
    primaryDamage = playerDefence(creature, attacker, primaryDamage, primaryType)
    primaryDamage = damageModifers4(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = finalDamage(creature, attacker, primaryDamage, primaryType)
  
    if primaryDamage == 0 and antiSpam(creature:getId(), 20) then creature:getPosition():sendMagicEffect(4) end
    return primaryDamage, primaryType
end
 
if monster deals 0 damage in first place, can be considered a block or just a bugged monster? xD
Idk none of my monsters deal 0 damage. (ye they can end up doing no damage, but the combat starts with some kind of damage)
But then again my source doesn't do armor nor defence calculations instead I do it with Lua functions.

This is the main damage event on all players and monsters, all the function names might not represent them well, because that function is like year old, but trough here goes all my damage stuff. Including block hits and their triggers.
Lua:
function damageSystem_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if creature:isPlayer() then
        if creature:isFakeDead() then return 0 end
        if getSV(creature, SV.player_ignoreDamage) == 1 then return 0 end
        if getSV(creature, SV.playerIsDead) == 1 then return 0 end
        setSV(creature, SV.lastDmg, os.time())
    end
 
    if creature:getCondition(INVISIBLE, 1) then return 0 end
    if attacker and attacker:isPlayer() then setSV(attacker, SV.lastHit, os.time()) end
    primaryDamage = tauntCreatures(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = bufferMonsters(creature, attacker, primaryDamage, primaryType, origin)
 
    primaryDamage = baseDamage(creature, attacker, primaryDamage, secondaryDamage, primaryType, origin)
    primaryDamage = damageModifers1(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = playerResistance(creature, attacker, primaryDamage, primaryType)
 
    primaryDamage = damageModifers2(creature, attacker, primaryDamage, primaryType)
    primaryDamage = playerArmor(creature, attacker, primaryDamage, primaryType)
    primaryDamage = damageModifers3(creature, attacker, primaryDamage, primaryType)
 
    primaryDamage = playerDefence(creature, attacker, primaryDamage, primaryType)
    primaryDamage = damageModifers4(creature, attacker, primaryDamage, primaryType, origin)
    primaryDamage = finalDamage(creature, attacker, primaryDamage, primaryType)
 
    if primaryDamage == 0 and antiSpam(creature:getId(), 20) then creature:getPosition():sendMagicEffect(4) end
    return primaryDamage, primaryType
end

Well, if monster deal no damage, it is either because it was blocked by armor or shield of the player (or other custom stuff, like resistance). And at least in TFS 1.2+ this is done BEFORE dealing any damage and if the block is successful (either by armor or shield), the function returns - no onHealthChange event is executed (because no health was changed). So assuming he uses TFS 1.2+ (I suppose TFS 1.x), then onHealthChange will not work. Looking at your script I guess your blocks / all conditions were moved to lua, so the onHealthChange will be called, because you happen to execute the block / other stuff in lua and modify damage there.

I base my answers here on TFS master branch, since he didn't tell anything about his server distribution.
 
Well, if monster deal no damage, it is either because it was blocked by armor or shield of the player (or other custom stuff, like resistance). And at least in TFS 1.2+ this is done BEFORE dealing any damage and if the block is successful (either by armor or shield), the function returns - no onHealthChange event is executed (because no health was changed). So assuming he uses TFS 1.2+ (I suppose TFS 1.x), then onHealthChange will not work. Looking at your script I guess your blocks / all conditions were moved to lua, so the onHealthChange will be called, because you happen to execute the block / other stuff in lua and modify damage there.

I base my answers here on TFS master branch, since he didn't tell anything about his server distribution.
I got default TFS 1.3 combat.cpp

You confirmed what? That monster needs to deal more than 0 damage? well DUH!!
Or the fact that if you deal 1 damage with Combat constructor and you have more than 2 armor onHealthChange creatureScript wont trigger?

If the confirmation was for the second one then, maybe the reason my monsters never do 0 damage is because of this?
doTargetCombatHealth(attacker, target, type, min, max, effect, origin)
This the only end result function I use (I don't use Combat() constructor)

Try it in your sever, if you pass 1 physical damage and you have like 10+ armor, does your onHealthChance creaturescript trigger and does primaryDamage pass 1 damage?

If yes then we just found the thing what needs to be done to make block hit work only with Lua.
If no then, well I got way too many Lua changes in data folder, so I guess its not worth to make such a feature in Lua unless you willing to spend lot of time.
 
I got default TFS 1.3 combat.cpp

You confirmed what? That monster needs to deal more than 0 damage? well DUH!!
Or the fact that if you deal 1 damage with Combat constructor and you have more than 2 armor onHealthChange creatureScript wont trigger?

If the confirmation was for the second one then, maybe the reason my monsters never do 0 damage is because of this?
doTargetCombatHealth(attacker, target, type, min, max, effect, origin)
This the only end result function I use (I don't use Combat() constructor)

Try it in your sever, if you pass 1 physical damage and you have like 10+ armor, does your onHealthChance creaturescript trigger and does primaryDamage pass 1 damage?

If yes then we just found the thing what needs to be done to make block hit work only with Lua.
If no then, well I got way too many Lua changes in data folder, so I guess its not worth to make such a feature in Lua unless you willing to spend lot of time.
To be honest I don't really understand what you're trying to tell me here. Do you mean that, assuming we use clean TFS (master branch) copy, if player blocks an attack (resulting damage is 0), it will still execute onHealthChange? I see you use some sort of custom "damage system", so I can't really tell what's happening behind your damageSystem_onHealthChange.
 
To be honest I don't really understand what you're trying to tell me here. Do you mean that, assuming we use clean TFS (master branch) copy, if player blocks an attack (resulting damage is 0), it will still execute onHealthChange? I see you use some sort of custom "damage system", so I can't really tell what's happening behind your damageSystem_onHealthChange.

nothing is happening there, hence I didn't post it.

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
return damageSystem_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
end
To be honest I don't really understand what you're trying to tell me here.
I just asked you what did you confirm and asked you to do 1 more test if the confirmation you made before was legit.
 
nothing is happening there, hence I didn't post it.

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
return damageSystem_onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
end

I just asked you what did you confirm and asked you to do 1 more test if the confirmation you made before was legit.

Oh, I see. Well, I don't "test", since I don't have Tibia client and can't really bother to save it. I did analyze the code though:

Here is onHealthChange (this is where TFS executes lua onHealthChange handler):
forgottenserver/creatureevent.cpp at b79d74fda22e61720818a8f1ceb9acb69103b04f · otland/forgottenserver · GitHub

If you look for uses, you will find:
forgottenserver/game.cpp at b79d74fda22e61720818a8f1ceb9acb69103b04f · otland/forgottenserver · GitHub

Look for uses of that method and you get:
forgottenserver/combat.cpp at 09a94f2870af8ecb39696bdc7b631b3e6fc9a59c · otland/forgottenserver · GitHub
forgottenserver/condition.cpp at cc8e15e9166359faa52d38823e679355a615ab23 · otland/forgottenserver · GitHub
( + creature::addHealth() )
Now if you go through these methods you will notice that there's a block check there before any execution of Game::combatChangeHealth. So unless you use
creature:addHealth (the only one that does not do the check, why would it?) from lua to deal damage this way, if player blocks the attack with armor / shield / anything else you put there, the onHealthChange event should not be executed. But obviously, this is only code analysis, so I must have missed / misread something if onHealthChange is still executed even when player blocked the attack completely.
 
ok guys a lot of complicated stuff i tried to understand but it's just too much
but i have been thinking if it was possible to do like this (just some examples like i said i don't know alot about coding, but i want to try to put my ideias to work)

if player IN_FIGHT and onHealthChange return false then . . . .

OR

if player shieldSkill goes up (successfully blocked) then . . . .

OR

if player getSkillShield > newSkillShield then {
trigger
trigger

newSkillShield = getSkillShield

}
 
ok guys a lot of complicated stuff i tried to understand but it's just too much
but i have been thinking if it was possible to do like this (just some examples like i said i don't know alot about coding, but i want to try to put my ideias to work)

if player IN_FIGHT and onHealthChange return false then . . . .

OR

if player shieldSkill goes up (successfully blocked) then . . . .

OR

if player getSkillShield > newSkillShield then {
trigger
trigger

newSkillShield = getSkillShield

}
Well, I see you keep thinking and this is great. The thing is onHealthChange does not get called until damage is dealt. As for skill advancement, the event is only called on skill level change (not on tries), so this would not work either. I think your best chance, if you can't code onBlock event yourself, would be to find someone who can. I can give it a try, but I can't promise you anything - neither that I will do it reasonably fast nor that I will have enough time to finish it at all.
 
Well, I see you keep thinking and this is great. The thing is onHealthChange does not get called until damage is dealt. As for skill advancement, the event is only called on skill level change (not on tries), so this would not work either. I think your best chance, if you can't code onBlock event yourself, would be to find someone who can. I can give it a try, but I can't promise you anything - neither that I will do it reasonably fast nor that I will have enough time to finish it at all.

@Ziker and @whitevo thanks for all the fast replys, do you have an example to add a new event? Like another thread that does this type of thing? And whatd does the skillTries do? isn't it supposed to slowly increase the players skill until a increment/level and why can't we use it? if you want to try to write the code i would be grateful, but i know that time nowadays is scarce then it's ok if you say no
 
Back
Top