• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Serious Player To Player Damage Problem

Stanos

Veteran OT User
Joined
Jun 12, 2018
Messages
634
Solutions
7
Reaction score
372
Location
Europe
TFS 1.2 8.60
[8.60] The Forgotten Server 1.2

Problem: I deal to monster around 20k, but to player i deal only 500 even when multiplier is 2.6
damage.primary.value /= 2.6;
So from 20k i should hit around 7-8k which is what i want

Tried:
1. Printing damage.primary.value result was 500dmg and 2000dmg(again i dont know why it printed 2000 when i saw only 500)
2. Printed damage to monster result was 20k and 2k(dunno from where it was 2k again, because in game i only saw ~20k)

My idea is that it has multiple pvp multipliers which works like this,so from 20k it multiplies to 2000 and then void Combat::CombatHealthFunc multiplies it to 500 which makes sense because 2000/2.6 its around 700 but i had two items so it decreased to 500 But .

C++:
void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{
    assert(data);
    CombatDamage damage = *data;
    if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
        return;
    }

    if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
        Player* targetPlayer = target->getPlayer();
        if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
       switch (damage.primary.type) {
        case COMBAT_ENERGYDAMAGE: {
            damage.primary.value /= (float)2.5f;
            break;
        }
       
        case COMBAT_PHYSICALDAMAGE: {
            damage.primary.value /= (float)2.6f;
            break;
        }       

        default: {
            damage.primary.value /= 2;
            break;
        }
    }


       switch (damage.secondary.type) {
        case COMBAT_ENERGYDAMAGE: {
            damage.secondary.value /= (float)2.5f;
            break;
        }
       
        case COMBAT_PHYSICALDAMAGE: {
            damage.secondary.value /= (float)2.6f;
            break;
        }       

        default: {
            damage.secondary.value /= 2;
            break;
        }
    }   
    }
    }


    if (g_game.combatChangeHealth(caster, target, damage)) {
        CombatConditionFunc(caster, target, params, nullptr);
        CombatDispelFunc(caster, target, params, nullptr);
    }
}
 
Solution
Tested it and like i said
To puppet

01:09 A Punching Bag loses 2000 hitpoints due to your attack.
To player
01:10 Puppet loses 650 hitpoints due to your attack.

"You will hit monster for 1000... 100%! And if you hit now dummy player by other values that this 1000 then you can search for others multipliers..."
This is what we are talking about where is that another multiplier thats the whole question of this thread.
But now you see values for SEARCH! 200% and 65%! If you use Notepad++ now you can use "search in files" and search first in "src" folder then in "data" folder for multipliers
For Monster you have double damage so "2" or "2.0" for player you got 65% then "0.65" or "-0.35".
Now u get for what you need tests? To FIND SOLVE.
Yes i have transform.lua which is pretty much empty
XML:
    <event type="healthchange" name="TransformSystem" script="transform.lua" />

LUA:
function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    return transformHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
end
 
it's not empty, it just calls a separate function part of another system which deals with it which might be the reason why you're doing no damage
what does transformHealthChange do?
can you post its definition? search your files for it
 
it's not empty, it just calls a separate function part of another system which deals with it which might be the reason why you're doing no damage
what does transformHealthChange do?
can you post its definition? search your files for it
 
Last edited:
Tried ignoring/blocking that creaturevent so it doesnt effect anything in pvp, so problem is somewhere else.
 
swap your function back to this to ensure that it's your edited code's issue
i added a print to see when it gets called, keep track of how many times it gets called when you hit a player and let me know
C++:
void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{
    std::cout << "Combat::CombatHealthFunc called.\n";
    assert(data);
    CombatDamage damage = *data;
    if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
        return;
    }

    if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
        Player* targetPlayer = target->getPlayer();
        if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
            damage.primary.value /= 2;
            damage.secondary.value /= 2;
        }
    }

    if (g_game.combatChangeHealth(caster, target, damage)) {
        CombatConditionFunc(caster, target, params, nullptr);
        CombatDispelFunc(caster, target, params, nullptr);
    }
}
 
swap your function back to this to ensure that it's your edited code's issue
i added a print to see when it gets called, keep track of how many times it gets called when you hit a player and let me know
C++:
void Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data)
{
    std::cout << "Combat::CombatHealthFunc called.\n";
    assert(data);
    CombatDamage damage = *data;
    if (g_game.combatBlockHit(damage, caster, target, params.blockedByShield, params.blockedByArmor, params.itemId != 0)) {
        return;
    }

    if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
        Player* targetPlayer = target->getPlayer();
        if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
            damage.primary.value /= 2;
            damage.secondary.value /= 2;
        }
    }

    if (g_game.combatChangeHealth(caster, target, damage)) {
        CombatConditionFunc(caster, target, params, nullptr);
        CombatDispelFunc(caster, target, params, nullptr);
    }
}
It calls once per hit
 
In my experience.
1. Prepare Training Dummy monster with tons of HP.
2. To make any tests of damage, make 2 characters with 100k HP~ without any item wearing,
3. Prepare spell that cause 1k damage, no more no less.
4. Change this values to /= 1;
5. Test damage on monster and player, if its different, there are more moddifier or edited stuff(For me was only this)
6. This work also on "Normal Attack" soo you need to change weapon formula if you want increase divide number otherwise you will hit with normal attack around "nothing" xD
 
