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

TFS 1.X+ TFS, Znote, mana bed, conditions error bug?

Terozer

New Member
Joined
Aug 29, 2007
Messages
14
Reaction score
1
Using TFS and Znote. Mana does not gain while sleeping in beds.
I think it might have something to do with this error?

Also, is there a way to set mana gain speed while sleeping?
 

Attachments

  • Bedmage bug source maybe.png
    Bedmage bug source maybe.png
    19.6 KB · Views: 8 · VirusTotal
First you need to be full to go to sleep. and it takes a long time for the mana to rise!
In bed.cpp ur edit time here!

C++:
void BedItem::regeneratePlayer(Player* player) const
{
    const uint32_t sleptTime = time(nullptr) - sleepStart;

    Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
    if (condition) {
        uint32_t regen;
        if (condition->getTicks() != -1) {
            regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
            const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
            if (newRegenTicks <= 0) {
                player->removeCondition(condition);
            } else {
                condition->setTicks(newRegenTicks);
            }
        } else {
            regen = sleptTime / 30;
        }

        player->changeHealth(regen, false);
        player->changeMana(regen);
    }

    const int32_t soulRegen = sleptTime / (60 * 15);
    player->changeSoul(soulRegen);
}
 
First you need to be full to go to sleep. and it takes a long time for the mana to rise!
In bed.cpp ur edit time here!

C++:
void BedItem::regeneratePlayer(Player* player) const
{
    const uint32_t sleptTime = time(nullptr) - sleepStart;

    Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
    if (condition) {
        uint32_t regen;
        if (condition->getTicks() != -1) {
            regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
            const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
            if (newRegenTicks <= 0) {
                player->removeCondition(condition);
            } else {
                condition->setTicks(newRegenTicks);
            }
        } else {
            regen = sleptTime / 30;
        }

        player->changeHealth(regen, false);
        player->changeMana(regen);
    }

    const int32_t soulRegen = sleptTime / (60 * 15);
    player->changeSoul(soulRegen);
}

I have tested it multiple times. Last with two characters over night. One 8 knight and one 20 MS. Both was full and had premium account.
No mana gain occurs but they lose their "food ticks". I can eat again when I log in but no mana is gained. I do not know how to debug this..

This is my bed.cpp. Not exactly the same as yours? Mine is "/Condition condition " and yours is "Condition* condition".
Also no "}[/CODE]" after changesoul or in the end. The whole file is 6.46kB.



void BedItem::regeneratePlayer(Player* player) const
{
const uint32_t sleptTime = time(nullptr) - sleepStart;

/Condition condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
if (condition) {
uint32_t regen;
if (condition->getTicks() != -1) {
regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
if (newRegenTicks <= 0) {
player->removeCondition(condition);
} else {
condition->setTicks(newRegenTicks);
}
} else {
regen = sleptTime / 30;
}

player->changeHealth(regen, false);
player->changeMana(regen);
}*/

const int32_t soulRegen = sleptTime / (60 * 15);
player->changeSoul(soulRegen);
}

void BedItem::updateAppearance(const Player* player)
{
const ItemType& it = Item::items[id];
if (it.type == ITEM_TYPE_BED) {
if (player && it.transformToOnUse != 0) {
const ItemType& newType = Item::items[it.transformToOnUse];
if (newType.type == ITEM_TYPE_BED) {
g_game.transformItem(this, it.transformToOnUse);
}
} else if (it.transformToFree != 0) {
const ItemType& newType = Item::items[it.transformToFree];
if (newType.type == ITEM_TYPE_BED) {
g_game.transformItem(this, it.transformToFree);
}
}
}


edit: I do not know how to post code the way you did..
 
My whole bed.cpp, posted correctly.
Thanks, Addams!

C++:
#include "otpch.h"

#include "bed.h"
#include "game.h"
#include "iologindata.h"
#include "scheduler.h"

extern Game g_game;

BedItem::BedItem(uint16_t id) : Item(id)
{
    internalRemoveSleeper();
}

Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream)
{
    switch (attr) {
        case ATTR_SLEEPERGUID: {
            uint32_t guid;
            if (!propStream.read<uint32_t>(guid)) {
                return ATTR_READ_ERROR;
            }

            if (guid != 0) {
                std::string name = IOLoginData::getNameByGuid(guid);
                if (!name.empty()) {
                    setSpecialDescription(name + " is sleeping there.");
                    g_game.setBedSleeper(this, guid);
                    sleeperGUID = guid;
                }
            }
            return ATTR_READ_CONTINUE;
        }

        case ATTR_SLEEPSTART: {
            uint32_t sleep_start;
            if (!propStream.read<uint32_t>(sleep_start)) {
                return ATTR_READ_ERROR;
            }

            sleepStart = static_cast<uint64_t>(sleep_start);
            return ATTR_READ_CONTINUE;
        }

        default:
            break;
    }
    return Item::readAttr(attr, propStream);
}

