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

C++ Money currency little bug

S

Shadow_

Guest
Hello guys,
i have a little money bug ii have added new 2 currencies in my OT in sources in my game.cpp i got a little bug when i say !aol or !bless or buying using NPC and i have gold nuggets(only)i take random number of scarab coins , crystal coins , platinum coins , gold coins ( when i have scarab coins or crystal coins i take 99 scrab coins and 99 crystal coin as it should be but using gold nuggets gives random number of money i think its from unit_xx but i don't know how to fix it.
here is my game.cpp add money code :
C++:
void Game::addMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/)
{
    if (money == 0) {
        return;
    }
    uint32_t goldNuggets = money / 100000000;
    money -= goldNuggets * 100000000;
    while (goldNuggets > 0) {
        const uint16_t count = std::min<uint32_t>(100, goldNuggets);
        Item* remaindItem = Item::CreateItem(ITEM_GOLD_NUGGET, count);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        goldNuggets -= count;
    }
   
     uint32_t scarabCoins = money / 1000000;
    if (scarabCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_SCARAB_COIN, scarabCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= scarabCoins * 1000000;
    }
   
    uint32_t crystalCoins = money / 10000;
    if (crystalCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_CRYSTAL_COIN, crystalCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= crystalCoins * 10000;
    }
    uint16_t platinumCoins = money / 100;
    if (platinumCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_PLATINUM_COIN, platinumCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= platinumCoins * 100;
    }
    if (money != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_GOLD_COIN, money);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
    }
}
 
Solution
keep knowing that i have changed gold_nugget id to 9971 ( gold ingot id ) :
dnj72q.png

@Vulcan_ after using your script the same bug

Its working but when you have only 1 gold nugget when you have more than 4-50 nugget it doesn't give you exactly the scarab coins i mean not 99 and 99 cc
uint32_t holds up to a value of 4,294,967,295
42 gold nuggets = 4,200,000,000
after 43 the number loops back around to 0 and starts counting from there again
basically you need to set the stuff that deals with item::getWorth() and uses money to uint64_t so it holds that big of a value
in game.cpp replace Game::removeMoney with this
C++:
bool Game::removeMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*=...
works fine for me
KeiPHrf.png

i used an aol command, takes 1 cc
started off with 1 gold nugget -> remove 1cc = 99 scarab coins and 99 cc
if i start off with 99 scarab coins and no cc -> remove 1 cc = 98 scarab coins and 99 cc
1 scarab coin -> remove 1 cc = 99 cc

this is the code i used:

game.cpp
C++:
void Game::addMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/)
{
    if (money == 0) {
        return;
    }
    uint32_t goldNuggets = money / 100000000;
    money -= goldNuggets * 100000000;
    while (goldNuggets > 0) {
        const uint16_t count = std::min<uint32_t>(100, goldNuggets);
        Item* remaindItem = Item::CreateItem(ITEM_GOLD_NUGGET, count);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        goldNuggets -= count;
    }

    uint32_t scarabCoins = money / 1000000;
    if (scarabCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_SCARAB_COIN, scarabCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= scarabCoins * 1000000;
    }

    uint32_t crystalCoins = money / 10000;
    if (crystalCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_CRYSTAL_COIN, crystalCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= crystalCoins * 10000;
    }
    uint16_t platinumCoins = money / 100;
    if (platinumCoins != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_PLATINUM_COIN, platinumCoins);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
        money -= platinumCoins * 100;
    }
    if (money != 0) {
        Item* remaindItem = Item::CreateItem(ITEM_GOLD_COIN, money);
        ReturnValue ret = internalAddItem(cylinder, remaindItem, INDEX_WHEREEVER, flags);
        if (ret != RETURNVALUE_NOERROR) {
            internalAddItem(cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        }
    }
}

