C++ Money currency little bug

Shadow_

asgard-ot.com
Premium User
Joined
Jun 2, 2018
Messages
298
Reaction score
56
Location
Cairo, Egypt
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);
        }
    }
}
 

Stigma

Veteran OT User
Joined
Feb 14, 2015
Messages
4,395
Reaction score
1,974
works fine for me

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)
 
OP
Shadow_

Shadow_

asgard-ot.com
Premium User
Joined
Jun 2, 2018
Messages
298
Reaction score
56
Location
Cairo, Egypt
keep knowing that i have changed gold_nugget id to 9971 ( gold ingot id ) :

@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:

Stigma

Veteran OT User
Joined
Feb 14, 2015
Messages
4,395
Reaction score
1,974
keep knowing that i have changed gold_nugget id to 9971 ( gold ingot id ) :

@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)
 

Sarah Wesker

ค∂vαηcε รүηтαx ❤
Joined
Mar 16, 2017
Messages
332
Reaction score
157
Location
London
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:

Stigma

Veteran OT User
Joined
Feb 14, 2015
Messages
4,395
Reaction score
1,974
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
 
Top