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

Feature Max Level + Passive Extra Damage after max level (for low-rates server)

drakylucas

Intermediate OT User
Joined
Dec 15, 2015
Messages
235
Solutions
7
Reaction score
121
Hello everyone.
I made this system based on a server that I've played called "Ruthless Chaos".

How does it works?
You will configure the maximum level (e.g. 300) and, after the player reachs the maximum level, every time that he advances again, he will return to the maximum level and the passive damage will be increased in 1%, but the exp-rate of that player will be reduced. The greater the passive damage, the lower the experience rate. (so it'll be very hard to reach high values).

It works on the lastest TFS (1.2, 1.3, etc) from the original fork on github.

Installation:

I'll do every step using the website "diff", so you can see what I've changed. I think this way is easier to you find the correct place to add these things.

Sources:
File: combat.cpp
place: CombatDamage Combat::getCombatDamage(Creature* creature, Creature* target) const
click here to see the difference

File: configmanager.cpp
place: bool ConfigManager::load()
click here to see the difference

File: configmanager.h
place: enum integer_config_t {
click here to see the difference


File: iologindata.cpp
place: bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
click here to see the difference

File: iologindata.cpp (same file)
place: bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
click here to see the difference

File: iologindata.cpp (same file)
place: bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
click here to see the difference

File: iologindata.cpp (same file)
place: bool IOLoginData::savePlayer(Player* player)
click here to see the difference

File: luascript.cpp
place: near all "registerEnumIn"
click here to see the difference

File: luascript.cpp (same file)
place: near all registerMethod
click here to see the difference

File: luascript.cpp (same file)
place: after the function int LuaScriptInterface::luaPlayerSetStamina(lua_State* L)
click here to see the difference

File: luascript.h
place: after static int luaPlayerSetStamina(lua_State* L);
click here to see the difference

File: player.cpp
place: std::string Player::getDescription(int32_t lookDistance) const
click here to see the difference

File: player.cpp (same file)
place: void Player::addExperience(Creature* source, uint64_t exp, bool sendText/* = false*/)
click here to see the difference

File: player.cpp (same file)
place: void Player::removeExperience(uint64_t exp, bool sendText/* = false*/)
click here to see the difference

File: player.cpp (same file)
place: void Player::death(Creature* lastHitCreature)
click here to see the difference

File: player.h
place: near uint8_t getMagicLevelPercent() const {
click here to see the difference

File: player.h
place: near uint8_t magLevelPercent = 0;
click here to see the difference

File: weapons.cpp
place: int32_t Weapons::getMaxWeaponDamage(uint32_t level, int32_t attackSkill, int32_t attackValue, float attackFactor)
click here to see the difference

File: weapons.cpp (same file)
place: bool Weapon::useFist(Player* player, Creature* target)
click here to see the difference

File: weapons.cpp (same file)
place: int32_t WeaponMelee::getElementDamage(const Player* player, const Creature*, const Item* item) const
click here to see the difference

File: weapons.cpp (same file)
place: int32_t WeaponMelee::getWeaponDamage(const Player* player, const Creature*, const Item* item, bool maxDamage /*= false*/) const
click here to see the difference

File: weapons.cpp (same file)
place: int32_t WeaponDistance::getElementDamage(const Player* player, const Creature* target, const Item* item) const --> note: method with the same name as above, but with an additional parameter "target"
click here to see the difference

File: weapons.cpp (same file)
place: int32_t WeaponDistance::getWeaponDamage(const Player* player, const Creature* target, const Item* item, bool maxDamage /*= false*/) const
click here to see the difference

File: weapons.h
place: static int32_t getMaxWeaponDamage(uint32_t level, int32_t attackSkill, int32_t attackValue, float attackFactor);
click here to see the difference

Server folder:
File: data/events/scripts/player.lua
place: function Player:eek:nGainExperience(source, exp, rawExp)
click here to see the difference
note: you can edit the formula here (or let it without change anything)
Lua:
exp = exp * (Game.getExperienceStage(self:getLevel()) / (self:getPassiveDamageBonus()+1))

File: config.lua
place: anywhere
click here to see the difference

Database:
(during the creation of the server, you can change this on the schemas.sql)
click here to see the difference

If the server already exists (but, the player levels aren't on the maximum level yet), you can use this sql command:
PHP:
alter table `players` add `passivedamagebonus` int(11) not null default 0 after `level`;
(or you can simply use any software to edit your database and add the "passivedamagebonus" as an integer after the level)


I think that's it.
If I forgot anything, please ask me and I'll fix ASAP.
If you implement this on your server, please let some screenshots in this topic aswell xD.

I'll try to post some screenshots soon.

I do not authorize anyone to share this in other forums. If you want to share, share the OTLand link, and not the content of the post.
 
Last edited by a moderator:
Duuude, this is awesome. Any reason it wouldn't work with OTX? (based on TFS) Either way, really incredible system and an amazing thing to share. I appreciate this.

Usually on my servers (they run for a long time and are NPVP) this is just the thing they are missing. One guy gets way out ahead of everyone and they're discouraged.

I know a lot of people will enjoy this. Thanks a million times over.
 
Hello guys, thanks for your feedback.
@Taurus
It should work in OTX too, but you should pay attention to its code too.
I didn't check the whole code of OTX, but if you want to try,you should pay attention in some parts like "iologindata", which there are some more fields on OTX than on TFS, so try to not replace the whole different code and be sure to only add the necessary code without removing anything. (the otx have some different things, like prey system, store system and imbuements, so you must pay attention in these things in the parts related to experience (like the Lua part)) .
 
pay attention to its code too.
For sure. I don't wanna be asking these same questions in 5 years haha.

I really appreciate this. We've needed this for a long time in Open Tibia. They should include this in TFS (of course ability to turn it off, too).

I get so sick of level 400s. lvl 300 seems high to me, but what do I know? I haven't played global since like version 5
 
Bugfix and some screenshots
Bug fix: on config.lua, I wrote "maxlevel" instead of "maxLevel". It's a shame that I can't edit my own thread on OTLand! moderators, fix this ASAP.

Screenshots:

From level 299 to level 300:
9vH0EV5hSo_oL9pl1IKNgA.jpg


On level 300 (first time):
qzPn0nbWQW2p_jSxG4qP3g.jpg


From level 300 to level 301 (first time):
3SFYKMmqQxWjLCtR02z4yA.jpg


Look 1% passive damage bonus:
wpq26utASpG6WH878_6snQ.jpg


Gaining less experience:
4IJOMLgxTQ_Lztpg6JbQDw.jpg


Level 300 to 301 (second time):
GW446DyfQ6_W24SjnjsTYA.jpg


Damage test (0% bonus):
6SyAXyozSSOuK00W_fomew.jpg


Damage test (20% bonus):
A0hYMEnJS0eaYoV1GB_QPA.jpg


Damage test (50% bonus):
mDLU5eHyRn_s351aDvV3xQ.jpg


Note: it's showing my level while looking at myself because I'm using my distro with some edits, but it should look similar (without showing the level, though)
 
Code:
/home/global/source/src/player.cpp: In member function ‘void Player::addExperience(Creature*, uint64_t, bool)’:
/home/global/source/src/player.cpp:1792:1: error: a function-definition is not allowed here before ‘{’ token
 {
 ^
/home/global/source/src/player.cpp:4870:1: error: expected ‘}’ at end of input
 }
 ^
make[2]: *** [CMakeFiles/tfs.dir/src/player.cpp.o] Error 1
make[1]: *** [CMakeFiles/tfs.dir/all] Error 2
make: *** [all] Error 2

C++:
void Player::addExperience(Creature* source, uint64_t exp, bool sendText/* = false*/)
{
    uint16_t prevPassiveDamageBonus = passiveDamageBonus;
    uint64_t currLevelExp = Player::getExpForLevel(level);
    uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
    uint64_t rawExp = exp;
    if (currLevelExp >= nextLevelExp) {
        //player has reached max level
        levelPercent = 0;
        sendStats();
        return;
    }

    g_events->eventPlayerOnGainExperience(this, source, exp, rawExp);
    if (exp == 0) {
        return;
    }

    experience += exp;

    if (sendText) {
        std::string expString = std::to_string(exp) + (exp != 1 ? " experience points." : " experience point.");

        TextMessage message(MESSAGE_EXPERIENCE, "You gained " + expString);
        message.position = position;
        message.primary.value = exp;
        message.primary.color = TEXTCOLOR_WHITE_EXP;
        sendTextMessage(message);

        SpectatorHashSet spectators;
        g_game.map.getSpectators(spectators, position, false, true);
        spectators.erase(this);
        if (!spectators.empty()) {
            message.type = MESSAGE_EXPERIENCE_OTHERS;
            message.text = getName() + " gained " + expString;
            for (Creature* spectator : spectators) {
                spectator->getPlayer()->sendTextMessage(message);
            }
        }
    }

    uint32_t prevLevel = level;
    while (experience >= nextLevelExp) {
        ++level;
        //custom edit: max level / passiveDamageBonus
        health += vocation->getHPGain();                if (level > (uint32_t)g_config.getNumber(ConfigManager::MAX_LEVEL))
        manaMax += vocation->getManaGain();                {
        mana += vocation->getManaGain();                    if (passiveDamageBonus < g_config.getNumber(ConfigManager::MAX_PASSIVE_DAMAGE_BONUS))
        capacity += vocation->getCapGain();                    {
                passiveDamageBonus++;
        currLevelExp = nextLevelExp;                    }       
        nextLevelExp = Player::getExpForLevel(level + 1);                    level = g_config.getNumber(ConfigManager::MAX_LEVEL);
        if (currLevelExp >= nextLevelExp) {                    // reduzir a exp equivalente a um level.. caso ele upe dois ou mais, vai executar o loop 2x
            //player has reached max level                    experience -= getExpForLevel(g_config.getNumber(ConfigManager::MAX_LEVEL)+1) - getExpForLevel(g_config.getNumber(ConfigManager::MAX_LEVEL));
            break;                }
        else
        {
            healthMax += vocation->getHPGain();
            health += vocation->getHPGain();
            manaMax += vocation->getManaGain();
            mana += vocation->getManaGain();
            capacity += vocation->getCapGain();
            currLevelExp = nextLevelExp;
            nextLevelExp = Player::getExpForLevel(level + 1);
            if (currLevelExp >= nextLevelExp) {
                //player has reached max level
                break;
            }
        }
    }

    if (prevLevel != level) {
        health = healthMax;
        mana = manaMax;

        updateBaseSpeed();
        setBaseSpeed(getBaseSpeed());
        //setBaseXpGain(g_game.getExperienceStage(level)*100);
        g_game.changeSpeed(this, 0);
        g_game.addCreatureHealth(this);

        if (party) {
            party->updateSharedExperience();
        }

        g_creatureEvents->playerAdvance(this, SKILL_LEVEL, prevLevel, level);

        std::ostringstream ss;
        ss << "You advanced from Level " << prevLevel << " to Level " << level << '.';
        sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
        }
    else if (prevPassiveDamageBonus != passiveDamageBonus)
    {
        std::ostringstream msgDamageBonus;
        msgDamageBonus << "You are currently on maximum level. Your passive damage bonus advanced from " << prevPassiveDamageBonus << "% to " << passiveDamageBonus << "%.";
        sendTextMessage(MESSAGE_EVENT_ADVANCE, msgDamageBonus.str());
    }

    if (nextLevelExp > currLevelExp) {
        levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
    } else {
        levelPercent = 0;
    }
    sendStats();
}

void Player::removeExperience(uint64_t exp, bool sendText/* = false*/)
{
    if (experience == 0 || exp == 0) {
        return;
    }

    g_events->eventPlayerOnLoseExperience(this, exp);
    if (exp == 0) {
        return;
    }

    uint64_t lostExp = experience;
    experience = std::max<int64_t>(0, experience - exp);

    if (sendText) {
        lostExp -= experience;

        std::string expString = std::to_string(lostExp) + (lostExp != 1 ? " experience points." : " experience point.");

        TextMessage message(MESSAGE_EXPERIENCE, "You lost " + expString);
        message.position = position;
        message.primary.value = lostExp;
        message.primary.color = TEXTCOLOR_RED;
        sendTextMessage(message);

        SpectatorHashSet spectators;
        g_game.map.getSpectators(spectators, position, false, true);
        spectators.erase(this);
        if (!spectators.empty()) {
            message.type = MESSAGE_EXPERIENCE_OTHERS;
            message.text = getName() + " lost " + expString;
            for (Creature* spectator : spectators) {
                spectator->getPlayer()->sendTextMessage(message);
            }
        }
    }

    uint32_t oldLevel = level;
    uint64_t currLevelExp = Player::getExpForLevel(level);

    while (level > 1 && experience < currLevelExp) {
        --level;
        healthMax = std::max<int32_t>(0, healthMax - vocation->getHPGain());
        manaMax = std::max<int32_t>(0, manaMax - vocation->getManaGain());
        capacity = std::max<int32_t>(0, capacity - vocation->getCapGain());
        currLevelExp = Player::getExpForLevel(level);
    }

    if (oldLevel != level) {
        health = healthMax;
        mana = manaMax;

        updateBaseSpeed();
        setBaseSpeed(getBaseSpeed());

        g_game.changeSpeed(this, 0);
        g_game.addCreatureHealth(this);

        if (party) {
            party->updateSharedExperience();
        }

        std::ostringstream ss;
        ss << "You were downgraded from Level " << oldLevel << " to Level " << level << '.';
        sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
        if (passiveDamageBonus > 0)
        {
            passiveDamageBonus--;
            std::ostringstream msgPassive;
            msgPassive << "Your passive damage bonus has reduced from " << passiveDamageBonus + 1 << "% to " << passiveDamageBonus << "%.";
            sendTextMessage(MESSAGE_EVENT_ADVANCE, msgPassive.str());
        }
    }

    uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
    if (nextLevelExp > currLevelExp) {
        levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
    } else {
        levelPercent = 0;
    }
    sendStats();
}

solution?
 
Back
Top