player.cpp
C++:
if (itemId != ITEM_GOLD_COIN && itemId != ITEM_PLATINUM_COIN && itemId != ITEM_CRYSTAL_COIN && itemId != ITEM_SCARAB_COIN && itemId != ITEM_GOLD_NUGGET) {

item.cpp
C++:
uint32_t Item::getWorth() const
{
    switch (id) {
    case ITEM_GOLD_COIN:
        return count;

    case ITEM_PLATINUM_COIN:
        return count * 100;

    case ITEM_CRYSTAL_COIN:
        return count * 10000;

    case ITEM_SCARAB_COIN:
        return count * 1000000;

    case ITEM_GOLD_NUGGET:
        return count * 100000000;

    default:
        return 0;
    }
}

const.h
C++:
    ITEM_SCARAB_COIN = 2159,
    ITEM_GOLD_NUGGET = 2157,

luascript.cpp
C++:
    registerEnum(ITEM_SCARAB_COIN)
    registerEnum(ITEM_GOLD_NUGGET)
 
keep knowing that i have changed gold_nugget id to 9971 ( gold ingot id ) :
dnj72q.png

@Vulcan_ after using your script the same bug

Its working but when you have only 1 gold nugget when you have more than 4-50 nugget it doesn't give you exactly the scarab coins i mean not 99 and 99 cc
 
Last edited by a moderator:
keep knowing that i have changed gold_nugget id to 9971 ( gold ingot id ) :
dnj72q.png

@Vulcan_ after using your script the same bug

Its working but when you have only 1 gold nugget when you have more than 4-50 nugget it doesn't give you exactly the scarab coins i mean not 99 and 99 cc
uint32_t holds up to a value of 4,294,967,295
42 gold nuggets = 4,200,000,000
after 43 the number loops back around to 0 and starts counting from there again
basically you need to set the stuff that deals with item::getWorth() and uses money to uint64_t so it holds that big of a value
in game.cpp replace Game::removeMoney with this
C++:
bool Game::removeMoney(Cylinder* cylinder, uint64_t money, uint32_t flags /*= 0*/)
{
    if (cylinder == nullptr) {
        return false;
    }

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

    std::vector<Container*> containers;

    std::multimap<uint64_t, Item*> moneyMap;
    uint64_t moneyCount = 0;

    for (size_t i = cylinder->getFirstIndex(), j = cylinder->getLastIndex(); i < j; ++i) {
        Thing* thing = cylinder->getThing(i);
        if (!thing) {
            continue;
        }

        Item* item = thing->getItem();
        if (!item) {
            continue;
        }

        Container* container = item->getContainer();
        if (container) {
            containers.push_back(container);
        } else {
            const uint64_t worth = item->getWorth();
            if (worth != 0) {
                moneyCount += worth;
                moneyMap.emplace(worth, item);
            }
        }
    }

    size_t i = 0;
    while (i < containers.size()) {
        Container* container = containers[i++];
        for (Item* item : container->getItemList()) {
            Container* tmpContainer = item->getContainer();
            if (tmpContainer) {
                containers.push_back(tmpContainer);
            } else {
                const uint64_t worth = item->getWorth();
                if (worth != 0) {
                    moneyCount += worth;
                    moneyMap.emplace(worth, item);
                }
            }
        }
    }

    if (moneyCount < money) {
        return false;
    }

    for (const auto& moneyEntry : moneyMap) {
        Item* item = moneyEntry.second;
        if (moneyEntry.first < money) {
            internalRemoveItem(item);
            money -= moneyEntry.first;
        } else if (moneyEntry.first > money) {
            const uint64_t worth = moneyEntry.first / item->getItemCount();
            const uint32_t removeCount = std::ceil(money / static_cast<double>(worth));

            addMoney(cylinder, (worth * removeCount) - money, flags);
            internalRemoveItem(item, removeCount);
            break;
        } else {
            internalRemoveItem(item);
            break;
        }
    }
    return true;
}

inside of item.cpp in Item::getWorth() replace case ITEM_GOLD_NUGGET: with this
C++:
    case ITEM_GOLD_NUGGET:
        return count * 100000000ULL;

if you ever add more money items, inside of Item::getWorth(), the number you multiply with (return count * <this number>) needs to have ULL at the end of it (see 100000000ULL above)
 
Solution
the answer of Vulcan_ is correct!
but missing this:
Code:
uint32_t Item::getWorth() const
change to
Code:
uint64_t Item::getWorth() const

result:
Code:
uint64_t Item::getWorth() const
{
    switch (id) {
    case ITEM_GOLD_COIN:
        return count;

    case ITEM_PLATINUM_COIN:
        return count * 100;

    case ITEM_CRYSTAL_COIN:
        return count * 10000;

    case ITEM_SCARAB_COIN:
        return count * 1000000ULL;

    case ITEM_GOLD_NUGGET:
        return count * 100000000ULL;

    default:
        return 0;
    }
}

also search in item.h
Code:
uint32_t getWorth() const;
and change for
Code:
uint64_t getWorth() const;
 
Last edited:
the answer of Vulcan_ is correct!
but missing this:
Code:
uint32_t Item::getWorth() const
change to
Code:
uint64_t Item::getWorth() const

result:
Code:
uint64_t Item::getWorth() const
{
    switch (id) {
    case ITEM_GOLD_COIN:
        return count;

    case ITEM_PLATINUM_COIN:
        return count * 100;

    case ITEM_CRYSTAL_COIN:
        return count * 10000;

    case ITEM_SCARAB_COIN:
        return count * 1000000;

    case ITEM_GOLD_NUGGET:
        return count * 100000000;

    default:
        return 0;
    }
}

also search in item.h
Code:
uint32_t getWorth() const;
and change for
Code:
uint64_t getWorth() const;
nice catch, forgot to recheck what i changed in items.cpp
but that case ITEM_GOLD_NUGGET needs to be return count * 100000000ULL
 
Back
Top