• 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+ Beds broken.

Dries390

Well-Known Member
Joined
Sep 8, 2007
Messages
91
Solutions
4
Reaction score
70
I've noticed my beds don't function on my TFS 1.3 downgraded for 8.60 with delusion's item stat changes.



bed.cpp
C++:
/**
 * The Forgotten Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2018  Mark Samman <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#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 'Zzzz'/sleep effect
    g_game.addMagicEffect(player->getPosition(), CONST_ME_SLEEP);

    // 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[player->getSex()] != 0) {
            const ItemType& newType = Item::items[it.transformToOnUse[player->getSex()]];
            if (newType.type == ITEM_TYPE_BED) {
                g_game.transformItem(this, it.transformToOnUse[player->getSex()]);
            }
        } 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.");
}
bed.h
C++:
/**
 * The Forgotten Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2018  Mark Samman <[email protected]>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifndef FS_BED_H_84DE19758D424C6C9789189231946BFF
#define FS_BED_H_84DE19758D424C6C9789189231946BFF

#include "item.h"

class House;
class Player;

class BedItem final : public Item
{
    public:
        explicit BedItem(uint16_t id);

        BedItem* getBed() override {
            return this;
        }
        const BedItem* getBed() const override {
            return this;
        }

        Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
        void serializeAttr(PropWriteStream& propWriteStream) const override;

        bool canRemove() const override {
            return house == nullptr;
        }

        uint32_t getSleeper() const {
            return sleeperGUID;
        }

        void setHouse(House* h) {
            house = h;
        }

        bool canUse(Player* player);

        bool trySleep(Player* player);
        bool sleep(Player* player);
        void wakeUp(Player* player);

        BedItem* getNextBedItem() const;

    private:
        void updateAppearance(const Player* player);
        void regeneratePlayer(Player* player) const;
        void internalSetSleeper(const Player* player);
        void internalRemoveSleeper();

        House* house = nullptr;
        uint64_t sleepStart;
        uint32_t sleeperGUID;
};

#endif

I have tried with my God account, bought new houses with lower-access accounts/characters and none of them can log off by sleeping. No "you cannot use this item" message appears. Does anybody know what I could try?
 
Back
Top Bottom