Attack resulted from weapon

01/18/2019 21:56 eunasciem#1
Hello dear friends,

I am trying to figure out how FlyFF calculates the ATTACK (seen in H hotkey, character window) based on the weapon equipped. I have found the thread below that helped me a lot and has given me good results, nailing down the attack for any weapon, as long as it's not upgraded above +2 and is not Ultimate or Baruna.

All calculations for regular weapons (not Ultimate) works if I always consider their attack range (xxx~yyy) as clean, not upgraded (thus +0) state. Even though upgrading increases the attack range of a weapon, not considering the increase seems to be the right way to calculate. However, past +2, I need to sum what I called a "correction factor" in my calculations in order to achieve the correct attack value. This factor starts at 2 (at +3) and goes up to 21 (at +10).

The thread I found mentions that the refinement of a weapon must be summed up. However, it mentions the refinement as "FLOOR (refinement on weapon)". If I should add the value of the current refinement (+1, +2, +3 and so on), why should it have a FLOOR function? Plus, even though I add the "raw" refinement of the weapon, the correction factor is still needed. What am I not getting right?

Also, I'm trying to figure out what happens when I equip an Ultimate weapon (for now, not touching Baruna). When I upgrade a weapon from +10 to Ultimate, I can't seem to fit my calculations to the ATTACK resulted in game. Even considering the attack range of the clean weapon, +10 weapon or clean Ultimate weapon, none of them results in the correct value. The multiplier (mentioned in the thread below) does not seem to be the answer 'cause I would need different values for different weapon types, as my tests concluded. Therefore, I have no idea what changes in the attack calculation when a weapon is Ultimate.

I can't hover through the FlyFF source right now 'cause I'm not in my house for some weeks... and even after I get there, I'll probably have little to no time to find it, as I'm not good with source stuff.

Can someone give me a hand here figuring out what happens with weapon upgrade and ultimate related to the attack seen in character window (H hotkey)?

NOTE: I was careful to not use Attack% items that could mask my results in my tests.

[Only registered and activated users can see links. Click Here To Register...]

Thank you in advance!
01/18/2019 23:06 Avalion#2
There's a random flyff source on a public github somewhere. Just look at that. Other than that, CWndCharacterDetail or something like that and just follow the function calls under the RenderAtk or OnDraw function. :thinking:
01/22/2019 14:03 eunasciem#3
Quote:
Originally Posted by Avalion View Post
There's a random flyff source on a public github somewhere. Just look at that. Other than that, CWndCharacterDetail or something like that and just follow the function calls under the RenderAtk or OnDraw function. :thinking:
Thanks for the tip. I've found the FlyFF source on github, but couldn't track down the calculations.

