• 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 1.2 Vocation initial and level in character list & chat channel.

Grrrr

Banned User
Joined
Feb 27, 2017
Messages
17
Solutions
2
Reaction score
10
This code might not work 100% or I might not have given all the code, but its good for testing purposes.
account.h
C++:
#ifndef FS_ACCOUNT_H_34817537BA2B4CB7B71AA562AFBB118F
#define FS_ACCOUNT_H_34817537BA2B4CB7B71AA562AFBB118F

#include "enums.h"

struct Account {
    std::vector<std::string> characters;
    std::string name;
    std::vector<std::string> vocinitial;
    std::vector<std::string> charlevel;
    std::string key;
    time_t lastDay = 0;
    uint32_t id = 0;
    uint16_t premiumDays = 0;
    AccountType_t accountType = ACCOUNT_TYPE_NORMAL;

    Account() = default;
};

#endif

iologindata.cpp
C++:
bool IOLoginData::loginserverAuthentication(const std::string& name, const std::string& password, Account& account)
{
    Database* db = Database::getInstance();

    std::ostringstream query;
    query << "SELECT `id`, `name`, `password`, `secret`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `name` = " << db.escapeString(name);
    DBResult_ptr result = db.storeQuery(query.str());
    if (!result) {
        return false;
    }

    if (transformToSHA1(password) != result->getString("password")) {
        return false;
    }

    account.id = result->getNumber<uint32_t>("id");
    account.name = result->getString("name");
    account.key = decodeSecret(result->getString("secret"));
    account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
    account.premiumDays = result->getNumber<uint16_t>("premdays");
    account.lastDay = result->getNumber<time_t>("lastday");

    query.str(std::string());
    query << "SELECT `name`, `deletion`, `initial`, `level` FROM `players` WHERE `account_id` = " << account.id;
    result = db.storeQuery(query.str());
    if (result) {
        do {
            if (result->getNumber<uint64_t>("deletion") == 0) {
                account.charlevel.push_back(levelConversion(result->getNumber<uint32_t>("level")));
                account.vocinitial.push_back(result->getString("initial"));
                account.characters.push_back(result->getString("name"));
            }
        } while (result->next());
    }
    return true;
}

protocollogin.cpp
C++:
void ProtocolLogin::getCharacterList(const std::string& accountName, const std::string& password, uint16_t version)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountName, password, account)) {
        disconnectClient("Account name or password is not correct.", version);
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();
    //Update premium days
    Game::updatePremium(account);

    addWorldInfo(output, accountName, password, version);

    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);
    for (uint8_t i = 0; i < size; i++) {
        output->addByte(0);
        const std::string achar = account.characters[i] + ":[ " + account.vocinitial[i] + " ][ " + account.charlevel[i] + " ] ";
        output->addString(achar);
    }

    //Add premium days
    output->addByte(0);
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->addByte(1);
        output->add<uint32_t>(0);
    } else {
        output->addByte(0);
        output->add<uint32_t>(time(nullptr) + (account.premiumDays * 86400));
    }

    send(output);

    disconnect();
}

add this to your schema CREATE TABLE IF NOT EXISTS `players` (
Code:
`initial` varchar(1) NOT NULL DEFAULT 'N',

Add this to IOLoginData::loadPlayer
C++:
player->setInitial(result->getString("initial"));
above
Code:
player->mana = result->getNumber<uint32_t>("mana");

Find IOLoginData::savePlayer(Player* player) and add this
C++:
query << "`initial` = '" << player->getInitial() << "',";
below
C++:
query << "`vocation` = " << player->getVocationId() << ',';


C++:
void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId)
{
    NetworkMessage msg;
    msg.addByte(0xAA);

    static uint32_t statementId = 0;
    msg.add<uint32_t>(++statementId);
    if (!creature) {
        msg.add<uint32_t>(0x00);
    }
    else if (type == TALKTYPE_CHANNEL_R2) {
        msg.add<uint32_t>(0x00);
        type = TALKTYPE_CHANNEL_R1;
    }
    else {
        // we want the player's name, their vocation and a summery of their level since its limited in range
        if (auto c = creature->getCreature()) {
            if (auto p = c->getPlayer()) {
                std::string extension = "[" + p->getInitial() + "][" + p->getPlayerTypeString() + "][" + levelConversion(p->getLevel()) + "]";
                const std::string tempName = getAbbreName(p->getName(), extension.size());
                const std::string newName = tempName + extension;
                msg.addString(newName);
            }
            else {
                msg.addString(creature->getName());
            }
        }
        msg.add<uint16_t>(0x00);
    }

    msg.addByte(type);
    msg.add<uint16_t>(channelId);
    msg.addString(text);
    writeToOutputBuffer(msg);
}

C++:
const std::string getAbbreName(const std::string name, size_t x) {
    if (name.size() > (x+2)) {
        const std::string n = name.substr(0, (name.size() - (x+2))) + "~";
        return n;
    }
    return name + " ";
}

C++:
void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, const std::string& text)
{
    NetworkMessage msg;
    msg.addByte(0xAA);
    static uint32_t statementId = 0;
    msg.add<uint32_t>(++statementId);
    if (speaker) {
        // we want the player's name, their vocation and a summery of their level since its limited in range
        if (auto c = speaker->getCreature()) {
            if (auto p = c->getPlayer()) {
                std::string extension = "[" + p->getInitial() + "][" + p->getPlayerTypeString() + "][" + levelConversion(p->getLevel()) + "]";
                const std::string tempName = getAbbreName(p->getName(), extension.size());
                const std::string newName = tempName + extension;
                msg.addString(newName);
            }
            else {
                msg.addString(speaker->getName());
            }
        }
        msg.add<uint16_t>(0x00);
    }
    else {
        msg.add<uint32_t>(0x00);
    }
    msg.addByte(type);
    msg.addString(text);
    writeToOutputBuffer(msg);
}

C++:
const std::string levelConversion(uint32_t value) {
    double i = (double)value;
    std::string l;
    if (value >= 1000 && value <= 999999) {
        l = std::to_string(i / 1000);
        if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
            const std::string level = l.substr(0, l.find('.')) + "K";
            return level;
        }
        else {
            const std::string level = l.substr(0, l.find('.') + 2) + "K";
            return level;
        }
    }
    else if (value >= 1000000 && value <= 999999999) {
        l = std::to_string(i / 1000000);
        if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
            const std::string level = l.substr(0, l.find('.')) + "M";
            return level;
        }
        else {
            const std::string level = l.substr(0, l.find('.') + 2) + "M";
            return level;
        }
    }
    else if (value >= 999999999 && value <= 9999999999) {
        l = std::to_string(i / 999999999);
        if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
            const std::string level = l.substr(0, l.find('.')) + "B";
            return level;
        }
        else {
            const std::string level = l.substr(0, l.find('.') + 2) + "B";
            return level;
        }
    }
    const std::string level = std::to_string(value);
    return level;
}
 
C++:
       std::string getInitial() const {
            initial = getVocation()->getVocName();
            initial = initial.substr(0, 1);
            return initial;
        }
 
Last edited:
C++:
        std::string getPlayerTypeString() const {
            uint32_t type = getPlayerType();
            switch (type) {
                case 1:
                    return "No-PvP";
                case 2:
                    return "PvP";
                case 3:
                    return "PvPe";
                default:
                    return "";
            }
        }
 
Last edited:
What exactly does this modification to the source do? Does it list Vocation and player level in all chat channels, as well as in the character list in the client? Do you have images of the outcome?
 
Back
Top