• 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 1.2 house warning letter & items disappearing

ots49

Member
Joined
Jun 7, 2022
Messages
61
Reaction score
17
Hello folks.
I've been recieving alot of help from you guys lately and I appreciate it alot so I'm trying my luck here again!

I'm using tfs 1.2 8.0 (This one)

And for some reason players are not getting any rent warning letters in their depot and also after 7 days of warnings being added on to the database (but no warning letter) they get kicked from the house like it should but their items get sent to oblivion.

If players have money in bank it does take it and renew the lease.

I've checked the database to try to see if the players items ends up in some unknown dp location after losing their house but no it literally disappears!

There is no such issue when player uses !leavehouse command. Only when rent warning has passed 7 days and player loses house.

Any one got any idea what the issue could be? Or if anyone got a fix for this I would appreciate it alot!
I tried searching alot for this issue but have not found anything unfortunatly.

EDIT: Is there anyway to make these functions lua script based instead?

edit:
This is from my house.cpp
C++:
void Houses::payHouses(RentPeriod_t rentPeriod) const
{
    if (rentPeriod == RENTPERIOD_NEVER) {
        return;
    }

    time_t currentTime = time(nullptr);
    for (const auto& it : houseMap) {
        House* house = it.second;
        if (house->getOwner() == 0) {
            continue;
        }

        const uint32_t rent = house->getRent();
        if (rent == 0 || house->getPaidUntil() > currentTime) {
            continue;
        }

        const uint32_t ownerId = house->getOwner();
        Town* town = g_game.map.towns.getTown(house->getTownId());
        if (!town) {
            continue;
        }

        Player player(nullptr);
        if (!IOLoginData::loadPlayerById(&player, ownerId)) {
            // Player doesn't exist, reset house owner
            house->setOwner(0);
            continue;
        }

        if (player.getBankBalance() >= rent) {
            player.setBankBalance(player.getBankBalance() - rent);

            time_t paidUntil = currentTime;
            switch (rentPeriod) {
                case RENTPERIOD_DAILY:
                    paidUntil += 24 * 60 * 60;
                    break;
                case RENTPERIOD_WEEKLY:
                    paidUntil += 24 * 60 * 60 * 7;
                    break;
                case RENTPERIOD_MONTHLY:
                    paidUntil += 24 * 60 * 60 * 30;
                    break;
                case RENTPERIOD_YEARLY:
                    paidUntil += 24 * 60 * 60 * 365;
                    break;
                default:
                    break;
            }

            house->setPaidUntil(paidUntil);
        } else {
            if (house->getPayRentWarnings() < 7) {
                int32_t daysLeft = 7 - house->getPayRentWarnings();

                Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED);
                std::string period;

                switch (rentPeriod) {
                    case RENTPERIOD_DAILY:
                        period = "daily";
                        break;

                    case RENTPERIOD_WEEKLY:
                        period = "weekly";
                        break;

                    case RENTPERIOD_MONTHLY:
                        period = "monthly";
                        break;

                    case RENTPERIOD_YEARLY:
                        period = "annual";
                        break;

                    default:
                        break;
                }

                std::ostringstream ss;
                ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house.";
                letter->setText(ss.str());
                DepotLocker* depotLocker = player.getDepotLocker(town->getID());
                if (depotLocker) {
                    g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
                }
                house->setPayRentWarnings(house->getPayRentWarnings() + 1);
            } else {
                house->setOwner(0, true, &player);
            }
        }

        IOLoginData::savePlayer(&player);
    }
}

Thanks in advance!
 
