[Fix] Remove Item Level Down

12/19/2018 23:23 ZeroTwo02#1
Files "DPSrvr.cpp" on the function "CDPSrvr::OnRemoveItemLevelDown"

After ->

Code:
		if( !IsUsableItem( pItemElem ) )
			return;
Add ->

Code:
		if( pUser->m_Inventory.IsEquip( pItemElem->m_dwObjId ) )
		{
			pUser->AddDiagText( prj.GetText( TID_GAME_EQUIPPUT ) );
			return;
		}
(Update 02/01/2019)

Files "WndTitle.cpp" function "void CWndSelectChar::Connected()"

Change ->

Code:
if( m_nSelectCharacter < 0 || m_nSelectCharacter >= 5 )
To ->

Code:
if( m_nSelectCharacter < 0 || m_nSelectCharacter >= MAX_CHARACTER_LIST )
(Update 02/01/2019)

Files "piercing.cpp" function "CPiercing::SetPiercingSize"

Change ->

Code:
void CPiercing::SetPiercingSize( int nSize )
{
	if( nSize > MAX_PIERCING_WEAPON )
		nSize = MAX_PIERCING_WEAPON;

	m_vPiercing.resize( nSize, 0 );
}
To ->

Code:
void CPiercing::SetPiercingSize( int nSize )
{
	if( nSize < 0 )
		nSize = 0;

	if( nSize > MAX_PIERCING_WEAPON )
		nSize = MAX_PIERCING_WEAPON;

	if (nSize == 0)
	{
		m_vPiercing.clear();
		return;
	}

	m_vPiercing.resize( nSize, 0 );
}
01/02/2019 02:01 ZeroTwo02#2
Fix damage from "Poison & Bleed" attack.

Go in the files "Mover.h"

Change ->

Code:
	short			m_wPoisonDamage;
	short			m_wBleedingDamage;
To ->

Code:
	int		m_wPoisonDamage;
	int			m_wBleedingDamage;
And change ->

Code:
	BOOL			SetPoison( BOOL bApply, OBJID idAttacker = NULL_ID, DWORD tmMaxTime = 0, DWORD tmUnit = 0, short wDamage = 0 );
	BOOL			SetBleeding( BOOL bApply, OBJID idAttacker = NULL_ID, DWORD tmMaxTime = 0, DWORD tmUnit = 0, short wDamage = 0 );
To ->

Code:
	BOOL			SetPoison( BOOL bApply, OBJID idAttacker = NULL_ID, DWORD tmMaxTime = 0, DWORD tmUnit = 0, int wDamage = 0 );
	BOOL			SetBleeding( BOOL bApply, OBJID idAttacker = NULL_ID, DWORD tmMaxTime = 0, DWORD tmUnit = 0, int wDamage = 0 );
Go in the files "MoverParam.cpp"

Change ->

Code:
BOOL CMover::SetPoison( BOOL bApply, OBJID idAttacker, DWORD tmMaxTime, DWORD tmUnit, short wDamage )
Code:
BOOL	CMover::SetBleeding( BOOL bApply, OBJID idAttacker, DWORD tmMaxTime, DWORD tmUnit, short wDamage )
To ->

Code:
BOOL CMover::SetPoison( BOOL bApply, OBJID idAttacker, DWORD tmMaxTime, DWORD tmUnit, int wDamage )
Code:
BOOL	CMover::SetBleeding( BOOL bApply, OBJID idAttacker, DWORD tmMaxTime, DWORD tmUnit, int wDamage )
--------------------------------------------------------------------------------------------

Penyas "Bug" Guild House

Go in the files "GuildHouse.cpp"

After ->
Code:
				int nPayPenya = gfi.dwItemId * GetUpkeepPenya();
Add ->

Code:
				if( nPayPenya < 0 || nPayPenya > INT_MAX )
				{
					pUser->AddDefinedText( TID_GAME_GUILDHOUSE_BUY_EXPENSE );
					return FALSE;
				}