void BedItem::serializeAttr(PropWriteStream& propWriteStream) const
{
    if (sleeperGUID != 0) {
        propWriteStream.write<uint8_t>(ATTR_SLEEPERGUID);
        propWriteStream.write<uint32_t>(sleeperGUID);
    }

    if (sleepStart != 0) {
        propWriteStream.write<uint8_t>(ATTR_SLEEPSTART);
        // FIXME: should be stored as 64-bit, but we need to retain backwards compatibility
        propWriteStream.write<uint32_t>(static_cast<uint32_t>(sleepStart));
    }
}

BedItem* BedItem::getNextBedItem() const
{
    Direction dir = Item::items[id].bedPartnerDir;
    Position targetPos = getNextPosition(dir, getPosition());

    Tile* tile = g_game.map.getTile(targetPos);
    if (!tile) {
        return nullptr;
    }
    return tile->getBedItem();
}

bool BedItem::canUse(Player* player)
{
    if (!player || !house || !player->isPremium()) {
        return false;
    }

    if (sleeperGUID == 0) {
        return true;
    }

    if (house->getHouseAccessLevel(player) == HOUSE_OWNER) {
        return true;
    }

    Player sleeper(nullptr);
    if (!IOLoginData::loadPlayerById(&sleeper, sleeperGUID)) {
        return false;
    }

    if (house->getHouseAccessLevel(&sleeper) > house->getHouseAccessLevel(player)) {
        return false;
    }
    return true;
}

bool BedItem::trySleep(Player* player)
{
    if (!house || player->isRemoved()) {
        return false;
    }

    if (sleeperGUID != 0) {
        if (Item::items[id].transformToFree != 0 && house->getOwner() == player->getGUID()) {
            wakeUp(nullptr);
        }

        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }
    return true;
}

bool BedItem::sleep(Player* player)
{
    if (!house) {
        return false;
    }

    if (sleeperGUID != 0) {
        return false;
    }

    BedItem* nextBedItem = getNextBedItem();

    internalSetSleeper(player);

    if (nextBedItem) {
        nextBedItem->internalSetSleeper(player);
    }

    // update the bedSleepersMap
    g_game.setBedSleeper(this, player->getGUID());

    // make the player walk onto the bed
    g_game.map.moveCreature(*player, *getTile());

    // display poff effect
    g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);

    // kick player after he sees himself walk onto the bed and it change id
    uint32_t playerId = player->getID();
    g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&Game::kickPlayer, &g_game, playerId, false)));

    // change self and partner's appearance
    updateAppearance(player);

    if (nextBedItem) {
        nextBedItem->updateAppearance(player);
    }

    return true;
}

void BedItem::wakeUp(Player* player)
{
    if (!house) {
        return;
    }

    if (sleeperGUID != 0) {
        if (!player) {
            Player regenPlayer(nullptr);
            if (IOLoginData::loadPlayerById(&regenPlayer, sleeperGUID)) {
                regeneratePlayer(&regenPlayer);
                IOLoginData::savePlayer(&regenPlayer);
            }
        } else {
            regeneratePlayer(player);
            g_game.addCreatureHealth(player);
        }
    }

    // update the bedSleepersMap
    g_game.removeBedSleeper(sleeperGUID);

    BedItem* nextBedItem = getNextBedItem();

    // unset sleep info
    internalRemoveSleeper();

    if (nextBedItem) {
        nextBedItem->internalRemoveSleeper();
    }

    // change self and partner's appearance
    updateAppearance(nullptr);

    if (nextBedItem) {
        nextBedItem->updateAppearance(nullptr);
    }
}