Last edited:
You should have something like this in house.cpp
C++:
bool House::transferToDepot(Player* player) const
{
    if (townId == 0 || owner == 0) {
        return false;
    }

    ItemList moveItemList;
    for (HouseTile* tile : houseTiles) {
        if (const TileItemVector* items = tile->getItemList()) {
            for (Item* item : *items) {
                if (item->isPickupable()) {
                    moveItemList.push_back(item);
                } else {
                    Container* container = item->getContainer();
                    if (container) {
                        for (Item* containerItem : container->getItemList()) {
                            moveItemList.push_back(containerItem);
                        }
                    }
                }
            }
        }
    }

    DepotLocker* depot = player->getDepotLocker(townId);
    for (Item* item : moveItemList) {
        g_game.internalMoveItem(item->getParent(), depot, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
    }
    return true;
}

The code to send letter seems fine. Make sure your depot boxes are set up correctly. I feel like that is the issue.
The house system is based on town ids so if player has townID 7 but there is no depot linked to that town id the items and letter can't go anywhere.
right click->properties the depot to check the townid it is linked too.
 
You should have something like this in house.cpp
C++:
bool House::transferToDepot(Player* player) const
{
    if (townId == 0 || owner == 0) {
        return false;
    }

    ItemList moveItemList;
    for (HouseTile* tile : houseTiles) {
        if (const TileItemVector* items = tile->getItemList()) {
            for (Item* item : *items) {
                if (item->isPickupable()) {
                    moveItemList.push_back(item);
                } else {
                    Container* container = item->getContainer();
                    if (container) {
                        for (Item* containerItem : container->getItemList()) {
                            moveItemList.push_back(containerItem);
                        }
                    }
                }
            }
        }
    }

    DepotLocker* depot = player->getDepotLocker(townId);
    for (Item* item : moveItemList) {
        g_game.internalMoveItem(item->getParent(), depot, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
    }
    return true;
}

The code to send letter seems fine. Make sure your depot boxes are set up correctly. I feel like that is the issue.
The house system is based on town ids so if player has townID 7 but there is no depot linked to that town id the items and letter can't go anywhere.
right click->properties the depot to check the townid it is linked too.
Hello thanks for taking your time to help me.

I have looked at town and depot id and have found nothing wrong. Every towns dp is linked correctly and even houses are in correct townID I have even tried my datapack with a different distro (with nekiros 1.5 8.0 downgrade) and on that distro everything is fine. I'm getting warning letters and items are being teleported to player depot instead of being deleted (on tfs 1.5 8.0 downgrade).
Which is why I'm looking deeper into the sources and I'm thinking the problem is probably there?

this is my complete house.cpp:
C++:
/**
 * The Forgotten Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2016  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 "pugicast.h"

#include "house.h"
#include "iologindata.h"
#include "game.h"
#include "configmanager.h"
#include "bed.h"

extern ConfigManager g_config;
extern Game g_game;

House::House(uint32_t _houseid) :
    transfer_container(ITEM_LOCKER)
{
    isLoaded = false;
    owner = 0;
    posEntry.x = 0;
    posEntry.y = 0;
    posEntry.z = 0;
    paidUntil = 0;
    id = _houseid;
    rentWarnings = 0;
    rent = 0;
    townid = 0;
    transferItem = nullptr;
}

void House::addTile(HouseTile* tile)
{
    tile->setFlag(TILESTATE_PROTECTIONZONE);
    houseTiles.push_back(tile);
}

void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* player/* = nullptr*/)
{
    if (updateDatabase && owner != guid) {
        Database* db = Database::getInstance();

        std::ostringstream query;
        query << "UPDATE `houses` SET `owner` = " << guid << ", `bid` = 0, `bid_end` = 0, `last_bid` = 0, `highest_bidder` = 0  WHERE `id` = " << id;
        db->executeQuery(query.str());
    }

    if (isLoaded && owner == guid) {
        return;
    }

    isLoaded = true;

    if (owner != 0) {
        //send items to depot
        if (player) {
            transferToDepot(player);
        } else {
            transferToDepot();
        }

        for (HouseTile* tile : houseTiles) {
            if (const CreatureVector* creatures = tile->getCreatures()) {
                for (int32_t i = creatures->size(); --i >= 0;) {
                    kickPlayer(nullptr, (*creatures)[i]->getPlayer());
                }
            }
        }

        // Remove players from beds
        for (BedItem* bed : bedsList) {
            if (bed->getSleeper() != 0) {
                bed->wakeUp(nullptr);
            }
        }

        //clean access lists
        owner = 0;
        setAccessList(SUBOWNER_LIST, "");
        setAccessList(GUEST_LIST, "");

        for (Door* door : doorSet) {
            door->setAccessList("");
        }
    } else {
        std::string strRentPeriod = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));
        time_t currentTime = time(nullptr);
        if (strRentPeriod == "yearly") {
            currentTime += 24 * 60 * 60 * 365;
        } else if (strRentPeriod == "monthly") {
            currentTime += 24 * 60 * 60 * 30;
        } else if (strRentPeriod == "weekly") {
            currentTime += 24 * 60 * 60 * 7;
        } else if (strRentPeriod == "daily") {
            currentTime += 24 * 60 * 60;
        } else {
            currentTime = 0;
        }

        paidUntil = currentTime;
    }

    rentWarnings = 0;
    
    if (guid != 0) {
        std::string name = IOLoginData::getNameByGuid(guid);
        if (!name.empty()) {
            owner = guid;
            ownerName = name;
        }
    }

    updateDoorDescription();
}

