// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdpch.h"
#include "seeds.h"
// shortcut to types defined in CSeeds
typedef CSeeds::TUInt TUInt;
typedef CSeeds::TBigUInt TBigUInt;
/** Add a value and return the overflow
*/
static inline void addAndCheckOverFlow(TUInt &dest, TUInt src, TUInt &overflow)
{
TBigUInt newValue = (TBigUInt) src + (TBigUInt) dest;
if (newValue > (TBigUInt) CSeeds::MaxUIntValue) // has an overflow occured ?
{
dest= (TUInt) (newValue - (TBigUInt) CSeeds::MaxUIntValue);
overflow = (TUInt) CSeeds::MaxUIntValue;
}
else
{
overflow = 0;
dest = (TUInt) newValue;
}
}
//=========================================================
void CSeeds::add(const CSeeds &other, CSeeds &overflow)
{
// add each component and check overflow
addAndCheckOverFlow(_LS, other._LS, overflow._LS);
addAndCheckOverFlow(_MS, other._MS, overflow._MS);
addAndCheckOverFlow(_BS, other._BS, overflow._BS);
addAndCheckOverFlow(_VBS, other._VBS, overflow._VBS);
}
//=========================================================
void CSeeds::tradeSubtract(TBigUInt toSubTotal)
{
nlassert(toSubTotal <= this->getTotal()); // quantity to subtract is too high!
// We always begin to subtract the lowest seeds
// Little seeds
TBigUInt toSub = std::min((TBigUInt) _LS, toSubTotal);
toSubTotal -= toSub;
_LS -= (TUInt) toSub;
if (toSubTotal == 0) return;
// Medium seeds
toSub = std::min((TBigUInt) _MS, toSubTotal / 10);
toSubTotal -= 10 * toSub;
_MS -= (TUInt) toSub;
if (toSubTotal == 0) return;
// Big seeds
toSub = std::min((TBigUInt) _BS, toSubTotal / 100);
toSubTotal -= 100 * toSub;
_BS -= (TUInt) toSub;
if (toSubTotal == 0) return;
// Very big seeds
toSub = std::min((TBigUInt) _VBS, toSubTotal / 1000);
toSubTotal -= 1000 * toSub;
_VBS -= (TUInt) toSub;
if (toSubTotal == 0) return;
// Give the money back
nlassert(_LS == 0);
if (10 * (TBigUInt) _MS > toSubTotal) // enough medium seeds left ?
{
_MS -= (TUInt) ((toSubTotal / 10) + 1);
_LS = (TUInt) (10 - (toSubTotal % 10)); // give back little seeds
return;
}
toSubTotal -= 10 * _MS;
_MS = 0;
if (100 * (TBigUInt) _BS > toSubTotal) // enough big seeds left ?
{
_BS -= (TUInt) ((toSubTotal / 100) + 1);
CSeeds overflow;
CSeeds left;
left.setTotal(100 - (toSubTotal % 100)); // give back medium & little seeds
add(left, overflow);
nlassert(overflow.getTotal() == 0);
return;
}
toSubTotal -= 100 * _BS;
_BS = 0;
// there should be enough VBS left
nlassert(1000 * (TBigUInt) _VBS > toSubTotal);
_VBS -= (TUInt) ((toSubTotal / 1000) + 1);
CSeeds overflow;
CSeeds left;
left.setTotal(1000 - (toSubTotal % 100)); // give back medium, little & big seeds
add(left, overflow);
nlassert(overflow.getTotal() == 0);
}
//=========================================================
void CSeeds::tradeSubtract(const CSeeds &other)
{
tradeSubtract(other.getTotal());
}
//=========================================================
bool CSeeds::canTradeSubtract(const CSeeds &other) const
{
return other.getTotal() <= getTotal();
}
//=========================================================
bool CSeeds::canTradeSubtract(TBigUInt rhs) const
{
return rhs <= getTotal();
}
//=========================================================
void CSeeds::subtract(const CSeeds &other)
{
nlassert(canSubtract(other));
_LS -= other._LS;
_MS -= other._MS;
_BS -= other._BS;
_VBS -= other._VBS;
}
//=========================================================
bool CSeeds::canSubtract(const CSeeds &other) const
{
return _LS >= other._LS &&
_MS >= other._MS &&
_BS >= other._BS &&
_VBS >= other._VBS;
}
//=========================================================
void CSeeds::setTotal(TBigUInt total)
{
nlassert(total < (TBigUInt) MaxUIntValue * 1111);
_LS = (TUInt) (total % 10);
_MS = (TUInt) ((total / 10) % 10);
_BS = (TUInt) ((total / 100) % 10);
_VBS = (TUInt) (total / 1000);
}
//=========================================================
void CSeeds::optimize()
{
setTotal(getTotal());
}