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

C++ Skill training depended on attack speed

GhostWD

I'm in love with the var_dump()
Joined
Jan 25, 2009
Messages
185
Solutions
6
Reaction score
29
Hi Otlanders! i have request to You. I would like to have script, which will make dependence with skilling and attack speed i mean
if player attacks 2 times / sec it's skill would grow same as 1 time / sec, 3t/s same as 1t/s ....etc etc etc


TFS 0.4.3777


Can someone help me with that? Thank You!

*BUMP* really need that :C
 
Last edited by a moderator:
Solution
Well lets test if we can make skilltraining constant between attack speed regardless of multipliers:

Set rate to 10 and:

Replace:
C++:
    std::stringstream s;
    s.str("");
    s << "Skill gain: " << count << " speed: " << getAttackSpeed();
    s << ".";
    sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)

With this:
C++:
    std::stringstream s;
    count = uint32_t((double)count * ((double)getAttackSpeed() / (double)1000));
    s.str("");
    s << "Skill gain: " << count << " speed: " << getAttackSpeed();
    s << ".";
    sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)
Do you have an online repository (like a github link) to the source code?
 
Lets have a look into the source code.

It starts in weapons.cpp:
TFS-0.4-DEV/weapons.cpp at master · laerciosant/TFS-0.4-DEV · GitHub
When you use a weapon:
C++:
void Weapon::onUsedWeapon(Player* player, Item* item, Tile*) const
{
    if(!player->hasFlag(PlayerFlag_NotGainSkill))
    {
        skills_t skillType;
        uint32_t skillPoint = 0;
        if(getSkillType(player, item, skillType, skillPoint))
            player->addSkillAdvance(skillType, skillPoint);
    }
    // removed irelevant code ...
}

What I found odd is that skillPoint is set to 0...

lets check that getSkillType since its weird.
TFS-0.4-DEV/weapons.cpp at master · laerciosant/TFS-0.4-DEV · GitHub
C++:
bool WeaponMelee::getSkillType(const Player* player, const Item* item,
    skills_t& skill, uint32_t& skillpoint) const
{
    skillpoint = 0;
    if(player->getAddAttackSkill())
    {
        switch(player->getLastAttackBlockType())
        {
            case BLOCK_ARMOR:
            case BLOCK_NONE:
                skillpoint = 1; // overwrites skillPoint in Weapon::onUsedWeapon
                break;

            case BLOCK_DEFENSE:
            default:
                skillpoint = 0;
                break;
        }
    }

    switch(item->getWeaponType())
    {
        case WEAPON_SWORD:
        {
            skill = SKILL_SWORD; // Overwrites skillType in Weapon::onUsedWeapon
            return true;
        }
        // repeat for every other weapon type
        // overwrites the skillType value which was passed to this function to represent skill_type instead of weapon_type.
        // returns true means the condition this function was called in will succeed toward skill gaining
    }

    return false;
}
These params are a bit special, I guess this is the deal with C++ and pointers and references and stuff. Basically this function overwrites the value of skillPoint and skillType (which was defined but not given a value) in the previous function Weapon:: onUsedWeapon

So now that those variables are set, we head on to the addSkillAdvance function:
player.cpp:
TFS-0.4-DEV/player.cpp at master · laerciosant/TFS-0.4-DEV · GitHub
C++:
void Player::addSkillAdvance(skills_t skill, uint32_t count, bool useMultiplier/* = true*/)
{
    if(!count)
        return;

    //player has reached max skill
    uint32_t currReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL]),
        nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1);
    if(currReqTries > nextReqTries)
        return;

    if(useMultiplier)
        count = uint32_t((double)count * rates[skill] * g_config.getDouble(ConfigManager::RATE_SKILL));

    std::stringstream s;
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)
    {
        count -= nextReqTries - skills[skill][SKILL_TRIES];
        skills[skill][SKILL_TRIES] = skills[skill][SKILL_PERCENT] = 0;
        skills[skill][SKILL_LEVEL]++;

        s.str("");
        s << "You advanced in " << getSkillName(skill);
        if(g_config.getBool(ConfigManager::ADVANCING_SKILL_LEVEL))
            s << " [" << skills[skill][SKILL_LEVEL] << "]";

        s << ".";
        sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());

        CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE);
        for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it)
            (*it)->executeAdvance(this, skill, (skills[skill][SKILL_LEVEL] - 1), skills[skill][SKILL_LEVEL]);

        currReqTries = nextReqTries;
        nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1);
        if(currReqTries > nextReqTries)
        {
            count = 0;
            break;
        }
    }

    if(count)
        skills[skill][SKILL_TRIES] += count;

    //update percent
    uint32_t newPercent = Player::getPercentLevel(skills[skill][SKILL_TRIES], nextReqTries);
    if(skills[skill][SKILL_PERCENT] != newPercent)
    {
        skills[skill][SKILL_PERCENT] = newPercent;
        sendSkills();
    }
    else if(!s.str().empty())
        sendSkills();
}