void House::updateDoorDescription() const
{
    std::ostringstream ss;
    if (owner != 0) {
        ss << "It belongs to house '" << houseName << "'. " << ownerName << " owns this house.";
    } else {
        ss << "It belongs to house '" << houseName << "'. Nobody owns this house.";

        const int32_t housePrice = g_config.getNumber(ConfigManager::HOUSE_PRICE);
        if (housePrice != -1) {
            ss << " It costs " << (houseTiles.size() * housePrice) << " gold coins.";
        }
    }

    for (const auto& it : doorSet) {
        it->setSpecialDescription(ss.str());
    }
}

AccessHouseLevel_t House::getHouseAccessLevel(const Player* player)
{
    if (!player) {
        return HOUSE_OWNER;
    }

    if (player->hasFlag(PlayerFlag_CanEditHouses)) {
        return HOUSE_OWNER;
    }

    if (player->getGUID() == owner) {
        return HOUSE_OWNER;
    }

    if (subOwnerList.isInList(player)) {
        return HOUSE_SUBOWNER;
    }

    if (guestList.isInList(player)) {
        return HOUSE_GUEST;
    }

    return HOUSE_NOT_INVITED;
}

bool House::kickPlayer(Player* player, Player* target)
{
    if (!target) {
        return false;
    }

    HouseTile* houseTile = dynamic_cast<HouseTile*>(target->getTile());
    if (!houseTile || houseTile->getHouse() != this) {
        return false;
    }

    if (getHouseAccessLevel(player) < getHouseAccessLevel(target) || target->hasFlag(PlayerFlag_CanEditHouses)) {
        return false;
    }

    Position oldPosition = target->getPosition();
    if (g_game.internalTeleport(target, getEntryPosition()) == RETURNVALUE_NOERROR) {
        g_game.addMagicEffect(oldPosition, CONST_ME_POFF);
        g_game.addMagicEffect(getEntryPosition(), CONST_ME_TELEPORT);
    }
    return true;
}

void House::setAccessList(uint32_t listId, const std::string& textlist)
{
    if (listId == GUEST_LIST) {
        guestList.parseList(textlist);
    } else if (listId == SUBOWNER_LIST) {
        subOwnerList.parseList(textlist);
    } else {
        Door* door = getDoorByNumber(listId);
        if (door) {
            door->setAccessList(textlist);
        }

        // We dont have kick anyone
        return;
    }

    //kick uninvited players
    for (HouseTile* tile : houseTiles) {
        if (CreatureVector* creatures = tile->getCreatures()) {
            for (int32_t i = creatures->size(); --i >= 0;) {
                Player* player = (*creatures)[i]->getPlayer();
                if (player && !isInvited(player)) {
                    kickPlayer(nullptr, player);
                }
            }
        }
    }
}

bool House::transferToDepot() const
{
    if (townid == 0 || owner == 0) {
        return false;
    }

    Player* player = g_game.getPlayerByGUID(owner);
    if (player) {
        transferToDepot(player);
    } else {
        Player tmpPlayer(nullptr);
        if (!IOLoginData::loadPlayerById(&tmpPlayer, owner)) {
            return false;
        }

        transferToDepot(&tmpPlayer);
        IOLoginData::savePlayer(&tmpPlayer);
    }
    return true;
}