void BedItem::regeneratePlayer(Player* player) const
{
    const uint32_t sleptTime = time(nullptr) - sleepStart;

    /*Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
    if (condition) {
        uint32_t regen;
        if (condition->getTicks() != -1) {
            regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
            const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
            if (newRegenTicks <= 0) {
                player->removeCondition(condition);
            } else {
                condition->setTicks(newRegenTicks);
            }
        } else {
            regen = sleptTime / 30;
        }

        player->changeHealth(regen, false);
        player->changeMana(regen);
    }*/

    const int32_t soulRegen = sleptTime / (60 * 15);
    player->changeSoul(soulRegen);
}

void BedItem::updateAppearance(const Player* player)
{
    const ItemType& it = Item::items[id];
    if (it.type == ITEM_TYPE_BED) {
        if (player && it.transformToOnUse != 0) {
            const ItemType& newType = Item::items[it.transformToOnUse];
            if (newType.type == ITEM_TYPE_BED) {
                g_game.transformItem(this, it.transformToOnUse);
            }
        } else if (it.transformToFree != 0) {
            const ItemType& newType = Item::items[it.transformToFree];
            if (newType.type == ITEM_TYPE_BED) {
                g_game.transformItem(this, it.transformToFree);
            }
        }
    }
}

void BedItem::internalSetSleeper(const Player* player)
{
    std::string desc_str = player->getName() + " is sleeping there.";

    sleeperGUID = player->getGUID();
    sleepStart = time(nullptr);
    setSpecialDescription(desc_str);
}

void BedItem::internalRemoveSleeper()
{
    sleeperGUID = 0;
    sleepStart = 0;
    setSpecialDescription("Nobody is sleeping there.");
}
 
My whole bed.cpp, posted correctly.
Thanks, Addams!

C++:
#include "otpch.h"

#include "bed.h"
#include "game.h"
#include "iologindata.h"
#include "scheduler.h"

extern Game g_game;

BedItem::BedItem(uint16_t id) : Item(id)
{
    internalRemoveSleeper();
}

Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream)
{
    switch (attr) {
        case ATTR_SLEEPERGUID: {
            uint32_t guid;
            if (!propStream.read<uint32_t>(guid)) {
                return ATTR_READ_ERROR;
            }

            if (guid != 0) {
                std::string name = IOLoginData::getNameByGuid(guid);
                if (!name.empty()) {
                    setSpecialDescription(name + " is sleeping there.");
                    g_game.setBedSleeper(this, guid);
                    sleeperGUID = guid;
                }
            }
            return ATTR_READ_CONTINUE;
        }

        case ATTR_SLEEPSTART: {
            uint32_t sleep_start;
            if (!propStream.read<uint32_t>(sleep_start)) {
                return ATTR_READ_ERROR;
            }

            sleepStart = static_cast<uint64_t>(sleep_start);
            return ATTR_READ_CONTINUE;
        }

        default:
            break;
    }
    return Item::readAttr(attr, propStream);
}

void BedItem::serializeAttr(PropWriteStream& propWriteStream) const
{
    if (sleeperGUID != 0) {
        propWriteStream.write<uint8_t>(ATTR_SLEEPERGUID);
        propWriteStream.write<uint32_t>(sleeperGUID);
    }

    if (sleepStart != 0) {
        propWriteStream.write<uint8_t>(ATTR_SLEEPSTART);
        // FIXME: should be stored as 64-bit, but we need to retain backwards compatibility
        propWriteStream.write<uint32_t>(static_cast<uint32_t>(sleepStart));
    }
}

BedItem* BedItem::getNextBedItem() const
{
    Direction dir = Item::items[id].bedPartnerDir;
    Position targetPos = getNextPosition(dir, getPosition());

    Tile* tile = g_game.map.getTile(targetPos);
    if (!tile) {
        return nullptr;
    }
    return tile->getBedItem();
}

bool BedItem::canUse(Player* player)
{
    if (!player || !house || !player->isPremium()) {
        return false;
    }

    if (sleeperGUID == 0) {
        return true;
    }

    if (house->getHouseAccessLevel(player) == HOUSE_OWNER) {
        return true;
    }

    Player sleeper(nullptr);
    if (!IOLoginData::loadPlayerById(&sleeper, sleeperGUID)) {
        return false;
    }

    if (house->getHouseAccessLevel(&sleeper) > house->getHouseAccessLevel(player)) {
        return false;
    }
    return true;
}

bool BedItem::trySleep(Player* player)
{
    if (!house || player->isRemoved()) {
        return false;
    }

    if (sleeperGUID != 0) {
        if (Item::items[id].transformToFree != 0 && house->getOwner() == player->getGUID()) {
            wakeUp(nullptr);
        }

        g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
        return false;
    }
    return true;
}