This is were things seems a bit confusing to me.
As far as I understand it:

Your total skilltry/progress:
skills[skill][SKILL_TRIES]

Your skill_tries incremental value progress from your recent attack, this is being manipulated from earlier defined 1, to something else based on vocations.xml skill rate * config.lua rate_skill:
count

The skill_tries total goal you need to overcome in order to advance in skill level:
nextReqTries

But why is there a while loop here?

Anyway, what we need to adjust is probably the count variable below the useMultiplier addition and before the while statement.
I'm not sure what is the best approach, perhaps fetch the weapon speed (Player::getAttackSpeed() ? ).
 
Last edited:
I don't know what to say o_O I have found those functions before but i don't know how to bite it, how to arrange equation to make it work but i only know that i need it XD cause i have done "skill stage" in vocation.xml which could be solution but if players go to voce with lower attack speed from higher when they aproach 99% of skill something goes wrong and they get more then 1 skill points so this attempt fails ;/. Thank You for Reply Znote!
 
Replace these lines:
TFS-0.4-DEV/player.cpp at master · laerciosant/TFS-0.4-DEV · GitHub
C++:
    std::stringstream s;
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)

With this:
C++:
    std::stringstream s;
    s.str("");
    s << "Skill gain: " << count << " speed: " << getAttackSpeed();
    s << ".";
    sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)
And recompile and test it.

And go around with the different weapons and attack creatures (with a player that can gain skills). Look at the speed value and count value. Let me know what those are for your quickest weapon, normal weapon and slowest weapon.
 
without "skill stage"
12:49 Skill gain: 2 speed: 1400.
12:49 Skill gain: 2 speed: 700.
12:50 Skill gain: 2 speed: 600.
12:50 Skill gain: 2 speed: 500.
12:50 Skill gain: 2 speed: 400.
12:51 Skill gain: 2 speed: 300.

with "skill stage" idk why count dont changes but it's going slower while attack speed increases
12:55 Skill gain: 2 speed: 1100.
12:56 Skill gain: 2 speed: 600.
12:57 Skill gain: 2 speed: 500.
12:57 Skill gain: 2 speed: 400.
12:57 Skill gain: 2 speed: 300.


without skill stage
Code:
<vocation id="1" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="1500" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.1" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="2" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="1000" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.2" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="3" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="800" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.2" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="4" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="700" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.3" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="5" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="600" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.3" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="6" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="500" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.4" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>
  
<vocation id="7" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="1" gainhpamount="150" gainmanaticks="1" gainmanaamount="250" manamultiplier="1.1" attackspeed="400" soulmax="100" gainsoulticks="60" fromvoc="1">
        <formula meleeDamage="1.0" distDamage="1.0" wandDamage="1.0" magDamage="0.4" magHealingDamage="1.0" defense="1.0" magDefense="1.0" armor="1.0"/>
        <skill fist="1.0" club="1.0" sword="1.0" axe="1.0" distance="1.0" shielding="1.0" fishing="1.0" experience="1.0"/>
    </vocation>

with skill stage
Code:
<vocation id="1" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="100" gainmanaticks="2" gainmanaamount="100" manamultiplier="1.1" attackspeed="1200" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="5" distDamage="5" wandDamage="1.0" magDamage="0.5" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.005" club="1.005" sword="1.005" axe="1.005" distance="1.005" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="2" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="150" gainmanaticks="2" gainmanaamount="150" manamultiplier="1.1" attackspeed="900" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="7" distDamage="9" wandDamage="1.0" magDamage="1" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.01" club="1.01" sword="1.01" axe="1.01" distance="1.01" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="3" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="200" gainmanaticks="2" gainmanaamount="200" manamultiplier="1.1" attackspeed="700" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="10" distDamage="13" wandDamage="1.0" magDamage="1.5" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.02" club="1.02" sword="1.02" axe="1.02" distance="1.02" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="4" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="250" gainmanaticks="2" gainmanaamount="250" manamultiplier="1.1" attackspeed="600" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="20" distDamage="17" wandDamage="1.0" magDamage="2" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.025" club="1.025" sword="1.025" axe="1.025" distance="1.025" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="5" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="300" gainmanaticks="2" gainmanaamount="300" manamultiplier="1.1" attackspeed="500" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="30" distDamage="21" wandDamage="1.0" magDamage="2.5" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.03" club="1.03" sword="1.03" axe="1.03" distance="1.03" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="6" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="350" gainmanaticks="2" gainmanaamount="350" manamultiplier="1.1" attackspeed="500" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="40" distDamage="25" wandDamage="1.0" magDamage="3" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.03" club="1.03" sword="1.03" axe="1.03" distance="1.03" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>

<vocation id="7" name="Goku" description="a Goku" needpremium="0" gaincap="20" gainhp="170" gainmana="130" gainhpticks="2" gainhpamount="400" gainmanaticks="2" gainmanaamount="400" manamultiplier="1.1" attackspeed="400" soulmax="200" gainsoulticks="120" fromvoc="1">
                <formula meleeDamage="45" distDamage="29" wandDamage="1.0" magDamage="3.5" magHealingDamage="1.0" defense="1" magDefense="1" armor="1.0"/>
                <skill fist="1.035" club="1.035" sword="1.035" axe="1.035" distance="1.035" shielding="1.5" fishing="1.1" experience="1.0"/>
          </vocation>