bool House::transferToDepot(Player* player) const
{
    if (townid == 0 || owner == 0) {
        return false;
    }

    ItemList moveItemList;
    for (HouseTile* tile : houseTiles) {
        if (const TileItemVector* items = tile->getItemList()) {
            for (Item* item : *items) {
                if (item->isPickupable()) {
                    moveItemList.push_back(item);
                } else {
                    Container* container = item->getContainer();
                    if (container) {
                        for (Item* containerItem : container->getItemList()) {
                            moveItemList.push_back(containerItem);
                        }
                    }
                }
            }
        }
    }

    DepotLocker* depotLocker = player->getDepotLocker(townid);
    if (depotLocker) {
        for (Item* item : moveItemList) {
            g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
        }
    }
    return true;
}

bool House::getAccessList(uint32_t listId, std::string& list) const
{
    if (listId == GUEST_LIST) {
        guestList.getList(list);
        return true;
    } else if (listId == SUBOWNER_LIST) {
        subOwnerList.getList(list);
        return true;
    }

    Door* door = getDoorByNumber(listId);
    if (!door) {
        return false;
    }

    return door->getAccessList(list);
}

bool House::isInvited(const Player* player)
{
    return getHouseAccessLevel(player) != HOUSE_NOT_INVITED;
}

void House::addDoor(Door* door)
{
    door->incrementReferenceCounter();
    doorSet.insert(door);
    door->setHouse(this);
    updateDoorDescription();
}

void House::removeDoor(Door* door)
{
    auto it = doorSet.find(door);
    if (it != doorSet.end()) {
        door->decrementReferenceCounter();
        doorSet.erase(it);
    }
}

void House::addBed(BedItem* bed)
{
    bedsList.push_back(bed);
    bed->setHouse(this);
}

Door* House::getDoorByNumber(uint32_t doorId) const
{
    for (Door* door : doorSet) {
        if (door->getDoorId() == doorId) {
            return door;
        }
    }
    return nullptr;
}

Door* House::getDoorByPosition(const Position& pos)
{
    for (Door* door : doorSet) {
        if (door->getPosition() == pos) {
            return door;
        }
    }
    return nullptr;
}

bool House::canEditAccessList(uint32_t listId, const Player* player)
{
    switch (getHouseAccessLevel(player)) {
        case HOUSE_OWNER:
            return true;

        case HOUSE_SUBOWNER:
            return listId == GUEST_LIST;

        default:
            return false;
    }
}

HouseTransferItem* House::getTransferItem()
{
    if (transferItem != nullptr) {
        return nullptr;
    }

    transfer_container.setParent(nullptr);
    transferItem = HouseTransferItem::createHouseTransferItem(this);
    transfer_container.addThing(transferItem);
    return transferItem;
}

void House::resetTransferItem()
{
    if (transferItem) {
        Item* tmpItem = transferItem;
        transferItem = nullptr;
        transfer_container.setParent(nullptr);

        transfer_container.removeThing(tmpItem, tmpItem->getItemCount());
        g_game.ReleaseItem(tmpItem);
    }
}

HouseTransferItem* HouseTransferItem::createHouseTransferItem(House* house)
{
    HouseTransferItem* transferItem = new HouseTransferItem(house);
    transferItem->incrementReferenceCounter();
    transferItem->setID(ITEM_DOCUMENT_RO);
    transferItem->setSubType(1);
    std::ostringstream ss;
    ss << "It is a house transfer document for '" << house->getName() << "'.";
    transferItem->setSpecialDescription(ss.str());
    return transferItem;
}

void HouseTransferItem::onTradeEvent(TradeEvents_t event, Player* owner)
{
    if (event == ON_TRADE_TRANSFER) {
        if (house) {
            house->executeTransfer(this, owner);
        }

        g_game.internalRemoveItem(this, 1);
    } else if (event == ON_TRADE_CANCEL) {
        if (house) {
            house->resetTransferItem();
        }
    }
}