In my experience.
1. Prepare Training Dummy monster with tons of HP.
2. To make any tests of damage, make 2 characters with 100k HP~ without any item wearing,
3. Prepare spell that cause 1k damage, no more no less.
4. Change this values to /= 1;
5. Test damage on monster and player, if its different, there are more moddifier or edited stuff(For me was only this)
6. This work also on "Normal Attack" soo you need to change weapon formula if you want increase divide number otherwise you will hit with normal attack around "nothing" xD
Still multiplies when its /= 1; but now i hit about 3-4k from melee tho :D so its to obvious that there is another moddifier which effects player to player dmg
 
Still multiplies when its /= 1; but now i hit about 3-4k from melee tho :D so its to obvious that there is another moddifier which effects player to player dmg
Did you prepare environment for tests like i said? Cause you talk about 3k-4k hits soo i think, no you dont.
Preparing "clear" environment is a fundamental for make changes, testing and modiffy all other stuff.
Make spell thats deal 1000 damage no more no less!! Without level, skill or magic scaling, without block by armor or defense! Disable all armors, immunities, resist on tested monster!... Just disable all possible modiffiers and test "clean" damage on monster and player.
Check vocation.xml for damage reductions!

AND! Do not touch anything more than this "/= 1;"

I got 1.2 and i just change this and work perfect for me.

Code:
    if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
        Player* targetPlayer = target->getPlayer();
        if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
            damage.primary.value /= 1;
            damage.secondary.value /= 1;
        }
    }
Ofcourse u must change BOTH!
 
Last edited:
Did you prepare environment for tests like i said? Cause you talk about 3k-4k hits soo i think, no you dont.
Preparing "clear" environment is a fundamental for make changes, testing and modiffy all other stuff.
Make spell thats deal 1000 damage no more no less!! Without level, skill or magic scaling, without block by armor or defense! Disable all armors, immunities, resist on tested monster!... Just disable all possible modiffiers and test "clean" damage on monster and player.
Check vocation.xml for damage reductions!

AND! Do not touch anything more than this "/= 1;"

I got 1.2 and i just change this and work perfect for me.

Code:
    if ((damage.primary.value < 0 || damage.secondary.value < 0) && caster) {
        Player* targetPlayer = target->getPlayer();
        if (targetPlayer && caster->getPlayer() && targetPlayer->getSkull() != SKULL_BLACK) {
            damage.primary.value /= 1;
            damage.secondary.value /= 1;
        }
    }
Ofcourse u must change BOTH!
So isn't it obvious then? You said with default tfs everything works so it means i have another moddifier. It will cause to make huge changes to make it hit only 1k because there <formula meleeDamage="1.0" in voc.xml, then i have transform.lua which increase melee/energy im not even talking about weapons.cpp so i dont think we need to test it when its to obvious that there is another moddifier, when if i test and we will be 200% sure it will not help us to find it where its made.
 
So isn't it obvious then? You said with default tfs everything works so it means i have another moddifier. It will cause to make huge changes to make it hit only 1k because there <formula meleeDamage="1.0" in voc.xml, then i have transform.lua which increase melee/energy im not even talking about weapons.cpp so i dont think we need to test it when its to obvious that there is another moddifier, when if i test and we will be 200% sure it will not help us to find it where its made.
I think you do not understand what i say.

Here is spell script for test:
LUA:
local combat = createCombatObject()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE)
combat:setParameter(COMBAT_PARAM_DISTANCEEFFECT, 25)

function onGetFormulaValues(player, skill, attack, factor)
    local min = 1000
    local max = 1000
    return -min, -max
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onCastSpell(cid, var)
return combat:execute(cid, var)
end
Here is monster for test:
Code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<monster name="Training Dummy" nameDescription="Training Dummy" race="undead" speed ="0" experience="0">
    <health now="100000000" max="100000000" />
    <look type="540"/>
    <targetchange interval="4000" chance="0" />
    <flags>
        <flag summonable="0" />
        <flag attackable="1" />
        <flag hostile="1" />
        <flag illusionable="1" />
        <flag convinceable="0" />
        <flag pushable="1" />
        <flag canpushitems="0" />
        <flag canpushcreatures="0" />
        <flag targetdistance="1" />
        <flag staticattack="90" />
        <flag runonhealth="0" />
    </flags>
    <attacks>
     </attacks>
    <defenses armor="0" defense="0">
    </defenses>
    <elements>
    </elements>
    <immunities>
    </immunities>
    <loot>
    </loot>
</monster>

Now change
Code:
/= 2.6
to
Code:
/= 1

Next, create "Dummy" character on your server. Clean one! And just change his HP to 50k
Dont wear anything on it, he must be clean, without any bonuses from items or your "custom events"

If you use OTClient, then launch it twice, login on Dummy Character and on second character thats will be casting prepared spell...

Now You should HIT MONSTER AND DUMMY PLAYER by this spell for 1000!
You will hit monster for 1000... 100%! And if you hit now dummy player by other values that this 1000 then you can search for others multipliers...


so i dont think we need to test it when its to obvious that there is another moddifier
Dont write again something like this, testings and trying to understand is fundamental of creating!
 
Back
Top