• 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 critical hit network message in TFS 1.3?

whitevo

Feeling good, thats what I do.
Joined
Jan 2, 2015
Messages
3,452
Solutions
1
Reaction score
625
Location
Estonia
EDIT: I found out its not TFS 1.3 but instead a OTX server based on TFS 1.3

What does this do?
Can I make a network message with Lua to change critical chance value on the client?
If yes then how I go about it?
C++:
void ProtocolGameBase::AddPlayerSkills(NetworkMessage& msg)
{
msg.addByte(0xA1);

for (uint8_t i = SKILL_FIRST; i <= SKILL_FISHING; ++i) {
msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
msg.add<uint16_t>(player->getBaseSkill(i));
msg.addByte(player->getSkillPercent(i));
}

for (uint8_t i = SKILL_CRITICAL_HIT_CHANCE; i <= SKILL_LAST; ++i) {
msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
msg.add<uint16_t>(player->getBaseSkill(i));
}
}
 
Last edited:
Solution
Are you sure I don't need effective skill level? as the first U16 byte for each skill?
what client expects from you is: skill level (unsigned short), skill base level (unsigned short), and percent to go (unsigned byte), since new critcal system has no percentage then client skip this byte, i don't get what you mean with skill level, i'm assuming it's a typo from skill ID, no you don't need it, client assumes ID by the order of messages, eg: first 3 messages after 161 will fill fist fighting skill with these data, and so on, and yes it's an horroble design, but what we gonna do? just cipsoft things =)
What does the number 20 stand for starting from > send crit chance to send mana leech dmg
it means nothing, just filled...
No ide how this system works, but the chance has to be in the source code, then it sends a byte to the client telling it to show the effect.
If you are talking about the skills list, it's what you posted, just send a network message in Lua with what you have above, not sure how it's supposed to be but give it a try :p
 
No ide how this system works, but the chance has to be in the source code, then it sends a byte to the client telling it to show the effect.
If you are talking about the skills list, it's what you posted, just send a network message in Lua with what you have above, not sure how it's supposed to be but give it a try :p
My tries end up with client crash hence the post.
But yes I want change the crit values in skills list. Don't care if its only visual.
 
C++:
void ProtocolGame::AddPlayerSkills(NetworkMessage& msg)
{
   msg.AddByte(0xA1);

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_FIST, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_FIST));
   msg.AddByte(player->getSkill(SKILL_FIST, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_CLUB, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_CLUB));
   msg.AddByte(player->getSkill(SKILL_CLUB, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_SWORD, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_SWORD));
   msg.AddByte(player->getSkill(SKILL_SWORD, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_AXE, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_AXE));
   msg.AddByte(player->getSkill(SKILL_AXE, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_DISTANCE, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_DISTANCE));
   msg.AddByte(player->getSkill(SKILL_DISTANCE, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_SHIELD, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_SHIELD));
   msg.AddByte(player->getSkill(SKILL_SHIELD, SKILLVALUE_PERCENT));

   msg.add<uint16_t>(std::min<int32_t>(0xFFFF, player->getSkill(SKILL_FISHING, SKILLVALUE_LEVEL)));
   msg.add<uint16_t>(player->getBaseSkill(SKILL_FISHING));
   msg.AddByte(player->getSkill(SKILL_FISHING, SKILLVALUE_PERCENT));

   if (version >= 1094) {
       msg.add<uint32_t>(player->getVarStats(crit_chance));
       msg.add<uint32_t>(player->getVarStats(crit_dmg));
       msg.add<uint32_t>(player->getVarStats(hp_chance));
       msg.add<uint32_t>(player->getVarStats(hp_percent));
       msg.add<uint32_t>(player->getVarStats(mana_chance));
       msg.add<uint32_t>(player->getVarStats(mana_percent));
   }
}
 
C++:
void ProtocolGame::AddPlayerSkills(NetworkMessage& msg)
{
    msg.addByte(0xA1);

    for (uint8_t i = SKILL_FIRST; i <= SKILL_FISHING; ++i) {
        msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
        msg.add<uint16_t>(player->getBaseSkill(i));
        msg.addByte(player->getSkillPercent(i));
    }

    for (uint8_t i = SKILL_CRITICAL_HIT_CHANCE; i <= SKILL_LAST; ++i) {
        msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
        msg.add<uint16_t>(player->getBaseSkill(i));
    }
}
 
What are you guys even posting I don't understand?
Here is broken example what I was trying to do in order to add 2 crit chance% or make it 2%:

Lua:
function Player.addCritChance(player)
local networkMessage = NetworkMessage()

    networkMessage:addByte(0xA1)
    networkMessage:addU32(SKILL_CRITICAL_HIT_CHANCE)
    networkMessage:addU32(2)
    networkMessage:sendToPlayer(player)
    networkMessage:delete()
    return true
end
 
Here is broken example what I was trying to do in order to add 2 crit chance% or make it 2%:
you can do it, but you should follow client rules, it wants whole data when updating stats.
Lua:
local msg = NetworkMessage();
msg:addByte(161);

msg:addU16(player:getSkillLevel(0)); // send fist stats
msg:addU16(player:getSkillLevel(0));
msg:addByte(player:getSkillPercent(0));

msg:addU16(player:getSkillLevel(1)); // send club stats
msg:addU16(player:getSkillLevel(1));
msg:addByte(player:getSkillPercent(1));

msg:addU16(player:getSkillLevel(2)); // send sword stats
msg:addU16(player:getSkillLevel(2));
msg:addByte(player:getSkillPercent(2));