bool House::executeTransfer(HouseTransferItem* item, Player* newOwner)
{
    if (transferItem != item) {
        return false;
    }

    setOwner(newOwner->getGUID());
    transferItem = nullptr;
    return true;
}

void AccessList::parseList(const std::string& _list)
{
    playerList.clear();
    guildList.clear();
    allowEveryone = false;
    list = _list;
    if (_list.empty()) {
        return;
    }

    std::istringstream listStream(_list);
    std::string line;

    int lineNo = 1;
    while (getline(listStream, line)) {
        if (++lineNo > 100) {
            break;
        }

        trimString(line);
        trim_left(line, '\t');
        trim_right(line, '\t');
        trimString(line);

        if (line.empty() || line.front() == '#' || line.length() > 100) {
            continue;
        }

        toLowerCaseString(line);

        std::string::size_type at_pos = line.find("@");
        if (at_pos != std::string::npos) {
            addGuild(line.substr(at_pos + 1));
        } else if (line == "*") {
            allowEveryone = true;
        } else if (line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) {
            continue; // regexp no longer supported
        } else {
            addPlayer(line);
        }
    }
}

void AccessList::addPlayer(const std::string& name)
{
    Player* player = g_game.getPlayerByName(name);
    if (player) {
        playerList.insert(player->getGUID());
    } else {
        uint32_t guid = IOLoginData::getGuidByName(name);
        if (guid != 0) {
            playerList.insert(guid);
        }
    }
}

void AccessList::addGuild(const std::string& name)
{
    uint32_t guildId = IOGuild::getGuildIdByName(name);
    if (guildId != 0) {
        guildList.insert(guildId);
    }
}

bool AccessList::isInList(const Player* player)
{
    if (allowEveryone) {
        return true;
    }
    auto playerIt = playerList.find(player->getGUID());
    if (playerIt != playerList.end()) {
        return true;
    }

    const Guild* guild = player->getGuild();
    return guild && guildList.find(guild->getId()) != guildList.end();
}

void AccessList::getList(std::string& _list) const
{
    _list = list;
}

Door::Door(uint16_t _type)
    : Item(_type)
{
    house = nullptr;
    accessList = nullptr;
}

Door::~Door()
{
    delete accessList;
}

Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream)
{
    if (attr == ATTR_HOUSEDOORID) {
        uint8_t _doorId;
        if (!propStream.read<uint8_t>(_doorId)) {
            return ATTR_READ_ERROR;
        }

        setDoorId(_doorId);
        return ATTR_READ_CONTINUE;
    }
    return Item::readAttr(attr, propStream);
}

void Door::setHouse(House* _house)
{
    if (house != nullptr) {
        return;
    }

    house = _house;

    if (!accessList) {
        accessList = new AccessList();
    }
}

bool Door::canUse(const Player* player)
{
    if (!house) {
        return true;
    }

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

    return accessList->isInList(player);
}

void Door::setAccessList(const std::string& textlist)
{
    if (!accessList) {
        accessList = new AccessList();
    }

    accessList->parseList(textlist);
}

bool Door::getAccessList(std::string& list) const
{
    if (!house) {
        return false;
    }

    accessList->getList(list);
    return true;
}

void Door::onRemoved()
{
    Item::onRemoved();

    if (house) {
        house->removeDoor(this);
    }
}

House* Houses::getHouseByPlayerId(uint32_t playerId)
{
    for (const auto& it : houseMap) {
        if (it.second->getOwner() == playerId) {
            return it.second;
        }
    }
    return nullptr;
}