03/05/2019 23:34 cookie69#3
your "fix" for "Duplication by Guild House "Overflow Maintenance Day"" is useless because if gfi.dwItemId < 0 then nTotalDays would be < 0.
Look below you will understand:
08/22/2022 09:46 jarzseald#4
hi, on your
Quote:
Files "DPSrvr.cpp" on the function "CDPSrvr::OnRemoveItemLevelDown"
does that remove item drop restriction upon reaching certain level?
08/22/2022 12:01 M¿dScientist#5
Quote:
Originally Posted by jarzseald View Post
does that remove item drop restriction upon reaching certain level?
No. It just makes it so players are unable to remove the "Level Down" scroll on an equipped item. What you are looking for is going to be in CMover::DropItem.


Since this thread was already necro'd, I might as well say somethings.

The fix for "CDPSrvr::OnRemoveItemLevelDown" could be changed. You could check for player level being in range still and if not then un-equip the item if there is space, then remove the scroll. When it is equipped and the level is within range, you can still update the variable as it wouldn't cause another exploit.

You can also do other things like for the "Blessing" stat stack, you're able to just reset the equipped items stats on the player and then there is no need to unequip said cs item.


CPiercing::SetPiercingSize is another fix where you don't need to check if < 0 if you just change the function to accept an unsigned integer rather than a signed integer because the type casting and overflow would already happen and thus be greater than the maximum pierced size. Also, vector resize will trim. There is no requirement for the == 0 check.


Haven't looked into the guild house code enough to state whether it is useless or not; however, if it's best to check the whole system before throwing fixes around.

nTotalDays is working with time_t variables, rather int, using time_t (because you can get rid of 32bit time_t and will have to in like 10 years).


But, here is multiply overflow checking that's templated. Could be optimized, and shouldn't be used with floats (you could constexpr check to see if it is floating point to cast to double rather than ulonglong to avoid float > int > float math and possibility of truncation and then the requires will need to be updated to be a boolean statement of integral value or floating point value).
Code:
enum FlowFlag : unsigned char
{
	ff_under = 1 << 0,
	ff_over = 1 << 1,
	ff_downcast = 1 << 2,
	ff_NegUpcast = 1 << 3
};

template <typename Ret = unsigned long, typename A = Ret, typename B = Ret>
bool checkMul(A a, B b, const FlowFlag ft = static_cast<FlowFlag>(ff_over | ff_downcast | ff_NegUpcast)) requires std::is_integral_v<Ret>
{
	static_assert((std::is_integral_v<A> || std::is_floating_point_v<A>) && (std::is_integral_v<B> || std::is_floating_point_v<B>) && std::is_integral_v<Ret>, "incorrect types");
	if constexpr (!std::numeric_limits<Ret>::is_signed)
	{
		if (ft & ff_NegUpcast)
			if (a < std::numeric_limits<Ret>::min() || b < std::numeric_limits<Ret>::min())
				return false;

		if (ft & ff_downcast)
			if (static_cast<unsigned long long>(static_cast<Ret>(a)) != static_cast<unsigned long long>(a) || static_cast<unsigned long long>(static_cast<Ret>(b)) != static_cast<unsigned long long>(b))
				return true;

		if (a == 0 || b == 0)
			return false;

		return static_cast<Ret>(a) < std::numeric_limits<Ret>::max() / static_cast<Ret>(b);
	}
	if (ft & ff_NegUpcast)
		if (a > std::numeric_limits<Ret>::max() || b > std::numeric_limits<Ret>::max())
			return true;

	if (ft & ff_downcast)
		if (static_cast<long long>(static_cast<Ret>(a)) != static_cast<long long>(a) || static_cast<long long>(static_cast<Ret>(b)) != static_cast<long long>(b))
			return true;

	if (a == 0 || b == 0)
		return false;

	return static_cast<Ret>(a) < std::numeric_limits<Ret>::max() / static_cast<Ret>(b);
}

template <typename Ret = unsigned long, typename A, typename B>
std::optional<Ret> eMul(A a, B b, const FlowFlag ft = static_cast<FlowFlag>(ff_over | ff_downcast | ff_NegUpcast)) requires std::numeric_limits<Ret>::is_integer
{
	return checkMul<Ret>(a, b, ft) ? std::optional<Ret>(static_cast<Ret>(a) * static_cast<Ret>(b)) : std::nullopt;
}
Code:
	if (const auto opt = eMul<long>(INT_MAX, 2); !opt.has_value())
	{
// overflow
	}