msg:addU16(player:getSkillLevel(3)); // send axe stats
msg:addU16(player:getSkillLevel(3));
msg:addByte(player:getSkillPercent(3));

msg:addU16(player:getSkillLevel(4)); // send dist stats
msg:addU16(player:getSkillLevel(4));
msg:addByte(player:getSkillPercent(4));

msg:addU16(player:getSkillLevel(5)); // send shield stats
msg:addU16(player:getSkillLevel(5));
msg:addByte(player:getSkillPercent(5));

msg:addU16(player:getSkillLevel(6)); // send fishing stats
msg:addU16(player:getSkillLevel(6));
msg:addByte(player:getSkillPercent(6));

msg:addU16(20); // send crit chance
msg:addU16(20);

msg:addU16(20); // // send crit dmg
msg:addU16(20); 

msg:addU16(20); // send life leech chance
msg:addU16(20);

msg:addU16(20); // send life leech dmg
msg:addU16(20); 

msg:addU16(20); // send mana leech chance
msg:addU16(20); 

msg:addU16(20); // send mana leech dmg
msg:addU16(20);
   
msg:sendToPlayer(player);
 
I will try this below code when I get a chance. (I don't have the build)
But I have few questions:
Are you sure I don't need effective skill level? as the first U16 byte for each skill?
What does the number 20 stand for starting from > send crit chance to send mana leech dmg
If I pass 0 for lets say send mana leech dmg, does it set mana leech to 0 or does nothing do it? (I haven't made get functions for custom stats yet, but I know how I can do it in Lua)

Lua:
function Player.setCritChance(player, amount)
local msg = NetworkMessage()

    msg:addByte(161) -- ::AddPlayerSkills byte
    -- Need to put all the skill informations
    -- registerMethod("Player", "getEffectiveSkillLevel", LuaScriptInterface::luaPlayerGetEffectiveSkillLevel);
    msg:addU16(player:getSkillLevel(SKILL_FIST)) -- Are you sure I dont need effective skill level?
    msg:addU16(player:getSkillLevel(SKILL_FIST))
    msg:addByte(player:getSkillPercent(SKILL_FIST))
 
    msg:addU16(player:getSkillLevel(SKILL_CLUB))
    msg:addU16(player:getSkillLevel(SKILL_CLUB))
    msg:addByte(player:getSkillPercent(SKILL_CLUB))
 
    msg:addU16(player:getSkillLevel(SKILL_SWORD))
    msg:addU16(player:getSkillLevel(SKILL_SWORD))
    msg:addByte(player:getSkillPercent(SKILL_SWORD))
 
    msg:addU16(player:getSkillLevel(SKILL_AXE))
    msg:addU16(player:getSkillLevel(SKILL_AXE))
    msg:addByte(player:getSkillPercent(SKILL_AXE))

    msg:addU16(player:getSkillLevel(SKILL_DISTANCE))
    msg:addU16(player:getSkillLevel(SKILL_DISTANCE))
    msg:addByte(player:getSkillPercent(SKILL_DISTANCE))
 
    msg:addU16(player:getSkillLevel(SKILL_SHIELD))
    msg:addU16(player:getSkillLevel(SKILL_SHIELD))
    msg:addByte(player:getSkillPercent(SKILL_SHIELD))
 
    msg:addU16(player:getSkillLevel(SKILL_FISHING))
    msg:addU16(player:getSkillLevel(SKILL_FISHING))
    msg:addByte(player:getSkillPercent(SKILL_FISHING))
 
    msg:addU16(amount) -- what doe 20 stand for you used in this?
    msg:addU16(amount)
 
    msg:addU16(0)   --send crit dmg
    msg:addU16(0)
 
    msg:addU16(0)   --send life leech chance
    msg:addU16(0)
 
    msg:addU16(0)   --send life leech dmg
    msg:addU16(0)
 
    msg:addU16(0)   --send mana leech chance
    msg:addU16(0)
 
    msg:addU16(0)   -- send mana leech dmg
    msg:addU16(0)
 
    msg:sendToPlayer(player)
end
 
Last edited:
Are you sure I don't need effective skill level? as the first U16 byte for each skill?
what client expects from you is: skill level (unsigned short), skill base level (unsigned short), and percent to go (unsigned byte), since new critcal system has no percentage then client skip this byte, i don't get what you mean with skill level, i'm assuming it's a typo from skill ID, no you don't need it, client assumes ID by the order of messages, eg: first 3 messages after 161 will fill fist fighting skill with these data, and so on, and yes it's an horroble design, but what we gonna do? just cipsoft things =)
What does the number 20 stand for starting from > send crit chance to send mana leech dmg
it means nothing, just filled to display 20% in client instead of 0% which is by default, it means in protocol as i said Skill level, then skill base level.
If I pass 0 for lets say send mana leech dmg, does it set mana leech to 0 or does nothing do it? (I haven't made get functions for custom stats yet, but I know how I can do it in Lua)
it is only a display for player, what player see in client should be synchronized with server by your system, eg: you sent 50% for client later on if you forget to update (send skill stats over again) client will still displaying 50% but in real server it has 0% and does nothing.
 
Solution
where i put it ?
I placed these functions in compat.
Know that you need to either use onThink() event to constantly check your skills and update them so it visually matches with server.
Or make skill updade on every possible event what can change your skills. But I believe this can be lot of work for default TFS to implement.
Generic events what usually change skills: moving equipment, leveling skills, spells, conditions, logging in
 
Back
Top