bool Houses::loadHousesXML(const std::string& filename)
{
    pugi::xml_document doc;
    pugi::xml_parse_result result = doc.load_file(filename.c_str());
    if (!result) {
        printXMLError("Error - Houses::loadHousesXML", filename, result);
        return false;
    }

    for (auto houseNode : doc.child("houses").children()) {
        pugi::xml_attribute houseIdAttribute = houseNode.attribute("houseid");
        if (!houseIdAttribute) {
            return false;
        }

        int32_t houseId = pugi::cast<int32_t>(houseIdAttribute.value());

        House* house = getHouse(houseId);
        if (!house) {
            std::cout << "Error: [Houses::loadHousesXML] Unknown house, id = " << houseId << std::endl;
            return false;
        }

        house->setName(houseNode.attribute("name").as_string());

        Position entryPos(
            pugi::cast<uint16_t>(houseNode.attribute("entryx").value()),
            pugi::cast<uint16_t>(houseNode.attribute("entryy").value()),
            pugi::cast<uint16_t>(houseNode.attribute("entryz").value())
        );
        if (entryPos.x == 0 && entryPos.y == 0 && entryPos.z == 0) {
            std::cout << "[Warning - Houses::loadHousesXML] House entry not set"
                        << " - Name: " << house->getName()
                        << " - House id: " << houseId << std::endl;
        }
        house->setEntryPos(entryPos);

        house->setRent(pugi::cast<uint32_t>(houseNode.attribute("rent").value()));
        house->setTownId(pugi::cast<uint32_t>(houseNode.attribute("townid").value()));

        house->setOwner(0, false);
    }
    return true;
}

void Houses::payHouses(RentPeriod_t rentPeriod) const
{
    if (rentPeriod == RENTPERIOD_NEVER) {
        return;
    }

    time_t currentTime = time(nullptr);
    for (const auto& it : houseMap) {
        House* house = it.second;
        if (house->getOwner() == 0) {
            continue;
        }

        const uint32_t rent = house->getRent();
        if (rent == 0 || house->getPaidUntil() > currentTime) {
            continue;
        }

        const uint32_t ownerId = house->getOwner();
        Town* town = g_game.map.towns.getTown(house->getTownId());
        if (!town) {
            continue;
        }

        Player player(nullptr);
        if (!IOLoginData::loadPlayerById(&player, ownerId)) {
            // Player doesn't exist, reset house owner
            house->setOwner(0);
            continue;
        }

        if (player.getBankBalance() >= rent) {
            player.setBankBalance(player.getBankBalance() - rent);

            time_t paidUntil = currentTime;
            switch (rentPeriod) {
                case RENTPERIOD_DAILY:
                    paidUntil += 24 * 60 * 60;
                    break;
                case RENTPERIOD_WEEKLY:
                    paidUntil += 24 * 60 * 60 * 7;
                    break;
                case RENTPERIOD_MONTHLY:
                    paidUntil += 24 * 60 * 60 * 30;
                    break;
                case RENTPERIOD_YEARLY:
                    paidUntil += 24 * 60 * 60 * 365;
                    break;
                default:
                    break;
            }

            house->setPaidUntil(paidUntil);
        } else {
            if (house->getPayRentWarnings() < 7) {
                int32_t daysLeft = 7 - house->getPayRentWarnings();

                Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED);
                std::string period;

                switch (rentPeriod) {
                    case RENTPERIOD_DAILY:
                        period = "daily";
                        break;

                    case RENTPERIOD_WEEKLY:
                        period = "weekly";
                        break;

                    case RENTPERIOD_MONTHLY:
                        period = "monthly";
                        break;

                    case RENTPERIOD_YEARLY:
                        period = "annual";
                        break;

                    default:
                        break;
                }

                std::ostringstream ss;
                ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house.";
                letter->setText(ss.str());
                DepotLocker* depotLocker = player.getDepotLocker(town->getID());
                if (depotLocker) {
                    g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
                }
                house->setPayRentWarnings(house->getPayRentWarnings() + 1);
            } else {
                house->setOwner(0, true, &player);
            }
        }

        IOLoginData::savePlayer(&player);
    }
}
 
What is stopping you from changing to 1.5 8.0?

try changing this part of the code and testing it out
C++:
if (depotLocker) {
          g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
}

C++:
if (depotLocker) {
          std::cout << "Attempting to add rent warning letter to player depot." << std::endl;
          g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
} else {
          std::cout << "Could not find player depot. Could not send letter." << std::endl;
}

In the console it should print one of those two messages and that will help determine what is going on.
 
What is stopping you from changing to 1.5 8.0?