@edit oh and speed mismatches because i have skill attack speed which decrease it by 100ms
 
Replace this line:
TFS-0.4-DEV/weapons.cpp at master · laerciosant/TFS-0.4-DEV · GitHub

With this:
C++:
player->addSkillAdvance(skillType, skillPoint, true);
See if that fixes the count value. (It should preferably be something higher so we can make it a formula/algorythm with the speed).

Does the speed mismatch in-game? One would think of your skill which decrease attack speed by 100 would be accounted for in player->getAttackSpeed().
 
no no speed in game is ok but i was explaining why it prints 1100 not 1200 ;P

changed rates to 1000 and nothing ;/

15:19 Skill gain: 1000 speed: 1100.
15:20 Skill gain: 1000 speed: 600.
15:21 Skill gain: 1000 speed: 400.
15:21 Skill gain: 1000 speed: 300.

skil stage is in vocation and attack speed depend on vocation
 
Well lets test if we can make skilltraining constant between attack speed regardless of multipliers:

Set rate to 10 and:

Replace:
C++:
    std::stringstream s;
    s.str("");
    s << "Skill gain: " << count << " speed: " << getAttackSpeed();
    s << ".";
    sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)

With this:
C++:
    std::stringstream s;
    count = uint32_t((double)count * ((double)getAttackSpeed() / (double)1000));
    s.str("");
    s << "Skill gain: " << count << " speed: " << getAttackSpeed();
    s << ".";
    sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str());
    while(skills[skill][SKILL_TRIES] + count >= nextReqTries)
 
Solution
17:49 Skill gain: 7 speed: 700.
17:49 Skill gain: 6 speed: 600.
17:49 Skill gain: 5 speed: 500.
17:49 Skill gain: 4 speed: 400.
17:49 Skill gain: 3 speed: 300.

Yea! You've got it :D
but now percent of skill constantly going up skillGain x 2 is it ok? :p
 
17:49 Skill gain: 7 speed: 700.
17:49 Skill gain: 6 speed: 600.
17:49 Skill gain: 5 speed: 500.
17:49 Skill gain: 4 speed: 400.
17:49 Skill gain: 3 speed: 300.

Yea! You've got it :D
but now percent of skill constantly going up skillGain x 2 is it ok? :p

Percent of skill going up skiiGain x2? Why do you think that/where do you see that?
 
in client, when i train skill. before hit it's 48% after 20% at 1400speed before 20% after 16% at 300ms speed even if skill is higher
 
in client, when i train skill. before hit it's 48% after 20% at 1400speed before 20% after 16% at 300ms speed even if skill is higher
The problem with too low skillgain is that you can only add whole numbers to the skilltries pool. So if you had skillrate at 5 instead of 10, and you attack with a 300ms weapon, you should get 1,5. But this will round to nearest whole number, so you are either getting 33% less skills (1), or 33% more skills (2) than what you should have.

With rateskill at 10, each of your attack speed compensate in skilltry count, so the sum should be the same over time.

To compensate quick skill gaining with skillrate = 10, I would increase the skilltry table by 5. Essentially simulating skillrate = 2, but using skillrate = 10, and perfect scaling between attack speeds.
 
Last edited:
oh my bad i haven't knew that multiplier in vocation.xml belongs to Required Tries and i used 1.0 for this skill :p now i understand why it was going wrong haha :D (my skill stage xd) Thank You VERY MUCH Znote !! And HAND


*WHY*
when you use vocation.xml skill multiplier to compensate attack skill it affects required tries to next skill level not gain per hit so when you have multiplier like 1.2 its take xxx tries when 1.0 yyy tries, yyy is lower so when you will build up skill to 99% at 1.2 and change to voce with 1.0 then you gain this difference(and more than one skill level)
 
Last edited:
oh my bad i haven't knew that multiplier in vocation.xml belongs to Required Tries and i used 1.0 for this skill :p now i understand why it was going wrong haha :D (my skill stage xd) Thank You VERY MUCH Znote !! And HAND


*WHY*
when you use vocation.xml skill multiplier to compensate attack skill it affects required tries to next skill level not gain per hit so when you have multiplier like 1.2 its take xxx tries when 1.0 yyy tries, yyy is lower so when you will build up skill to 99% at 1.2 and change to voce with 1.0 then you gain this difference(and more than one skill level)

It kindof makes sence, the math calculations will be easier for the server, so less cpu usage than to use high skillcounts++, and you don't need to use (double) type values (like 1.5), you can use whole numbers.
There are some servers that have done something similar with experience rate. Instead of making 10x exp rate, they set 1x exp rate and reduce exp table by / 10. Less calculations for high levels = less cpu usage = more players online without lags.
 
Back
Top