What I have found is just the attack from the character main stat and, weapon type and character level, which I already had... but couldn't find how attack scales with the weapon upgrade + ultimate.
01/26/2019 17:35 Herzlos95#4
Code:
void CWndCharacterDetail::RenderATK( C2DRender* p2DRender, int x, int y )
{
	DWORD dwColor = D3DCOLOR_ARGB(255,0,0,0);
	char szText[32];
	int nMin, nMax;
	g_pPlayer->GetHitMinMax( &nMin, &nMax );
	int nATK = ( nMin + nMax ) / 2;

	if( g_pPlayer->IsSMMode( SM_ATTACK_UP1 ) || g_pPlayer->IsSMMode( SM_ATTACK_UP ) )
		nATK	= (int)( nATK * 1.2f );
	
	if( 0 < g_pPlayer->GetParam( DST_ATKPOWER_RATE, 0 ) )
		nATK = nATK + ( nATK * g_pPlayer->GetParam( DST_ATKPOWER_RATE, 0 ) / 100 );

	nATK += g_pPlayer->GetWeaponPlusDamage( 1, FALSE );

//#ifdef __PET_0410
	nATK	+= g_pPlayer->GetParam( DST_ATKPOWER, 0 );
//#endif	// __PET_0410

#ifdef __JEFF_11
	if( nATK < 0 )
		nATK	= 0;
#endif	// __JEFF_11

	wsprintf( szText, "%d", nATK );

	p2DRender->TextOut( x, y, szText, dwColor ); 
}
In the WndField.cpp
Code:
void CMover::GetHitMinMax( int* pnMin, int* pnMax, ATTACK_INFO *pInfo )
{
	int nParts = PARTS_RWEAPON;
	if( pInfo )
		nParts  = pInfo->nParts;

	*pnMin = 0;
	*pnMax = 0;

	if( IsInvalidObj(this) )	
		return;

	if( IsPlayer() )
	{
		ItemProp* pItemProp = GetActiveHandItemProp( nParts );
		if( pItemProp == NULL )
			return;

		*pnMin = pItemProp->dwAbilityMin * 2;
		*pnMax = pItemProp->dwAbilityMax * 2;

		*pnMin = GetParam( DST_ABILITY_MIN, *pnMin );
		*pnMax = GetParam( DST_ABILITY_MAX, *pnMax );

		int nPlus = GetWeaponATK( pItemProp->dwWeaponType ) + GetParam( DST_CHR_DMG, 0 );
		*pnMin += nPlus;
		*pnMax += nPlus;

		CItemElem *pWeapon = GetWeaponItem( nParts );
		if( pWeapon && pWeapon->GetProp() )
		{
			float f = GetItemMultiplier( pWeapon );
			*pnMin = (int)( *pnMin * f );
			*pnMax = (int)( *pnMax * f );
		}

		if( pWeapon )
		{
			int nOption = pWeapon->GetAbilityOption();
			if( nOption > 0 )
			{
				int nValue = (int)( pow( (float)( nOption ), 1.5f ) );

				*pnMin += nValue;
				*pnMax += nValue;
			}
		}
	} 
	else
	{
		MoverProp* pMoverProp = GetProp();
		*pnMin = pMoverProp->dwAtkMin;
		*pnMax = pMoverProp->dwAtkMax;

		*pnMin = GetParam( DST_ABILITY_MIN, *pnMin );
		*pnMax = GetParam( DST_ABILITY_MAX, *pnMax );
		
		*pnMin = GetParam( DST_CHR_DMG, *pnMin );
		*pnMax = GetParam( DST_CHR_DMG, *pnMax );		
		
		DWORD dwAtk = pMoverProp->dwAtk1;
		if( pInfo )
		{
			DWORD dwValue = pInfo->nParam >> 16;
			if( dwValue != 0 && dwValue != NULL_ID )
				dwAtk = dwValue;
		}
	
		if( dwAtk != NULL_ID )		// 들고있는 무기가 있을땐 그 무기의 min,max 값까지 더한다.
		{
			ItemProp* pItemProp = prj.GetItemProp( dwAtk );
			if( pItemProp )
			{
				*pnMin += pItemProp->dwAbilityMin;
				*pnMax += pItemProp->dwAbilityMax;
			}
		}
	}
}
In the MoverAttack.cpp
Code:
// 들고있는 무기의 옵션에 의한 추가 데미지를 구한다. ( bRandom = TRUE )
int CMover::GetWeaponPlusDamage( int nDamage, BOOL bRandom )
{
	int nPlus = 0;
	CItemElem* pWeapon = GetWeaponItem();
	if( pWeapon )
	{
		int nOption = pWeapon->GetAbilityOption();	
		if( nOption > 10 )
			return nPlus;
		
		ItemProp* pItemProp = GetActiveHandItemProp();
		return ::GetWeaponPlusDamage( nDamage, bRandom, pItemProp, nOption ); 
	}
	return nPlus;
}
In the MoverAttack.cpp

Since it would be way to much code to post here, I'll stop now. Simply find the CWndCharacterDetail::RenderATK in the WndField.cpp and start following the code and go deeper.

But if you want a short answer: Trying to understand the ATK shown in your H window is useless. The ATK shown there has almost nothing todo with your real dmg output. There are way to many factors not taken into account in that atk value.