try changing this part of the code and testing it out
C++:
if (depotLocker) {
          g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
}

C++:
if (depotLocker) {
          std::cout << "Attempting to add rent warning letter to player depot." << std::endl;
          g_game.internalAddItem(depotLocker, letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
} else {
          std::cout << "Could not find player depot. Could not send letter." << std::endl;
}

In the console it should print one of those two messages and that will help determine what is going on.
I am working on moving over but it's taking sometime unfortunatly. Just thought I'd get this fixed until I complete the move over =D

So I followed ur code and got this in the distro:
Attempting to add rent warning letter to player depot.

But no letter. I checked in database as well and I have nothing in player_inboxitems or player_depotitems so I dont really know where it's going?

I've triple checked house and town ids now again and everything is correct (besides it wouldn't work on tfs 1.5 if there was an issue with house or townid?)
 
I just wanted to make sure the code was actually happening that way we can try to figure out what to do next.

Now we should see the code for
C++:
ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
                                  uint32_t flags/* = 0*/, bool test/* = false*/)

ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index,
                                  uint32_t flags, bool test, uint32_t& remainderCount)

Post the full codes for that it is in game.cpp
 
I just wanted to make sure the code was actually happening that way we can try to figure out what to do next.

Now we should see the code for
C++:
ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
                                  uint32_t flags/* = 0*/, bool test/* = false*/)

ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index,
                                  uint32_t flags, bool test, uint32_t& remainderCount)

Post the full codes for that it is in game.cpp
Looks like this in mine:

C++:
ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
                                  uint32_t flags/* = 0*/, bool test/* = false*/)
{
    uint32_t remainderCount = 0;
    return internalAddItem(toCylinder, item, index, flags, test, remainderCount);
}

ReturnValue Game::internalAddItem(Cylinder* toCylinder, Item* item, int32_t index,
                                  uint32_t flags, bool test, uint32_t& remainderCount)
{
    if (toCylinder == nullptr || item == nullptr) {
        return RETURNVALUE_NOTPOSSIBLE;
    }

    Cylinder* destCylinder = toCylinder;
    Item* toItem = nullptr;
    toCylinder = toCylinder->queryDestination(index, *item, &toItem, flags);

    //check if we can add this item
    ReturnValue ret = toCylinder->queryAdd(index, *item, item->getItemCount(), flags);
    if (ret != RETURNVALUE_NOERROR) {
        return ret;
    }

edit: Not sure how much I should have copied from game.cpp but here is my game.cpp game.cpp
 
Last edited:
After getting a tip I tried commiting this.
Only difference now is that after 7 days of not paying rent you lose the house and items are not in deleted but they stay in the house with no owner (before it cleared house and deleted item) also still no rent warning letters

edit: Also it completely broke the mail system can't send parcels xD

So I've gotten no where :D

So this is basically a BUMP
 
It looks like the code is the same in both distros you are using. Try posting
C++:
getDepotLocker

from player.cpp
 
It looks like the code is the same in both distros you are using. Try posting
C++:
getDepotLocker

from player.cpp


C++:
DepotChest* Player::getDepotChest(uint32_t depotId, bool autoCreate)
{
    auto it = depotChests.find(depotId);
    if (it != depotChests.end()) {
        return it->second;
    }

    if (!autoCreate) {
        return nullptr;
    }

    DepotChest* depotChest = new DepotChest(ITEM_DEPOT);
    depotChest->incrementReferenceCounter();
    depotChest->setMaxDepotItems(getMaxDepotItems());
    depotChests[depotId] = depotChest;
    return depotChest;
}

DepotLocker* Player::getDepotLocker(uint32_t depotId)
{
    auto it = depotLockerMap.find(depotId);
    if (it != depotLockerMap.end()) {
        return it->second;
    }

    DepotLocker* depotLocker = new DepotLocker(ITEM_LOCKER);
    depotLocker->setDepotId(depotId);
    depotLocker->internalAddThing(getDepotChest(depotId, true));
    depotLockerMap[depotId] = depotLocker;
    return depotLocker;
}

Here is both depotchest and locker!
 
Back
Top