bool BedItem::sleep(Player* player)
{
    if (!house) {
        return false;
    }

    if (sleeperGUID != 0) {
        return false;
    }

    BedItem* nextBedItem = getNextBedItem();

    internalSetSleeper(player);

    if (nextBedItem) {
        nextBedItem->internalSetSleeper(player);
    }

    // update the bedSleepersMap
    g_game.setBedSleeper(this, player->getGUID());

    // make the player walk onto the bed
    g_game.map.moveCreature(*player, *getTile());

    // display poff effect
    g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);

    // kick player after he sees himself walk onto the bed and it change id
    uint32_t playerId = player->getID();
    g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&Game::kickPlayer, &g_game, playerId, false)));

    // change self and partner's appearance
    updateAppearance(player);

    if (nextBedItem) {
        nextBedItem->updateAppearance(player);
    }

    return true;
}

void BedItem::wakeUp(Player* player)
{
    if (!house) {
        return;
    }

    if (sleeperGUID != 0) {
        if (!player) {
            Player regenPlayer(nullptr);
            if (IOLoginData::loadPlayerById(&regenPlayer, sleeperGUID)) {
                regeneratePlayer(&regenPlayer);
                IOLoginData::savePlayer(&regenPlayer);
            }
        } else {
            regeneratePlayer(player);
            g_game.addCreatureHealth(player);
        }
    }

    // update the bedSleepersMap
    g_game.removeBedSleeper(sleeperGUID);

    BedItem* nextBedItem = getNextBedItem();

    // unset sleep info
    internalRemoveSleeper();

    if (nextBedItem) {
        nextBedItem->internalRemoveSleeper();
    }

    // change self and partner's appearance
    updateAppearance(nullptr);

    if (nextBedItem) {
        nextBedItem->updateAppearance(nullptr);
    }
}

void BedItem::regeneratePlayer(Player* player) const
{
    const uint32_t sleptTime = time(nullptr) - sleepStart;

    /*Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
    if (condition) {
        uint32_t regen;
        if (condition->getTicks() != -1) {
            regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
            const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
            if (newRegenTicks <= 0) {
                player->removeCondition(condition);
            } else {
                condition->setTicks(newRegenTicks);
            }
        } else {
            regen = sleptTime / 30;
        }

        player->changeHealth(regen, false);
        player->changeMana(regen);
    }*/

    const int32_t soulRegen = sleptTime / (60 * 15);
    player->changeSoul(soulRegen);
}

void BedItem::updateAppearance(const Player* player)
{
    const ItemType& it = Item::items[id];
    if (it.type == ITEM_TYPE_BED) {
        if (player && it.transformToOnUse != 0) {
            const ItemType& newType = Item::items[it.transformToOnUse];
            if (newType.type == ITEM_TYPE_BED) {
                g_game.transformItem(this, it.transformToOnUse);
            }
        } else if (it.transformToFree != 0) {
            const ItemType& newType = Item::items[it.transformToFree];
            if (newType.type == ITEM_TYPE_BED) {
                g_game.transformItem(this, it.transformToFree);
            }
        }
    }
}

void BedItem::internalSetSleeper(const Player* player)
{
    std::string desc_str = player->getName() + " is sleeping there.";

    sleeperGUID = player->getGUID();
    sleepStart = time(nullptr);
    setSpecialDescription(desc_str);
}

void BedItem::internalRemoveSleeper()
{
    sleeperGUID = 0;
    sleepStart = 0;
    setSpecialDescription("Nobody is sleeping there.");
}
From line 203 to line 220, the function is commited, just remove the /* in line 203 and *\ in line 220 and compile your server again
 
From line 203 to line 220, the function is commited, just remove the /* in line 203 and *\ in line 220 and compile your server again
From line 203 to line 220, the function is commited, just remove the /* in line 203 and *\ in line 220 and compile your server again
From line 203 to line 220, the function is commited, just remove the /* in line 203 and *\ in line 220 and compile your server again

Thanks!
I wonder why they commited the bed regen function to begin with, very strange,..
By the way, do you know which value to change to change the mana gain rate?
I can not figure out what these values exactly mean:

It's either the "getTicks() / 1000)" value,
the "sleptTime) / 30" value
the "regen * 30000)" value
or the: "regen = sleptTime / 30" value

Also I am trying to find where to set how much food you can eat until full
 
Last edited:
Back
Top